-fix URIs
[oweals/gnunet.git] / src / statistics / gnunet-statistics.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file statistics/gnunet-statistics.c
23  * @brief tool to obtain statistics
24  * @author Christian Grothoff
25  * @author Igor Wronsky
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_statistics_service.h"
30 #include "statistics.h"
31
32 #define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
33
34 /**
35  * Final status code.
36  */
37 static int ret;
38
39 /**
40  * Set to subsystem that we're going to get stats for (or NULL for all).
41  */
42 static char *subsystem;
43
44 /**
45  * Set to the specific stat value that we are after (or NULL for all).
46  */
47 static char *name;
48
49 /**
50  * Make the value that is being set persistent.
51  */
52 static int persistent;
53
54 /**
55  * Watch value continuously
56  */
57 static int watch;
58
59 /**
60  * Quiet mode
61  */
62 static int quiet;
63
64 /**
65  * Remote host
66  */
67 static char *remote_host;
68
69 /**
70  * Remote host's port
71  */
72 static unsigned long long  remote_port;
73
74 /**
75  * Value to set
76  */
77 static unsigned long long set_val;
78
79 /**
80  * Set operation
81  */
82 static int set_value;
83
84
85 /**
86  * Callback function to process statistic values.
87  *
88  * @param cls closure
89  * @param subsystem name of subsystem that created the statistic
90  * @param name the name of the datum
91  * @param value the current value
92  * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
93  * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
94  */
95 static int
96 printer (void *cls, const char *subsystem, const char *name, uint64_t value,
97          int is_persistent)
98 {
99   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get();
100   const char * now_str;
101
102   if (quiet == GNUNET_NO)
103   {
104     if (GNUNET_YES == watch)
105     {
106       now_str = GNUNET_STRINGS_absolute_time_to_string(now);
107       FPRINTF (stdout, "%24s %s%12s %50s: %16llu \n",
108                now_str,
109                is_persistent ? "!" : " ",
110                subsystem, _(name), (unsigned long long) value);
111     }
112     else
113     {
114       FPRINTF (stdout, "%s%12s %50s: %16llu \n",
115                is_persistent ? "!" : " ",
116                subsystem, _(name), (unsigned long long) value);
117     }
118   }
119   else
120     FPRINTF (stdout, "%llu\n", (unsigned long long) value);
121
122   return GNUNET_OK;
123 }
124
125
126 /**
127  * Function called last by the statistics code.
128  *
129  * @param cls closure
130  * @param success #GNUNET_OK if statistics were
131  *        successfully obtained, #GNUNET_SYSERR if not.
132  */
133 static void
134 cleanup (void *cls, int success)
135 {
136
137   if (success != GNUNET_OK)
138   {
139     if (NULL == remote_host)
140       FPRINTF (stderr, "%s", _("Failed to obtain statistics.\n"));
141     else
142       FPRINTF (stderr,  _("Failed to obtain statistics from host `%s:%llu'\n"),
143               remote_host, remote_port);
144     ret = 1;
145   }
146   GNUNET_SCHEDULER_shutdown ();
147 }
148
149
150 /**
151  * Function run on shutdown to clean up.
152  *
153  * @param cls the statistics handle
154  * @param tc scheduler context
155  */
156 static void
157 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
158 {
159   struct GNUNET_STATISTICS_Handle *h = cls;
160
161   if (NULL == h)
162     return;
163   if ( (GNUNET_YES == watch) &&
164        (NULL != subsystem) &&
165        (NULL != name) )
166     GNUNET_assert (GNUNET_OK ==
167                    GNUNET_STATISTICS_watch_cancel (h, subsystem, name, &printer, h));
168   GNUNET_STATISTICS_destroy (h, GNUNET_NO);
169   h = NULL;
170 }
171
172
173 /**
174  * Main task that does the actual work.
175  *
176  * @param cls closure with our configuration
177  * @param tc schedueler context
178  */
179 static void
180 main_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
181 {
182   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
183   struct GNUNET_STATISTICS_Handle *h;
184
185   if (set_value)
186   {
187     if (subsystem == NULL)
188     {
189       FPRINTF (stderr, "%s", _("Missing argument: subsystem \n"));
190       ret = 1;
191       return;
192     }
193     if (name == NULL)
194     {
195       FPRINTF (stderr, "%s", _("Missing argument: name\n"));
196       ret = 1;
197       return;
198     }
199     h = GNUNET_STATISTICS_create (subsystem, cfg);
200     if (NULL == h)
201     {
202       ret = 1;
203       return;
204     }
205     GNUNET_STATISTICS_set (h, name, (uint64_t) set_val, persistent);
206     GNUNET_STATISTICS_destroy (h, GNUNET_YES);
207     h = NULL;
208     return;
209   }
210   if (NULL == (h = GNUNET_STATISTICS_create ("gnunet-statistics", cfg)))
211   {
212     ret = 1;
213     return;
214   }
215   if (GNUNET_NO == watch)
216   {
217     if (NULL ==
218       GNUNET_STATISTICS_get (h, subsystem, name, GET_TIMEOUT, &cleanup,
219                              &printer, h))
220     cleanup (h, GNUNET_SYSERR);
221   }
222   else
223   {
224     if ((NULL == subsystem) || (NULL == name))
225     {
226       printf (_("No subsystem or name given\n"));
227       GNUNET_STATISTICS_destroy (h, GNUNET_NO);
228       h = NULL;
229       ret = 1;
230       return;
231     }
232     if (GNUNET_OK != GNUNET_STATISTICS_watch (h, subsystem, name, &printer, h))
233     {
234       fprintf (stderr, _("Failed to initialize watch routine\n"));
235       GNUNET_SCHEDULER_add_now (&shutdown_task, h);
236       return;
237     }
238   }
239   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
240                                 &shutdown_task, h);
241
242 }
243
244
245 /**
246  * Function called with th test result to see if the resolver is
247  * running.
248  *
249  * @param cls closure with our configuration
250  * @param result #GNUNET_YES if the resolver is running
251  */
252 static void
253 resolver_test_task (void *cls,
254                     int result)
255 {
256   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
257
258   if (GNUNET_YES != result)
259    {
260      FPRINTF (stderr,
261               _("Trying to connect to remote host, but service `%s' is not running\n"), "resolver");
262      return;
263    }
264   /* connect to a remote host */
265   if (0 == remote_port)
266   {
267     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "statistics", "PORT", &remote_port))
268     {
269       FPRINTF (stderr, _("A port is required to connect to host `%s'\n"), remote_host);
270       return;
271     }
272   }
273   else if (65535 <= remote_port)
274   {
275     FPRINTF (stderr,
276              _("A port has to be between 1 and 65535 to connect to host `%s'\n"), remote_host);
277     return;
278   }
279
280   /* Manipulate configuration */
281   GNUNET_CONFIGURATION_set_value_string (cfg,
282                                          "statistics", "UNIXPATH", "");
283   GNUNET_CONFIGURATION_set_value_string (cfg,
284                                          "statistics", "HOSTNAME", remote_host);
285   GNUNET_CONFIGURATION_set_value_number (cfg,
286                                          "statistics", "PORT", remote_port);
287   GNUNET_SCHEDULER_add_now (&main_task, cfg);
288 }
289
290
291 /**
292  * Main function that will be run by the scheduler.
293  *
294  * @param cls closure
295  * @param args remaining command-line arguments
296  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
297  * @param cfg configuration
298  */
299 static void
300 run (void *cls, char *const *args, const char *cfgfile,
301      const struct GNUNET_CONFIGURATION_Handle *cfg)
302 {
303   set_value = GNUNET_NO;
304   if (NULL != args[0])
305   {
306     if (1 != SSCANF (args[0], "%llu", &set_val))
307     {
308       FPRINTF (stderr, _("Invalid argument `%s'\n"), args[0]);
309       ret = 1;
310       return;
311     }
312     set_value = GNUNET_YES;
313   }
314   if (NULL != remote_host)
315     GNUNET_CLIENT_service_test ("resolver", cfg, GNUNET_TIME_UNIT_SECONDS,
316                                 &resolver_test_task, (void *) cfg);
317   else
318     GNUNET_SCHEDULER_add_now (&main_task, (void *) cfg);
319 }
320
321
322 /**
323  * The main function to obtain statistics in GNUnet.
324  *
325  * @param argc number of arguments from the command line
326  * @param argv command line arguments
327  * @return 0 ok, 1 on error
328  */
329 int
330 main (int argc, char *const *argv)
331 {
332   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
333     {'n', "name", "NAME",
334      gettext_noop ("limit output to statistics for the given NAME"), 1,
335      &GNUNET_GETOPT_set_string, &name},
336     {'p', "persistent", NULL,
337      gettext_noop ("make the value being set persistent"), 0,
338      &GNUNET_GETOPT_set_one, &persistent},
339     {'s', "subsystem", "SUBSYSTEM",
340      gettext_noop ("limit output to the given SUBSYSTEM"), 1,
341      &GNUNET_GETOPT_set_string, &subsystem},
342     {'q', "quiet", NULL,
343      gettext_noop ("just print the statistics value"), 0,
344      &GNUNET_GETOPT_set_one, &quiet},
345     {'w', "watch", NULL,
346      gettext_noop ("watch value continuously"), 0,
347      &GNUNET_GETOPT_set_one, &watch},
348      {'r', "remote", NULL,
349       gettext_noop ("connect to remote host"), 1,
350       &GNUNET_GETOPT_set_string, &remote_host},
351     {'o', "port", NULL,
352      gettext_noop ("port for remote host"), 1,
353      &GNUNET_GETOPT_set_uint, &remote_port},
354     GNUNET_GETOPT_OPTION_END
355   };
356   remote_port = 0;
357   remote_host = NULL;
358   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
359     return 2;
360
361   ret = (GNUNET_OK ==
362          GNUNET_PROGRAM_run (argc, argv, "gnunet-statistics [options [value]]",
363                              gettext_noop
364                              ("Print statistics about GNUnet operations."),
365                              options, &run, NULL)) ? ret : 1;
366   GNUNET_free_non_null (remote_host);
367   GNUNET_free ((void*) argv);
368   return ret;
369 }
370
371 /* end of gnunet-statistics.c */