73785a71c1fb811065283cd7bc1eb37780273a8c
[oweals/gnunet.git] / src / testbed / gnunet-testbed-profiler.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011, 2012 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 testbed/gnunet-testbed-profiler.c
23  * @brief Profiling driver for the testbed.
24  * @author Sree Harsha Totakura <sreeharsha@totakura.in> 
25  */
26
27 #include "platform.h"
28 #include "gnunet_common.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_testbed_service.h"
31 #include "testbed_api_hosts.h"
32
33 /**
34  * Generic loggins shorthand
35  */
36 #define LOG(kind,...)                                           \
37   GNUNET_log (kind, __VA_ARGS__)
38
39
40 /**
41  * DLL of operations
42  */
43 struct DLLOperation
44 {
45   /**
46    * The testbed operation handle
47    */
48   struct GNUNET_TESTBED_Operation *op;
49
50   /**
51    * Closure
52    */
53   void *cls;
54
55   /**
56    * The next pointer for DLL
57    */
58   struct DLLOperation *next;
59
60   /**
61    * The prev pointer for DLL
62    */
63   struct DLLOperation *prev;
64 };
65
66
67 /**
68  * Availanle states during profiling
69  */
70 enum State
71 {
72   /**
73    * Initial state
74    */
75   STATE_INIT = 0,
76
77   /**
78    * Starting slaves
79    */
80   STATE_SLAVES_STARTING,
81
82   /**
83    * Creating peers
84    */
85   STATE_PEERS_CREATING,
86
87   /**
88    * Starting peers
89    */
90   STATE_PEERS_STARTING,
91
92   /**
93    * Linking peers
94    */
95   STATE_PEERS_LINKING,
96
97   /**
98    * Destroying peers; we can do this as the controller takes care of stopping a
99    * peer if it is running
100    */
101   STATE_PEERS_DESTROYING
102 };
103
104
105 /**
106  * An array of hosts loaded from the hostkeys file
107  */
108 static struct GNUNET_TESTBED_Host **hosts;
109
110 /**
111  * The array of peers; we fill this as the peers are given to us by the testbed
112  */
113 static struct GNUNET_TESTBED_Peer **peers;
114
115 /* /\** */
116 /*  * Operation handle */
117 /*  *\/ */
118 /* static struct GNUNET_TESTBED_Operation *op; */
119
120 /**
121  * Host registration handle
122  */
123 static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
124
125 /**
126  * Handle to the master controller process
127  */
128 struct GNUNET_TESTBED_ControllerProc *mc_proc;
129
130 /**
131  * Handle to the master controller
132  */
133 struct GNUNET_TESTBED_Controller *mc;
134
135 /**
136  * Handle to global configuration
137  */
138 struct GNUNET_CONFIGURATION_Handle *cfg;
139
140 /**
141  * Head of the operations list
142  */
143 struct DLLOperation *dll_op_head;
144
145 /**
146  * Tail of the operations list
147  */
148 struct DLLOperation *dll_op_tail;
149
150 /**
151  * Peer linking - topology operation
152  */
153 struct GNUNET_TESTBED_Operation *topology_op;
154
155 /**
156  * Abort task identifier
157  */
158 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
159
160 /**
161  * Shutdown task identifier
162  */
163 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
164
165 /**
166  * Host registration task identifier
167  */
168 static GNUNET_SCHEDULER_TaskIdentifier register_hosts_task;
169
170 /**
171  * Global event mask for all testbed events
172  */
173 uint64_t event_mask;
174
175 /**
176  * The starting time of a profiling step
177  */
178 struct GNUNET_TIME_Absolute prof_start_time;
179
180 /**
181  * Duration profiling step has taken
182  */
183 struct GNUNET_TIME_Relative prof_time;
184
185 /**
186  * Current peer id
187  */
188 unsigned int peer_id;
189
190 /**
191  * Number of peers to be started by the profiler
192  */
193 static unsigned int num_peers;
194
195 /**
196  * Number of hosts in the hosts array
197  */
198 static unsigned int num_hosts;
199
200 /**
201  * Number of random links to be established between peers
202  */
203 static unsigned int num_links;
204
205 /**
206  * Number of timeout failures to tolerate
207  */
208 static unsigned int num_cont_fails;
209
210 /**
211  * Continuous failures during overlay connect operations
212  */
213 static unsigned int cont_fails;
214
215 /**
216  * Links which are successfully established
217  */
218 static unsigned int established_links;
219
220 /**
221  * Links which are not successfully established
222  */
223 static unsigned int failed_links;
224
225 /**
226  * Global testing status
227  */
228 static int result;
229
230 /**
231  * current state of profiling
232  */
233 enum State state;
234
235 /**
236  * The topology we want to acheive
237  */
238 enum GNUNET_TESTBED_TopologyOption topology;
239
240
241 /**
242  * Shutdown nicely
243  *
244  * @param cls NULL
245  * @param tc the task context
246  */
247 static void
248 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
249 {
250   struct DLLOperation *dll_op;
251   unsigned int nhost;
252
253   shutdown_task = GNUNET_SCHEDULER_NO_TASK;
254   if (GNUNET_SCHEDULER_NO_TASK != abort_task)
255     GNUNET_SCHEDULER_cancel (abort_task);
256   if (GNUNET_SCHEDULER_NO_TASK != register_hosts_task)
257     GNUNET_SCHEDULER_cancel (register_hosts_task);
258   if (NULL != reg_handle)
259     GNUNET_TESTBED_cancel_registration (reg_handle);
260   if (NULL != topology_op)
261     GNUNET_TESTBED_operation_cancel (topology_op);
262   for (nhost = 0; nhost < num_hosts; nhost++)
263     if (NULL != hosts[nhost])
264       GNUNET_TESTBED_host_destroy (hosts[nhost]);
265   GNUNET_free_non_null (hosts);
266   while (NULL != (dll_op = dll_op_head))
267   {
268     GNUNET_TESTBED_operation_cancel (dll_op->op);
269     GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op);
270     GNUNET_free (dll_op);
271   }
272   if (NULL != mc)
273     GNUNET_TESTBED_controller_disconnect (mc);
274   if (NULL != mc_proc)
275     GNUNET_TESTBED_controller_stop (mc_proc);
276   if (NULL != cfg)
277     GNUNET_CONFIGURATION_destroy (cfg);
278   GNUNET_SCHEDULER_shutdown (); /* Stop scheduler to shutdown testbed run */
279 }
280
281
282 /**
283  * abort task to run on test timed out
284  *
285  * @param cls NULL
286  * @param tc the task context
287  */
288 static void
289 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
290 {
291   LOG (GNUNET_ERROR_TYPE_WARNING, "Aborting\n");
292   abort_task = GNUNET_SCHEDULER_NO_TASK;
293   result = GNUNET_SYSERR;
294   if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
295     GNUNET_SCHEDULER_cancel (shutdown_task);
296   shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
297 }
298
299
300
301
302
303 /**
304  * Functions of this signature are called when a peer has been successfully
305  * started or stopped.
306  *
307  * @param cls the closure from GNUNET_TESTBED_peer_start/stop()
308  * @param emsg NULL on success; otherwise an error description
309  */
310 static void 
311 peer_churn_cb (void *cls, const char *emsg)
312 {
313   struct DLLOperation *dll_op = cls;
314   struct GNUNET_TESTBED_Operation *op;  
315   static unsigned int started_peers;
316
317   op = dll_op->op;
318   GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op);
319   GNUNET_free (dll_op);
320   if (NULL != emsg)
321   {
322     LOG (GNUNET_ERROR_TYPE_WARNING,
323          _("An operation has failed while starting peers\n"));
324     GNUNET_TESTBED_operation_done (op);
325     GNUNET_SCHEDULER_cancel (abort_task);
326     abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
327     return;
328   }
329   GNUNET_TESTBED_operation_done (op);
330   if (++started_peers == num_peers)
331   {
332     prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time);
333     printf ("%u peers started successfully in %.2f seconds\n",
334             num_peers, ((double) prof_time.rel_value) / 1000.00);
335     fflush (stdout);
336     result = GNUNET_OK;
337     if ((0 == num_links) && (topology == GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI))
338     {      
339       shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
340       return;
341     }
342     state = STATE_PEERS_LINKING;
343     /* Do overlay connect */
344     prof_start_time = GNUNET_TIME_absolute_get ();
345     switch (topology)
346     {
347     case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
348       topology_op =
349           GNUNET_TESTBED_overlay_configure_topology (NULL, num_peers, peers,
350                                                      topology,
351                                                      num_links,
352                                                      GNUNET_TESTBED_TOPOLOGY_DISABLE_AUTO_RETRY,
353                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
354       break;
355     case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
356       topology_op =
357           GNUNET_TESTBED_overlay_configure_topology (NULL, num_peers, peers,
358                                                      topology,
359                                                      GNUNET_TESTBED_TOPOLOGY_DISABLE_AUTO_RETRY,
360                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
361       break;
362     default:
363       GNUNET_assert (0);
364     }
365   }
366 }
367
368
369 /**
370  * Functions of this signature are called when a peer has been successfully
371  * created
372  *
373  * @param cls the closure from GNUNET_TESTBED_peer_create()
374  * @param peer the handle for the created peer; NULL on any error during
375  *          creation
376  * @param emsg NULL if peer is not NULL; else MAY contain the error description
377  */
378 static void 
379 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
380 {
381   struct DLLOperation *dll_op = cls;
382   struct GNUNET_TESTBED_Peer **peer_ptr;
383   static unsigned int created_peers;
384   unsigned int peer_cnt;
385
386   if (NULL != emsg)
387   {
388     LOG (GNUNET_ERROR_TYPE_WARNING,
389          _("Creating a peer failed. Error: %s\n"), emsg);
390     GNUNET_TESTBED_operation_done (dll_op->op);
391     GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op);
392     GNUNET_free (dll_op);
393     GNUNET_SCHEDULER_cancel (abort_task);
394     abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
395     return;
396   }
397   peer_ptr = dll_op->cls;
398   GNUNET_assert (NULL == *peer_ptr);
399   *peer_ptr = peer;
400   GNUNET_TESTBED_operation_done (dll_op->op);
401   GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op);
402   GNUNET_free (dll_op);
403   if (++created_peers == num_peers)
404   {
405     prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time);    
406     printf ("%u peers created successfully in %.2f seconds\n",
407             num_peers, ((double) prof_time.rel_value) / 1000.00);
408     fflush (stdout);
409     /* Now peers are to be started */
410     state = STATE_PEERS_STARTING;
411     prof_start_time = GNUNET_TIME_absolute_get ();
412     for (peer_cnt = 0; peer_cnt < num_peers; peer_cnt++)
413     {
414       dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
415       dll_op->op = GNUNET_TESTBED_peer_start (dll_op, peers[peer_cnt], 
416                                               &peer_churn_cb, dll_op);
417       GNUNET_CONTAINER_DLL_insert_tail (dll_op_head, dll_op_tail, dll_op);
418     }
419   }
420 }
421
422
423 /**
424  * Function to print summary about how many overlay links we have made and how
425  * many failed
426  */
427 static void
428 print_overlay_links_summary ()
429 {
430   prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time);
431   printf ("\n%u links established in %.2f seconds\n",
432           established_links, ((double) prof_time.rel_value) / 1000.00);
433   printf ("%u links failed due to timeouts\n", failed_links);
434 }
435
436
437 /**
438  * Function to start peers
439  */
440 static void
441 start_peers ()
442 {
443   struct DLLOperation *dll_op;
444   unsigned int peer_cnt;
445   
446   state = STATE_PEERS_CREATING;
447   prof_start_time = GNUNET_TIME_absolute_get ();
448   peers = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *)
449                          * num_peers);
450   for (peer_cnt = 0; peer_cnt < num_peers; peer_cnt++)
451   {
452     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
453     dll_op->cls = &peers[peer_cnt];
454     dll_op->op = GNUNET_TESTBED_peer_create (mc,
455                                              hosts
456                                              [peer_cnt % num_hosts],
457                                              cfg,
458                                              &peer_create_cb,
459                                              dll_op);
460     GNUNET_CONTAINER_DLL_insert_tail (dll_op_head, dll_op_tail, dll_op);
461   }
462 }
463
464
465 /**
466  * Controller event callback
467  *
468  * @param cls NULL
469  * @param event the controller event
470  */
471 static void
472 controller_event_cb (void *cls,
473                      const struct GNUNET_TESTBED_EventInformation *event)
474 {
475   struct DLLOperation *dll_op;
476   struct GNUNET_TESTBED_Operation *op;
477
478   switch (state)
479   {
480   case STATE_SLAVES_STARTING:
481     switch (event->type)
482     {
483     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
484       {
485         static unsigned int slaves_started;
486         
487         dll_op = event->details.operation_finished.op_cls;
488         GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op);
489         GNUNET_free (dll_op);
490         op = event->details.operation_finished.operation;
491         if (NULL != event->details.operation_finished.emsg)
492         {
493           LOG (GNUNET_ERROR_TYPE_WARNING,
494                _("An operation has failed while starting slaves\n"));
495           GNUNET_TESTBED_operation_done (op);
496           GNUNET_SCHEDULER_cancel (abort_task);
497           abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
498           return;
499         }
500         GNUNET_TESTBED_operation_done (op);
501         /* Proceed to start peers */
502         if (++slaves_started == num_hosts - 1)
503         {
504           printf ("%u controllers started successfully\n", num_hosts);
505           fflush (stdout);
506           start_peers ();
507         }
508       }
509       break;
510     default:
511       GNUNET_assert (0);
512     }
513     break;
514   case STATE_PEERS_STARTING:
515     switch (event->type)
516     {
517     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
518       /* Control reaches here when peer start fails */
519     case GNUNET_TESTBED_ET_PEER_START:
520       /* we handle peer starts in peer_churn_cb */
521       break;
522     default:
523       GNUNET_assert (0);
524     }
525     break;
526   case STATE_PEERS_LINKING:
527    switch (event->type)
528     {
529     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
530       /* Control reaches here when a peer linking operation fails */
531       if (NULL != event->details.operation_finished.emsg)
532       {
533         printf ("F");
534         fflush (stdout);
535         failed_links++;
536         if (++cont_fails > num_cont_fails)
537         {
538           printf ("\nAborting due to very high failure rate");
539           print_overlay_links_summary ();         
540           GNUNET_SCHEDULER_cancel (abort_task);
541           abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
542         }
543       }
544       break;
545     case GNUNET_TESTBED_ET_CONNECT:
546       {
547         if (0 != cont_fails)
548           cont_fails--;
549         if (0 == established_links)
550           printf ("Establishing links. Please wait\n");
551         printf (".");
552         fflush (stdout);
553         established_links++;
554         if ((established_links + failed_links) == 
555             (GNUNET_TESTBED_TOPOLOGY_CLIQUE == topology ? 
556              num_peers * (num_peers -1) : num_links))
557         {
558           print_overlay_links_summary ();
559           result = GNUNET_OK;
560           shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
561         }
562       }
563       break;
564     default:
565       GNUNET_assert (0);
566     }
567     break;
568   default:
569     GNUNET_assert (0);
570   }
571 }
572
573
574 /**
575  * Task to register all hosts available in the global host list
576  *
577  * @param cls NULL
578  * @param tc the scheduler task context
579  */
580 static void
581 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
582
583
584 /**
585  * Callback which will be called to after a host registration succeeded or failed
586  *
587  * @param cls the closure
588  * @param emsg the error message; NULL if host registration is successful
589  */
590 static void
591 host_registration_completion (void *cls, const char *emsg)
592 {
593   reg_handle = NULL;
594   if (NULL != emsg)
595   {
596     LOG (GNUNET_ERROR_TYPE_WARNING,
597          _("Host registration failed for a host. Error: %s\n"), emsg);
598     GNUNET_SCHEDULER_cancel (abort_task);
599     abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
600     return;
601   }
602   register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, NULL);
603 }
604
605
606 /**
607  * Task to register all hosts available in the global host list
608  *
609  * @param cls NULL
610  * @param tc the scheduler task context
611  */
612 static void
613 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
614 {
615   struct DLLOperation *dll_op;
616   static unsigned int reg_host;
617   unsigned int slave;
618
619   register_hosts_task = GNUNET_SCHEDULER_NO_TASK;  
620   if (reg_host == num_hosts - 1)
621   {
622     LOG (GNUNET_ERROR_TYPE_DEBUG,
623          "All hosts successfully registered\n");
624     /* Start slaves */
625     state = STATE_SLAVES_STARTING;
626     for (slave = 1; slave < num_hosts; slave++)
627     {
628       dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
629       dll_op->op = GNUNET_TESTBED_controller_link (dll_op,
630                                                    mc,
631                                                    hosts[slave],
632                                                    hosts[0],
633                                                    cfg,
634                                                    GNUNET_YES);
635       GNUNET_CONTAINER_DLL_insert_tail (dll_op_head, dll_op_tail, dll_op);
636     }
637     return;
638   }
639   reg_handle = GNUNET_TESTBED_register_host (mc, hosts[++reg_host],
640                                              host_registration_completion,
641                                              NULL);
642 }
643
644
645 /**
646  * Callback to signal successfull startup of the controller process
647  *
648  * @param cls the closure from GNUNET_TESTBED_controller_start()
649  * @param config the configuration with which the controller has been started;
650  *          NULL if status is not GNUNET_OK
651  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
652  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
653  */
654 static void
655 status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *config, int status)
656 {
657   if (GNUNET_SCHEDULER_NO_TASK != abort_task)
658     GNUNET_SCHEDULER_cancel (abort_task);
659   if (GNUNET_OK != status)
660   {
661     mc_proc = NULL;
662     abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
663     return;
664   }
665   event_mask = 0;
666   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
667   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
668   event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
669   event_mask |= (1LL << GNUNET_TESTBED_ET_DISCONNECT);
670   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
671   mc = GNUNET_TESTBED_controller_connect (config, hosts[0], event_mask,
672                                           &controller_event_cb, NULL);
673   if (NULL == mc)
674   {
675     LOG (GNUNET_ERROR_TYPE_WARNING,
676          _("Unable to connect to master controller -- Check config\n"));
677     abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
678     return;
679   }
680   if (num_hosts > 1)
681     register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, NULL);
682   else
683     start_peers ();
684   abort_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
685                                              &do_abort, NULL);
686 }
687
688
689 /**
690  * Main function that will be run by the scheduler.
691  *
692  * @param cls closure
693  * @param args remaining command-line arguments
694  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
695  * @param config configuration
696  */
697 static void
698 run (void *cls, char *const *args, const char *cfgfile,
699      const struct GNUNET_CONFIGURATION_Handle *config)
700 {
701   unsigned int nhost;
702
703   if (NULL == args[0])
704   {
705     fprintf (stderr, _("No hosts-file specified on command line\n"));
706     return;
707   }
708   if (0 == num_peers)
709   {
710     result = GNUNET_OK;
711     return;
712   }
713   num_hosts = GNUNET_TESTBED_hosts_load_from_file (args[0], &hosts);
714   if (0 == num_hosts)
715   {
716     fprintf (stderr, _("No hosts loaded. Need atleast one host\n"));
717     return;
718   }
719   for (nhost = 0; nhost < num_hosts; nhost++)
720   {
721     if (GNUNET_YES != GNUNET_TESTBED_is_host_habitable (hosts[nhost]))
722     {
723       fprintf (stderr, _("Host %s cannot start testbed\n"),
724                GNUNET_TESTBED_host_get_hostname_ (hosts[nhost]));
725       break;
726     }
727   }
728   if (num_hosts != nhost)
729   {
730     fprintf (stderr, _("Exiting\n"));
731     shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
732     return;
733   }
734   cfg = GNUNET_CONFIGURATION_dup (config);
735   mc_proc = 
736       GNUNET_TESTBED_controller_start (GNUNET_TESTBED_host_get_hostname_ 
737                                        (hosts[0]),
738                                        hosts[0],
739                                        cfg,
740                                        status_cb,
741                                        NULL);
742   abort_task =
743       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
744                                     (GNUNET_TIME_UNIT_SECONDS, 5), &do_abort,
745                                     NULL);
746 }
747
748
749 /**
750  * Set an option of type 'char *' from the command line.
751  * A pointer to this function should be passed as part of the
752  * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
753  * of this type.  It should be followed by a pointer to a value of
754  * type 'char *'.
755  *
756  * @param ctx command line processing context
757  * @param scls additional closure (will point to the 'char *',
758  *             which will be allocated)
759  * @param option name of the option
760  * @param value actual value of the option (a string)
761  * @return GNUNET_OK to continue procesing; GNUNET_SYSERR to signal error
762  */
763 int
764 set_topology (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
765               void *scls, const char *option, const char *value)
766 {
767   enum GNUNET_TESTBED_TopologyOption *val = scls;
768
769   if (0 == strncasecmp ("CLIQUE", value, strlen ("CLIQUE")))
770   {  
771     *val = GNUNET_TESTBED_TOPOLOGY_CLIQUE;
772     return GNUNET_OK;
773   }
774   if (0 == strncasecmp ("RANDOM", value, strlen ("RANDOM")))
775   {  
776     *val = GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI;
777     return GNUNET_OK;
778   }
779   FPRINTF (stderr, "%s", _("Only `CLIQUE' and `RANDOM' are permitted.\n"));
780   return GNUNET_SYSERR;
781 }
782
783
784 /**
785  * Main function.
786  *
787  * @return 0 on success
788  */
789 int
790 main (int argc, char *const *argv)
791 {
792   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
793     { 'p', "num-peers", "COUNT",
794       gettext_noop ("create COUNT number of peers"),
795       GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers },
796     { 'n', "num-links", "COUNT",
797       gettext_noop ("create COUNT number of random links"),
798       GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_links },
799     { 'e', "num-errors", "COUNT",
800       gettext_noop ("tolerate COUNT number of continious timeout failures"),
801       GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_cont_fails },
802     { 't', "topology", "TOPOLOGY",
803       gettext_noop ("Try to acheive TOPOLOGY. This options takes either CLIQUE "
804                     "or RANDOM. For CLIQUE the parameter -n is ignored. The "
805                     "default is to acheive a random graph topology."),
806       GNUNET_YES, &set_topology, &topology },
807     GNUNET_GETOPT_OPTION_END
808   };
809   int ret;
810
811   topology = GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI;
812   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
813     return 2;
814   
815   result = GNUNET_SYSERR;
816   ret =
817       GNUNET_PROGRAM_run (argc, argv, "gnunet-testbed-profiler [OPTIONS] hosts-file",
818                           _("Profiler for testbed"),
819                           options, &run, NULL);
820   if (GNUNET_OK != ret)
821     return ret;
822   if (GNUNET_OK != result)
823     return 1;
824   return 0;
825 }