glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / testbed / gnunet-testbed-profiler.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2008--2013 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14 */
15
16 /**
17  * @file testbed/gnunet-testbed-profiler.c
18  * @brief Profiling driver for the testbed.
19  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
20  */
21
22 #include "platform.h"
23 #include "gnunet_util_lib.h"
24 #include "gnunet_testbed_service.h"
25 #include "testbed_api_hosts.h"
26
27 /**
28  * Generic loggins shorthand
29  */
30 #define LOG(kind,...)                                           \
31   GNUNET_log (kind, __VA_ARGS__)
32
33
34 /**
35  * Handle to global configuration
36  */
37 struct GNUNET_CONFIGURATION_Handle *cfg;
38
39 /**
40  * Peer linking - topology operation
41  */
42 struct GNUNET_TESTBED_Operation *topology_op;
43
44 /**
45  * Name of the file with the hosts to run the test over (configuration option).
46  * It will be NULL if ENABLE_LL is set
47  */
48 static char *hosts_file;
49
50 /**
51  * Abort task identifier
52  */
53 static struct GNUNET_SCHEDULER_Task *abort_task;
54
55 /**
56  * Global event mask for all testbed events
57  */
58 uint64_t event_mask;
59
60 /**
61  * Number of peers to be started by the profiler
62  */
63 static unsigned int num_peers;
64
65 /**
66  * Number of timeout failures to tolerate
67  */
68 static unsigned int num_cont_fails;
69
70 /**
71  * Continuous failures during overlay connect operations
72  */
73 static unsigned int cont_fails;
74
75 /**
76  * Links which are successfully established
77  */
78 static unsigned int established_links;
79
80 /**
81  * Links which are not successfully established
82  */
83 static unsigned int failed_links;
84
85 /**
86  * Global testing status
87  */
88 static int result;
89
90 /**
91  * Are we running non interactively
92  */
93 static int noninteractive;
94
95
96 /**
97  * Shutdown nicely
98  *
99  * @param cls NULL
100  */
101 static void
102 do_shutdown (void *cls)
103 {
104   if (NULL != abort_task)
105   {
106     GNUNET_SCHEDULER_cancel (abort_task);
107     abort_task = NULL;
108   }
109   if (NULL != cfg)
110   {
111     GNUNET_CONFIGURATION_destroy (cfg);
112     cfg = NULL;
113   }
114 }
115
116
117 /**
118  * abort task to run on test timed out
119  *
120  * @param cls NULL
121  */
122 static void
123 do_abort (void *cls)
124 {
125   abort_task = NULL;
126   LOG (GNUNET_ERROR_TYPE_WARNING,
127        "Aborting\n");
128   result = GNUNET_SYSERR;
129   GNUNET_SCHEDULER_shutdown ();
130 }
131
132
133 /**
134  * Function to print summary about how many overlay links we have made and how
135  * many failed
136  */
137 static void
138 print_overlay_links_summary ()
139 {
140   static int printed_already;
141
142   if (GNUNET_YES == printed_already)
143     return;
144   printed_already = GNUNET_YES;
145   printf ("%u links succeeded\n", established_links);
146   printf ("%u links failed due to timeouts\n", failed_links);
147 }
148
149
150 /**
151  * Controller event callback
152  *
153  * @param cls NULL
154  * @param event the controller event
155  */
156 static void
157 controller_event_cb (void *cls,
158                      const struct GNUNET_TESTBED_EventInformation *event)
159 {
160   switch (event->type)
161   {
162   case GNUNET_TESTBED_ET_OPERATION_FINISHED:
163     /* Control reaches here when a peer linking operation fails */
164     if (NULL != event->details.operation_finished.emsg)
165     {
166       printf ("F");
167       fflush (stdout);
168       failed_links++;
169       if (++cont_fails > num_cont_fails)
170       {
171         printf ("\nAborting due to very high failure rate\n");
172         print_overlay_links_summary ();
173         GNUNET_SCHEDULER_shutdown ();
174         return;
175       }
176     }
177     break;
178   case GNUNET_TESTBED_ET_CONNECT:
179   {
180     if (0 != cont_fails)
181       cont_fails--;
182     if (0 == established_links)
183       printf ("Establishing links. Please wait\n");
184     printf (".");
185     fflush (stdout);
186     established_links++;
187   }
188     break;
189   default:
190     GNUNET_break (0);
191   }
192 }
193
194
195 /**
196  * Signature of a main function for a testcase.
197  *
198  * @param cls closure
199  * @param h the run handle
200  * @param num_peers number of peers in 'peers'
201  * @param peers handle to peers run in the testbed
202  * @param links_succeeded the number of overlay link connection attempts that
203  *          succeeded
204  * @param links_failed the number of overlay link
205  */
206 static void
207 test_run (void *cls,
208           struct GNUNET_TESTBED_RunHandle *h,
209           unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers,
210           unsigned int links_succeeded,
211           unsigned int links_failed)
212 {
213   result = GNUNET_OK;
214   fprintf (stdout, "\n");
215   print_overlay_links_summary ();
216   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
217   if (noninteractive)
218   {
219     GNUNET_SCHEDULER_cancel (abort_task);
220     abort_task = NULL;
221     return;
222   }
223 #if (!ENABLE_SUPERMUC)
224   fprintf (stdout, "Testbed running, waiting for keystroke to shut down\n");
225   fflush (stdout);
226   (void) getc (stdin);
227 #endif
228   fprintf (stdout, "Shutting down. Please wait\n");
229   fflush (stdout);
230   GNUNET_SCHEDULER_shutdown ();
231 }
232
233
234 /**
235  * Main function that will be run by the scheduler.
236  *
237  * @param cls closure
238  * @param args remaining command-line arguments
239  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
240  * @param config configuration
241  */
242 static void
243 run (void *cls, char *const *args, const char *cfgfile,
244      const struct GNUNET_CONFIGURATION_Handle *config)
245 {
246   if (0 == num_peers)
247   {
248     LOG (GNUNET_ERROR_TYPE_ERROR, _("Exiting as the number of peers is %u\n"),
249          num_peers);
250     return;
251   }
252   cfg = GNUNET_CONFIGURATION_dup (config);
253   event_mask = 0;
254   event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
255   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
256   GNUNET_TESTBED_run (hosts_file, cfg, num_peers, event_mask,
257                       &controller_event_cb, NULL,
258                       &test_run, NULL);
259   abort_task =
260       GNUNET_SCHEDULER_add_shutdown (&do_abort,
261                                      NULL);
262 }
263
264
265 /**
266  * Main function.
267  *
268  * @return 0 on success
269  */
270 int
271 main (int argc, char *const *argv)
272 {
273   struct GNUNET_GETOPT_CommandLineOption options[] = {
274
275     GNUNET_GETOPT_option_uint ('p',
276                                    "num-peers",
277                                    "COUNT",
278                                    gettext_noop ("create COUNT number of peers"),
279                                    &num_peers),
280
281     GNUNET_GETOPT_option_uint ('e',
282                                    "num-errors",
283                                    "COUNT",
284                                    gettext_noop ("tolerate COUNT number of continious timeout failures"),
285                                    &num_cont_fails),
286
287     GNUNET_GETOPT_option_flag ('n',
288                                   "non-interactive",
289                                   gettext_noop ("run profiler in non-interactive mode where upon "
290                                                 "testbed setup the profiler does not wait for a "
291                                                 "keystroke but continues to run until a termination "
292                                                 "signal is received"),
293                                   &noninteractive),
294
295 #if !ENABLE_SUPERMUC
296     GNUNET_GETOPT_option_string ('H',
297                                  "hosts",
298                                  "FILENAME",
299                                  gettext_noop ("name of the file with the login information for the testbed"),
300                                  &hosts_file),
301 #endif
302     GNUNET_GETOPT_OPTION_END
303   };
304   const char *binaryHelp = "gnunet-testbed-profiler [OPTIONS]";
305   int ret;
306
307   unsetenv ("XDG_DATA_HOME");
308   unsetenv ("XDG_CONFIG_HOME");
309   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
310     return 2;
311   result = GNUNET_SYSERR;
312   ret =
313       GNUNET_PROGRAM_run (argc, argv, "gnunet-testbed-profiler", binaryHelp,
314                           options, &run, NULL);
315   GNUNET_free ((void *) argv);
316   if (GNUNET_OK != ret)
317     return ret;
318   if (GNUNET_OK != result)
319     return 1;
320   return 0;
321 }