-only trigger check config if we actually need it
[oweals/gnunet.git] / src / statistics / gnunet-statistics.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, 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
33 /**
34  * Final status code.
35  */
36 static int ret;
37
38 /**
39  * Set to subsystem that we're going to get stats for (or NULL for all).
40  */
41 static char *subsystem;
42
43 /**
44  * Set to the specific stat value that we are after (or NULL for all).
45  */
46 static char *name;
47
48 /**
49  * Make the value that is being set persistent.
50  */
51 static int persistent;
52
53 /**
54  * Watch value continuously
55  */
56 static int watch;
57
58 /**
59  * Quiet mode
60  */
61 static int quiet;
62
63 /**
64  * Remote host
65  */
66 static char *remote_host;
67
68 /**
69  * Remote host's port
70  */
71 static unsigned long long remote_port;
72
73 /**
74  * Value to set
75  */
76 static unsigned long long set_val;
77
78 /**
79  * Set operation
80  */
81 static int set_value;
82
83 /**
84  * Handle for pending GET operation.
85  */
86 static struct GNUNET_STATISTICS_GetHandle *gh;
87
88
89 /**
90  * Callback function to process statistic values.
91  *
92  * @param cls closure
93  * @param subsystem name of subsystem that created the statistic
94  * @param name the name of the datum
95  * @param value the current value
96  * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
97  * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
98  */
99 static int
100 printer (void *cls,
101          const char *subsystem,
102          const char *name,
103          uint64_t value,
104          int is_persistent)
105 {
106   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get();
107   const char * now_str;
108
109   if (quiet == GNUNET_NO)
110   {
111     if (GNUNET_YES == watch)
112     {
113       now_str = GNUNET_STRINGS_absolute_time_to_string(now);
114       FPRINTF (stdout, "%24s %s%12s %50s: %16llu \n",
115                now_str,
116                is_persistent ? "!" : " ",
117                subsystem, _(name), (unsigned long long) value);
118     }
119     else
120     {
121       FPRINTF (stdout, "%s%12s %50s: %16llu \n",
122                is_persistent ? "!" : " ",
123                subsystem, _(name), (unsigned long long) value);
124     }
125   }
126   else
127     FPRINTF (stdout, "%llu\n", (unsigned long long) value);
128
129   return GNUNET_OK;
130 }
131
132
133 /**
134  * Function called last by the statistics code.
135  *
136  * @param cls closure
137  * @param success #GNUNET_OK if statistics were
138  *        successfully obtained, #GNUNET_SYSERR if not.
139  */
140 static void
141 cleanup (void *cls,
142          int success)
143 {
144   gh = NULL;
145   if (GNUNET_OK != success)
146   {
147     if (NULL == remote_host)
148       FPRINTF (stderr,
149                "%s",
150                _("Failed to obtain statistics.\n"));
151     else
152       FPRINTF (stderr,
153                _("Failed to obtain statistics from host `%s:%llu'\n"),
154                remote_host,
155                remote_port);
156     ret = 1;
157   }
158   GNUNET_SCHEDULER_shutdown ();
159 }
160
161
162 /**
163  * Function run on shutdown to clean up.
164  *
165  * @param cls the statistics handle
166  */
167 static void
168 shutdown_task (void *cls)
169 {
170   struct GNUNET_STATISTICS_Handle *h = cls;
171
172   if (NULL == h)
173     return;
174   if (NULL != gh)
175   {
176     GNUNET_STATISTICS_get_cancel (gh);
177     gh = NULL;
178   }
179   if ( (GNUNET_YES == watch) &&
180        (NULL != subsystem) &&
181        (NULL != name) )
182     GNUNET_assert (GNUNET_OK ==
183                    GNUNET_STATISTICS_watch_cancel (h,
184                                                    subsystem,
185                                                    name,
186                                                    &printer, h));
187   GNUNET_STATISTICS_destroy (h,
188                              GNUNET_NO);
189   h = NULL;
190 }
191
192
193 /**
194  * Main task that does the actual work.
195  *
196  * @param cls closure with our configuration
197  */
198 static void
199 main_task (void *cls)
200 {
201   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
202   struct GNUNET_STATISTICS_Handle *h;
203
204   if (set_value)
205   {
206     if (NULL == subsystem)
207     {
208       FPRINTF (stderr, "%s", _("Missing argument: subsystem \n"));
209       ret = 1;
210       return;
211     }
212     if (NULL == name)
213     {
214       FPRINTF (stderr, "%s", _("Missing argument: name\n"));
215       ret = 1;
216       return;
217     }
218     h = GNUNET_STATISTICS_create (subsystem, cfg);
219     if (NULL == h)
220     {
221       ret = 1;
222       return;
223     }
224     GNUNET_STATISTICS_set (h,
225                            name,
226                            (uint64_t) set_val,
227                            persistent);
228     GNUNET_STATISTICS_destroy (h,
229                                GNUNET_YES);
230     h = NULL;
231     return;
232   }
233   if (NULL == (h = GNUNET_STATISTICS_create ("gnunet-statistics",
234                                              cfg)))
235   {
236     ret = 1;
237     return;
238   }
239   if (GNUNET_NO == watch)
240   {
241     if (NULL ==
242         (gh = GNUNET_STATISTICS_get (h,
243                                      subsystem,
244                                      name,
245                                      &cleanup,
246                                      &printer, h)) )
247       cleanup (h, GNUNET_SYSERR);
248   }
249   else
250   {
251     if ((NULL == subsystem) || (NULL == name))
252     {
253       printf (_("No subsystem or name given\n"));
254       GNUNET_STATISTICS_destroy (h, GNUNET_NO);
255       h = NULL;
256       ret = 1;
257       return;
258     }
259     if (GNUNET_OK !=
260         GNUNET_STATISTICS_watch (h,
261                                  subsystem,
262                                  name,
263                                  &printer, h))
264     {
265       fprintf (stderr,
266                _("Failed to initialize watch routine\n"));
267       GNUNET_SCHEDULER_add_now (&shutdown_task,
268                                 h);
269       return;
270     }
271   }
272   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
273                                  h);
274 }
275
276
277 /**
278  * Function called with th test result to see if the resolver is
279  * running.
280  *
281  * @param cls closure with our configuration
282  * @param result #GNUNET_YES if the resolver is running
283  */
284 static void
285 resolver_test_task (void *cls,
286                     int result)
287 {
288   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
289
290   if (GNUNET_YES != result)
291    {
292      FPRINTF (stderr,
293               _("Trying to connect to remote host, but service `%s' is not running\n"),
294               "resolver");
295      return;
296    }
297   /* connect to a remote host */
298   if (0 == remote_port)
299   {
300     if (GNUNET_SYSERR ==
301         GNUNET_CONFIGURATION_get_value_number (cfg, "statistics",
302                                                "PORT",
303                                                &remote_port))
304     {
305       FPRINTF (stderr,
306                _("A port is required to connect to host `%s'\n"),
307                remote_host);
308       return;
309     }
310   }
311   else if (65535 <= remote_port)
312   {
313     FPRINTF (stderr,
314              _("A port has to be between 1 and 65535 to connect to host `%s'\n"),
315              remote_host);
316     return;
317   }
318
319   /* Manipulate configuration */
320   GNUNET_CONFIGURATION_set_value_string (cfg,
321                                          "statistics",
322                                          "UNIXPATH",
323                                          "");
324   GNUNET_CONFIGURATION_set_value_string (cfg,
325                                          "statistics",
326                                          "HOSTNAME",
327                                          remote_host);
328   GNUNET_CONFIGURATION_set_value_number (cfg,
329                                          "statistics",
330                                          "PORT",
331                                          remote_port);
332   GNUNET_SCHEDULER_add_now (&main_task, cfg);
333 }
334
335
336 /**
337  * Main function that will be run by the scheduler.
338  *
339  * @param cls closure
340  * @param args remaining command-line arguments
341  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
342  * @param cfg configuration
343  */
344 static void
345 run (void *cls,
346      char *const *args,
347      const char *cfgfile,
348      const struct GNUNET_CONFIGURATION_Handle *cfg)
349 {
350   set_value = GNUNET_NO;
351   if (NULL != args[0])
352   {
353     if (1 != SSCANF (args[0], "%llu", &set_val))
354     {
355       FPRINTF (stderr, _("Invalid argument `%s'\n"), args[0]);
356       ret = 1;
357       return;
358     }
359     set_value = GNUNET_YES;
360   }
361   if (NULL != remote_host)
362     GNUNET_CLIENT_service_test ("resolver",
363                                 cfg,
364                                 GNUNET_TIME_UNIT_SECONDS,
365                                 &resolver_test_task, (void *) cfg);
366   else
367     GNUNET_SCHEDULER_add_now (&main_task, (void *) cfg);
368 }
369
370
371 /**
372  * The main function to obtain statistics in GNUnet.
373  *
374  * @param argc number of arguments from the command line
375  * @param argv command line arguments
376  * @return 0 ok, 1 on error
377  */
378 int
379 main (int argc, char *const *argv)
380 {
381   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
382     {'n', "name", "NAME",
383      gettext_noop ("limit output to statistics for the given NAME"), 1,
384      &GNUNET_GETOPT_set_string, &name},
385     {'p', "persistent", NULL,
386      gettext_noop ("make the value being set persistent"), 0,
387      &GNUNET_GETOPT_set_one, &persistent},
388     {'s', "subsystem", "SUBSYSTEM",
389      gettext_noop ("limit output to the given SUBSYSTEM"), 1,
390      &GNUNET_GETOPT_set_string, &subsystem},
391     {'q', "quiet", NULL,
392      gettext_noop ("just print the statistics value"), 0,
393      &GNUNET_GETOPT_set_one, &quiet},
394     {'w', "watch", NULL,
395      gettext_noop ("watch value continuously"), 0,
396      &GNUNET_GETOPT_set_one, &watch},
397      {'r', "remote", NULL,
398       gettext_noop ("connect to remote host"), 1,
399       &GNUNET_GETOPT_set_string, &remote_host},
400     {'o', "port", NULL,
401      gettext_noop ("port for remote host"), 1,
402      &GNUNET_GETOPT_set_uint, &remote_port},
403     GNUNET_GETOPT_OPTION_END
404   };
405   remote_port = 0;
406   remote_host = NULL;
407   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv,
408                                                  &argc, &argv))
409     return 2;
410
411   ret = (GNUNET_OK ==
412          GNUNET_PROGRAM_run (argc, argv, "gnunet-statistics [options [value]]",
413                              gettext_noop
414                              ("Print statistics about GNUnet operations."),
415                              options, &run, NULL)) ? ret : 1;
416   GNUNET_free_non_null (remote_host);
417   GNUNET_free ((void*) argv);
418   return ret;
419 }
420
421 /* end of gnunet-statistics.c */