- print time durations in debug output
[oweals/gnunet.git] / src / testbed / testbed_api_testbed.c
1 /*
2   This file is part of GNUnet
3   (C) 2008--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/testbed_api_testbed.c
23  * @brief high-level testbed management
24  * @author Christian Grothoff
25  * @author Sree Harsha Totakura
26  */
27
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_testbed_service.h"
31 #include "testbed_api_peers.h"
32 #include "testbed_api_hosts.h"
33 #include "testbed_api_topology.h"
34
35 /**
36  * Generic loggins shorthand
37  */
38 #define LOG(kind,...)                                           \
39   GNUNET_log_from (kind, "testbed-api-testbed", __VA_ARGS__)
40
41 /**
42  * Debug logging shortcut
43  */
44 #define DEBUG(...)                              \
45   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
46
47 /**
48  * DLL of operations
49  */
50 struct DLLOperation
51 {
52   /**
53    * The testbed operation handle
54    */
55   struct GNUNET_TESTBED_Operation *op;
56
57   /**
58    * Context information for GNUNET_TESTBED_run()
59    */
60   struct RunContext *rc;
61
62   /**
63    * Closure
64    */
65   void *cls;
66
67   /**
68    * The next pointer for DLL
69    */
70   struct DLLOperation *next;
71
72   /**
73    * The prev pointer for DLL
74    */
75   struct DLLOperation *prev;
76 };
77
78
79 /**
80  * States of RunContext
81  */
82 enum State
83 {
84   /**
85    * Initial state
86    */
87   RC_INIT = 0,
88
89   /**
90    * Controllers on given hosts started and linked
91    */
92   RC_LINKED,
93
94   /**
95    * The testbed run is ready and the master callback can be called now. At this
96    * time the peers are all started and if a topology is provided in the
97    * configuration the topology would have been attempted
98    */
99   RC_READY,
100
101   /**
102    * Peers are stopped
103    */
104   RC_PEERS_STOPPED,
105
106   /**
107    * Peers are destroyed
108    */
109   RC_PEERS_DESTROYED
110 };
111
112
113 /**
114  * Testbed Run Handle
115  */
116 struct RunContext
117 {
118   /**
119    * The controller handle
120    */
121   struct GNUNET_TESTBED_Controller *c;
122
123   /**
124    * The configuration of the controller. This is based on the cfg given to the
125    * function GNUNET_TESTBED_run(). We also use this config as a template while
126    * for peers
127    */
128   struct GNUNET_CONFIGURATION_Handle *cfg;
129
130   /**
131    * Handle to the host on which the controller runs
132    */
133   struct GNUNET_TESTBED_Host *h;
134
135   /**
136    * The handle to the controller process
137    */
138   struct GNUNET_TESTBED_ControllerProc *cproc;
139
140   /**
141    * The callback to use as controller callback
142    */
143   GNUNET_TESTBED_ControllerCallback cc;
144
145   /**
146    * The pointer to the controller callback
147    */
148   void *cc_cls;
149
150   /**
151    * The trusted IP string
152    */
153   char *trusted_ip;
154
155   /**
156    * TestMaster callback to call when testbed initialization is done
157    */
158   GNUNET_TESTBED_TestMaster test_master;
159   
160   /**
161    * The closure for the TestMaster callback
162    */
163   void *test_master_cls;
164
165   /**
166    * The head element of DLL operations
167    */
168   struct DLLOperation *dll_op_head;
169
170   /**
171    * The tail element of DLL operations
172    */
173   struct DLLOperation *dll_op_tail;
174
175   /**
176    * An array of hosts loaded from the hostkeys file
177    */
178   struct GNUNET_TESTBED_Host **hosts;
179
180   /**
181    * The handle for whether a host is habitable or not
182    */
183   struct GNUNET_TESTBED_HostHabitableCheckHandle **hc_handles;
184
185   /**
186    * Array of peers which we create
187    */
188   struct GNUNET_TESTBED_Peer **peers;
189
190   /**
191    * The topology generation operation. Will be null if no topology is set in
192    * the configuration
193    */
194   struct GNUNET_TESTBED_Operation *topology_operation;
195
196   /**
197    * The file containing topology data. Only used if the topology is set to 'FROM_FILE'
198    */
199   char *topo_file;
200
201   /**
202    * Host registration handle
203    */
204   struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
205
206   /**
207    * Profiling start time
208    */
209   struct GNUNET_TIME_Absolute pstart_time;
210
211   /**
212    * Host registration task
213    */
214   GNUNET_SCHEDULER_TaskIdentifier register_hosts_task;
215
216   /**
217    * Task to be run while shutting down
218    */
219   GNUNET_SCHEDULER_TaskIdentifier shutdown_run_task;
220
221   /**
222    * The event mask for the controller
223    */
224   uint64_t event_mask;
225
226   /**
227    * State of this context
228    */
229   enum State state;
230
231   /**
232    * The topology which has to be achieved with the peers started in this context
233    */
234   enum GNUNET_TESTBED_TopologyOption topology;
235
236   /**
237    * Have we already shutdown
238    */
239   int shutdown;
240
241   /**
242    * Number of hosts in the given host file
243    */
244   unsigned int num_hosts;
245
246   /**
247    * Number of registered hosts. Also used as a counter while checking
248    * habitabillity of hosts
249    */
250   unsigned int reg_hosts;
251
252   /**
253    * Current peer count for an operation; Set this to 0 and increment for each
254    * successful operation on a peer
255    */
256   unsigned int peer_count;
257
258   /**
259    * number of peers to start
260    */
261   unsigned int num_peers;
262
263   /**
264    * counter to count overlay connect attempts. This counter includes both
265    * successful and failed overlay connects
266    */
267   unsigned int oc_count;
268
269   /**
270    * Expected overlay connects. Should be zero if no topology is relavant
271    */
272   unsigned int num_oc;
273
274   /**
275    * Number of random links to established
276    */
277   unsigned int random_links;
278   
279 };
280
281
282 /**
283  * Function to return the string representation of the duration between current
284  * time and `pstart_time' in `RunContext'
285  *
286  * @param rc the RunContext
287  * @return the representation string; this is NOT reentrant
288  */
289 static const char *
290 prof_time (struct RunContext *rc)
291 {
292   struct GNUNET_TIME_Relative ptime;
293
294   ptime = GNUNET_TIME_absolute_get_duration (rc->pstart_time);
295   return GNUNET_STRINGS_relative_time_to_string (ptime, GNUNET_YES);
296 }
297
298
299 /**
300  * Task for starting peers
301  *
302  * @param cls the RunHandle
303  * @param tc the task context from scheduler
304  */
305 static void
306 start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
307 {
308   struct RunContext *rc = cls;
309   struct DLLOperation *dll_op;
310   unsigned int peer;
311
312   DEBUG ("Starting Peers\n");
313   rc->pstart_time = GNUNET_TIME_absolute_get ();
314   for (peer = 0; peer < rc->num_peers; peer++)
315   {
316     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
317     dll_op->op = GNUNET_TESTBED_peer_start (NULL, rc->peers[peer], NULL, NULL);
318     dll_op->cls = rc->peers[peer];
319     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
320   }
321   rc->peer_count = 0;
322 }
323
324
325 /**
326  * Functions of this signature are called when a peer has been successfully
327  * created
328  *
329  * @param cls the closure from GNUNET_TESTBED_peer_create()
330  * @param peer the handle for the created peer; NULL on any error during
331  *          creation
332  * @param emsg NULL if peer is not NULL; else MAY contain the error description
333  */
334 static void
335 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
336 {
337   struct DLLOperation *dll_op = cls;
338   struct RunContext *rc;
339
340   GNUNET_assert (NULL != dll_op);
341   rc = dll_op->rc;
342   GNUNET_assert (NULL != rc);
343   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
344   GNUNET_TESTBED_operation_done (dll_op->op);
345   GNUNET_free (dll_op);
346   if (NULL == peer)
347   {
348     if (NULL != emsg)
349       LOG (GNUNET_ERROR_TYPE_WARNING, "Error while creating a peer: %s\n",
350            emsg);
351     /* FIXME: GNUNET_TESTBED_shutdown_run()? */
352     return;
353   }
354   rc->peers[rc->peer_count] = peer;
355   rc->peer_count++;
356   if (rc->peer_count < rc->num_peers)
357     return;
358   DEBUG ("%u peers created in %s\n", rc->num_peers, prof_time (rc));
359   GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
360 }
361
362
363 /**
364  * Assuming all peers have been destroyed cleanup run handle
365  *
366  * @param cls the run handle
367  * @param tc the task context from scheduler
368  */
369 static void
370 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
371 {
372   struct RunContext *rc = cls;
373   struct DLLOperation *dll_op;
374   unsigned int hid;
375
376   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rc->register_hosts_task);
377   GNUNET_assert (NULL == rc->reg_handle);
378   GNUNET_assert (NULL == rc->peers);
379   GNUNET_assert (NULL == rc->hc_handles);
380   GNUNET_assert (RC_PEERS_DESTROYED == rc->state);
381   if (NULL != rc->dll_op_head)
382   {                             /* cancel our pending operations */
383     while (NULL != (dll_op = rc->dll_op_head))
384     {
385       GNUNET_TESTBED_operation_done (dll_op->op);
386       GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
387       GNUNET_free (dll_op);
388     }
389   }
390   if (NULL != rc->c)
391     GNUNET_TESTBED_controller_disconnect (rc->c);
392   if (NULL != rc->cproc)
393     GNUNET_TESTBED_controller_stop (rc->cproc);
394   if (NULL != rc->h)
395     GNUNET_TESTBED_host_destroy (rc->h);
396   for (hid = 0; hid < rc->num_hosts; hid++)
397         GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
398   GNUNET_free_non_null (rc->hosts);
399   if (NULL != rc->cfg)
400     GNUNET_CONFIGURATION_destroy (rc->cfg);
401   GNUNET_free_non_null (rc->topo_file);
402   GNUNET_free_non_null (rc->trusted_ip);
403   GNUNET_free (rc);
404 }
405
406
407 /**
408  * Stops the testbed run and releases any used resources
409  *
410  * @param cls the tesbed run handle
411  * @param tc the task context from scheduler
412  */
413 static void
414 shutdown_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
415
416
417 /**
418  * Function to shutdown now
419  *
420  * @param rc the RunContext
421  */
422 static void
423 shutdown_now (struct RunContext *rc)
424 {
425   if (GNUNET_YES == rc->shutdown)
426     return;
427   if (GNUNET_SCHEDULER_NO_TASK != rc->shutdown_run_task)
428     GNUNET_SCHEDULER_cancel (rc->shutdown_run_task);
429   rc->shutdown_run_task = GNUNET_SCHEDULER_add_now (&shutdown_run, rc);
430 }
431
432
433 /**
434  * Stops the testbed run and releases any used resources
435  *
436  * @param cls the tesbed run handle
437  * @param tc the task context from scheduler
438  */
439 static void
440 shutdown_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
441 {
442   struct RunContext *rc = cls;
443   struct DLLOperation *dll_op;
444   int all_peers_destroyed;
445   unsigned int peer;
446   unsigned int nhost;
447
448   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != rc->shutdown_run_task);
449   rc->shutdown_run_task = GNUNET_SCHEDULER_NO_TASK;
450   GNUNET_assert (GNUNET_NO == rc->shutdown);
451   rc->shutdown = GNUNET_YES;
452   if (NULL != rc->hc_handles)
453   {
454     for (nhost = 0; nhost < rc->num_hosts; nhost++)
455       if (NULL != rc->hc_handles[nhost])
456         GNUNET_TESTBED_is_host_habitable_cancel (rc->hc_handles[nhost]);
457     GNUNET_free (rc->hc_handles);
458     rc->hc_handles = NULL;
459   }
460   /* Stop register hosts task if it is running */
461   if (GNUNET_SCHEDULER_NO_TASK != rc->register_hosts_task)
462   {
463     GNUNET_SCHEDULER_cancel (rc->register_hosts_task);
464     rc->register_hosts_task = GNUNET_SCHEDULER_NO_TASK;
465   }
466   if (NULL != rc->reg_handle)
467   {
468     GNUNET_TESTBED_cancel_registration (rc->reg_handle);
469     rc->reg_handle = NULL;
470   }
471   if (NULL != rc->c)
472   {
473     if (NULL != rc->peers)
474     {
475       if (NULL != rc->topology_operation)
476       {
477         GNUNET_TESTBED_operation_done (rc->topology_operation);
478         rc->topology_operation = NULL;
479       }
480       if (RC_INIT == rc->state)
481         rc->state = RC_READY;   /* Even though we haven't called the master callback */
482       rc->peer_count = 0;
483       /* Check if some peers are stopped */
484       for (peer = 0; peer < rc->num_peers; peer++)
485       {
486         if (NULL == rc->peers[peer])
487           continue;
488         if (PS_STOPPED != rc->peers[peer]->state)
489           break;
490       }
491       if (peer == rc->num_peers)
492       {
493         /* All peers are stopped */
494         rc->state = RC_PEERS_STOPPED;
495         all_peers_destroyed = GNUNET_YES;
496         for (peer = 0; peer < rc->num_peers; peer++)
497         {
498           if (NULL == rc->peers[peer])
499             continue;
500           all_peers_destroyed = GNUNET_NO;
501           dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
502           dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer]);
503           GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
504                                             dll_op);
505         }
506         if (all_peers_destroyed == GNUNET_NO)
507         {
508           DEBUG ("Destroying peers\n");
509           rc->pstart_time = GNUNET_TIME_absolute_get ();
510           return;
511         }
512       }
513       /* Some peers are stopped */
514       DEBUG ("Stopping peers\n");
515       rc->pstart_time = GNUNET_TIME_absolute_get ();
516       for (peer = 0; peer < rc->num_peers; peer++)
517       {
518         if ((NULL == rc->peers[peer]) || (PS_STARTED != rc->peers[peer]->state))
519         {
520           rc->peer_count++;
521           continue;
522         }
523         dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
524         dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer], NULL, NULL);
525         dll_op->cls = rc->peers[peer];
526         GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
527                                           dll_op);
528       }
529       if (rc->peer_count != rc->num_peers)
530         return;
531       GNUNET_free (rc->peers);
532       rc->peers = NULL;
533     }    
534   }
535   rc->state = RC_PEERS_DESTROYED;       /* No peers are present so we consider the
536                                          * state where all peers are destroyed  */
537   GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
538 }
539
540
541 /**
542  * Task to call master task
543  *
544  * @param cls the run context
545  * @param tc the task context
546  */
547 static void
548 call_master (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
549 {
550   struct RunContext *rc = cls;
551   
552   if (NULL != rc->topology_operation)
553   {
554     GNUNET_TESTBED_operation_done (rc->topology_operation);
555     rc->topology_operation = NULL;
556   }
557   if (NULL != rc->test_master)
558     rc->test_master (rc->test_master_cls, rc->num_peers, rc->peers);
559 }
560
561
562 /**
563  * Function to create peers
564  *
565  * @param rc the RunContext
566  */
567 static void
568 create_peers (struct RunContext *rc)
569 {
570   struct DLLOperation *dll_op;
571   unsigned int peer;
572  
573   DEBUG ("Creating peers\n");
574   rc->pstart_time = GNUNET_TIME_absolute_get ();
575   rc->peers =
576       GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
577   GNUNET_assert (NULL != rc->c);
578   rc->peer_count = 0;
579   for (peer = 0; peer < rc->num_peers; peer++)
580   {
581     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
582     dll_op->rc = rc;
583     dll_op->op =
584         GNUNET_TESTBED_peer_create (rc->c, 
585                                     (0 == rc->num_hosts)
586                                     ? rc->h : rc->hosts[peer % rc->num_hosts],
587                                     rc->cfg,
588                                     peer_create_cb, dll_op);
589     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
590   }
591 }
592
593
594 /**
595  * Signature of the event handler function called by the
596  * respective event controller.
597  *
598  * @param cls closure
599  * @param event information about the event
600  */
601 static void
602 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
603 {
604   struct RunContext *rc = cls;
605   struct DLLOperation *dll_op;
606   unsigned int peer_id;
607
608   if (RC_INIT == rc->state)
609   {
610     switch (event->type)
611     {
612     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
613       dll_op = event->details.operation_finished.op_cls;
614       if (NULL != event->details.operation_finished.emsg)
615       {
616         LOG (GNUNET_ERROR_TYPE_ERROR,
617              _("Linking controllers failed. Exiting"));
618         shutdown_now (rc);
619       }
620       else
621         rc->reg_hosts++;
622       GNUNET_assert (event->details.operation_finished.operation == dll_op->op);
623       GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
624       GNUNET_TESTBED_operation_done (dll_op->op);
625       GNUNET_free (dll_op);
626       if (rc->reg_hosts == rc->num_hosts)
627       {
628         rc->state = RC_LINKED;
629         create_peers (rc);
630       }
631       return;
632     default:
633       GNUNET_break (0);
634       shutdown_now (rc);
635       return;
636     }
637   }
638   if (NULL != rc->topology_operation)
639   {
640     switch (event->type)
641     {
642     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
643     case GNUNET_TESTBED_ET_CONNECT:
644       rc->oc_count++;
645       break;
646     default:
647       GNUNET_break (0);
648       shutdown_now (rc);
649       return;
650     }
651     if (rc->oc_count == rc->num_oc)
652     {
653       rc->state = RC_READY;
654       GNUNET_SCHEDULER_add_continuation (&call_master, rc,
655                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
656     }
657     goto call_cc;
658   }
659   for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
660   {
661     if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
662         (event->details.operation_finished.operation == dll_op->op))
663       break;
664     if ((GNUNET_TESTBED_ET_PEER_STOP == event->type) &&
665         (event->details.peer_stop.peer == dll_op->cls))
666       break;
667   }
668   if (NULL == dll_op)
669     goto call_cc;
670   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
671   GNUNET_TESTBED_operation_done (dll_op->op);
672   GNUNET_free (dll_op);
673   rc->peer_count++;
674   if (rc->peer_count < rc->num_peers)
675     return;
676   switch (rc->state)
677   {
678   case RC_LINKED:
679   case RC_READY:
680     rc->state = RC_PEERS_STOPPED;
681     DEBUG ("Peers stopped in %s\n", prof_time (rc));
682     DEBUG ("Destroying peers\n");
683     rc->pstart_time = GNUNET_TIME_absolute_get ();
684     rc->peer_count = 0;
685     for (peer_id = 0; peer_id < rc->num_peers; peer_id++)
686     {
687       dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
688       dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer_id]);
689       GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
690                                         dll_op);
691     }
692     break;
693   case RC_PEERS_STOPPED:
694     rc->state = RC_PEERS_DESTROYED;
695     GNUNET_free (rc->peers);
696     rc->peers = NULL;
697     DEBUG ("Peers destroyed in %s\n", prof_time (rc));
698     GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
699     break;
700   default:
701     GNUNET_assert (0);
702   }
703   return;
704
705 call_cc:
706   if ((0 != (rc->event_mask & (1LL << event->type))) && (NULL != rc->cc))
707     rc->cc (rc->cc_cls, event);
708   if (GNUNET_TESTBED_ET_PEER_START != event->type)
709     return;
710   for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
711     if ((NULL != dll_op->cls) &&
712         (event->details.peer_start.peer == dll_op->cls))
713       break;
714   if (NULL == dll_op)           /* Not our operation */
715     return;
716   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
717   GNUNET_TESTBED_operation_done (dll_op->op);
718   GNUNET_free (dll_op);
719   rc->peer_count++;
720   if (rc->peer_count < rc->num_peers)
721     return;  
722   DEBUG ("%u peers started in %s\n", rc->num_peers,
723          prof_time (rc));
724   if (GNUNET_TESTBED_TOPOLOGY_NONE != rc->topology)
725   {
726     if ( (GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology)
727          || (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology)
728          || (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD == rc->topology))
729     {
730       rc->topology_operation =
731           GNUNET_TESTBED_overlay_configure_topology (NULL,
732                                                      rc->num_peers,
733                                                      rc->peers,
734                                                      &rc->num_oc,
735                                                      rc->topology,
736                                                      rc->random_links,
737                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
738     }
739     else if (GNUNET_TESTBED_TOPOLOGY_FROM_FILE == rc->topology)
740     {
741       GNUNET_assert (NULL != rc->topo_file);
742       rc->topology_operation =
743           GNUNET_TESTBED_overlay_configure_topology (NULL,
744                                                      rc->num_peers,
745                                                      rc->peers,
746                                                      &rc->num_oc,
747                                                      rc->topology,
748                                                      rc->topo_file,
749                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
750     }
751     else
752       rc->topology_operation =
753           GNUNET_TESTBED_overlay_configure_topology (NULL,
754                                                      rc->num_peers,
755                                                      rc->peers,
756                                                      &rc->num_oc,
757                                                      rc->topology,
758                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
759     if (NULL == rc->topology_operation)
760       LOG (GNUNET_ERROR_TYPE_WARNING,
761            "Not generating topology. Check number of peers\n");
762     else
763       return;
764   }
765   rc->state = RC_READY;
766   GNUNET_SCHEDULER_add_continuation (&call_master, rc,
767                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
768 }
769
770
771 /**
772  * Task to register all hosts available in the global host list
773  *
774  * @param cls the RunContext
775  * @param tc the scheduler task context
776  */
777 static void
778 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
779
780
781 /**
782  * Callback which will be called to after a host registration succeeded or failed
783  *
784  * @param cls the closure
785  * @param emsg the error message; NULL if host registration is successful
786  */
787 static void
788 host_registration_completion (void *cls, const char *emsg)
789 {
790   struct RunContext *rc = cls;
791
792   rc->reg_handle = NULL;
793   if (NULL != emsg)
794   {
795     LOG (GNUNET_ERROR_TYPE_WARNING,
796          _("Host registration failed for a host. Error: %s\n"), emsg);
797     shutdown_now (rc);
798     return;
799   }
800   rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
801 }
802
803
804 /**
805  * Task to register all hosts available in the global host list
806  *
807  * @param cls RunContext
808  * @param tc the scheduler task context
809  */
810 static void
811 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
812 {
813   struct RunContext *rc = cls;
814   struct DLLOperation *dll_op;
815   unsigned int slave;
816
817   rc->register_hosts_task = GNUNET_SCHEDULER_NO_TASK;
818   if (rc->reg_hosts == rc->num_hosts)
819   {
820     DEBUG ("All hosts successfully registered\n");
821     /* Start slaves */
822     for (slave = 0; slave < rc->num_hosts; slave++)
823     {
824       dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
825       dll_op->rc = rc;
826       dll_op->op = GNUNET_TESTBED_controller_link (dll_op,
827                                                    rc->c,
828                                                    rc->hosts[slave],
829                                                    rc->h,
830                                                    rc->cfg,
831                                                    GNUNET_YES);
832       GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
833     }
834     rc->reg_hosts = 0;
835     return;
836   }
837   rc->reg_handle = GNUNET_TESTBED_register_host (rc->c,
838                                                  rc->hosts[rc->reg_hosts++],
839                                                  host_registration_completion,
840                                                  rc);
841 }
842
843
844 /**
845  * Callback to signal successfull startup of the controller process
846  *
847  * @param cls the closure from GNUNET_TESTBED_controller_start()
848  * @param cfg the configuration with which the controller has been started;
849  *          NULL if status is not GNUNET_OK
850  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
851  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
852  */
853 static void
854 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
855                       int status)
856 {
857   struct RunContext *rc = cls;
858   uint64_t event_mask;
859
860   if (status != GNUNET_OK)
861   {
862     switch (rc->state)
863     {
864     case RC_INIT:
865       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
866       return;
867     default:
868       rc->cproc = NULL;
869       shutdown_now (rc);      
870       return;
871     }
872   }
873   GNUNET_CONFIGURATION_destroy (rc->cfg);
874   rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
875   event_mask = rc->event_mask;
876   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
877   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
878   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
879   if (rc->topology < GNUNET_TESTBED_TOPOLOGY_NONE)
880     event_mask |= GNUNET_TESTBED_ET_CONNECT;
881   rc->c =
882       GNUNET_TESTBED_controller_connect (rc->cfg, rc->h, event_mask, &event_cb, rc);
883   if (0 < rc->num_hosts)
884   {
885     rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
886     return;
887   }
888   rc->state = RC_LINKED;
889   create_peers (rc);
890 }
891
892
893 /**
894  * Callback function invoked for each interface found.
895  *
896  * @param cls closure
897  * @param name name of the interface (can be NULL for unknown)
898  * @param isDefault is this presumably the default interface
899  * @param addr address of this interface (can be NULL for unknown or unassigned)
900  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
901  * @param netmask the network mask (can be NULL for unknown or unassigned))
902  * @param addrlen length of the address
903  * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort
904  */
905 static int
906 netint_proc (void *cls, const char *name,
907              int isDefault,
908              const struct sockaddr *addr,
909              const struct sockaddr *broadcast_addr,
910              const struct sockaddr *netmask,
911              socklen_t addrlen)
912 {
913    struct RunContext *rc = cls;
914    char hostip[NI_MAXHOST];
915    char *buf;
916
917    if (sizeof (struct sockaddr_in) != addrlen)
918      return GNUNET_OK;          /* Only consider IPv4 for now */
919    if (0 != getnameinfo(addr, addrlen,
920                         hostip, NI_MAXHOST,
921                         NULL, 0, NI_NUMERICHOST))
922      GNUNET_log_strerror(GNUNET_ERROR_TYPE_WARNING, "getnameinfo");
923    if (NULL == rc->trusted_ip)
924    {
925      rc->trusted_ip = GNUNET_strdup (hostip);
926      return GNUNET_YES;
927    }
928    (void) GNUNET_asprintf (&buf, "%s; %s", rc->trusted_ip, hostip);
929    GNUNET_free (rc->trusted_ip);
930    rc->trusted_ip = buf;
931    return GNUNET_YES;
932 }
933
934
935 /**
936  * Callbacks of this type are called by GNUNET_TESTBED_is_host_habitable to
937  * inform whether the given host is habitable or not. The Handle returned by
938  * GNUNET_TESTBED_is_host_habitable() is invalid after this callback is called
939  *
940  * @param cls NULL
941  * @param host the host whose status is being reported; will be NULL if the host
942  *          given to GNUNET_TESTBED_is_host_habitable() is NULL
943  * @param status GNUNET_YES if it is habitable; GNUNET_NO if not
944  */
945 static void 
946 host_habitable_cb (void *cls, const struct GNUNET_TESTBED_Host *host, int status)
947 {
948   struct RunContext *rc = cls;
949   unsigned int nhost;
950   
951   for (nhost = 0; nhost < rc->num_hosts; nhost++)
952   {
953     if (host == rc->hosts[nhost])
954       break;
955   }
956   GNUNET_assert (nhost != rc->num_hosts);
957   rc->hc_handles[nhost] = NULL;
958   if (GNUNET_NO == status)
959   {
960     if ((NULL != host) && (NULL != GNUNET_TESTBED_host_get_hostname (host)))
961       LOG (GNUNET_ERROR_TYPE_ERROR, _("Host %s cannot start testbed\n"),
962            GNUNET_TESTBED_host_get_hostname (host));
963     else
964       LOG (GNUNET_ERROR_TYPE_ERROR, _("Testbed cannot be started on localhost\n"));
965     shutdown_now (rc);
966     return;
967   }
968   rc->reg_hosts++;
969   if (rc->reg_hosts < rc->num_hosts)
970     return;
971   GNUNET_free (rc->hc_handles);
972   rc->hc_handles = NULL;
973   rc->h = rc->hosts[0];
974   rc->num_hosts--;
975   if (0 < rc->num_hosts)
976     rc->hosts = &rc->hosts[1];
977   else
978   {
979     GNUNET_free (rc->hosts);
980     rc->hosts = NULL;
981   }
982   GNUNET_OS_network_interfaces_list (netint_proc, rc);
983   if (NULL == rc->trusted_ip)
984     rc->trusted_ip = GNUNET_strdup ("127.0.0.1");
985   rc->cproc =
986       GNUNET_TESTBED_controller_start (rc->trusted_ip, rc->h, rc->cfg,
987                                        &controller_status_cb, rc);
988   GNUNET_free (rc->trusted_ip);
989   rc->trusted_ip = NULL;
990   if (NULL == rc->cproc)
991   {
992     LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot start the master controller"));
993     shutdown_now (rc);
994   }
995 }
996
997
998 /**
999  * Convenience method for running a testbed with
1000  * a single call.  Underlay and overlay topology
1001  * are configured using the "UNDERLAY" and "OVERLAY"
1002  * options in the "[testbed]" section of the configuration\
1003  * (with possible options given in "UNDERLAY_XXX" and/or
1004  * "OVERLAY_XXX").
1005  *
1006  * The testbed is to be terminated using a call to
1007  * "GNUNET_SCHEDULER_shutdown".
1008  *
1009  * @param host_filename name of the file with the 'hosts', NULL
1010  *        to run everything on 'localhost'
1011  * @param cfg configuration to use (for testbed, controller and peers)
1012  * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
1013  * @param event_mask bit mask with set of events to call 'cc' for;
1014  *                   or-ed values of "1LL" shifted by the
1015  *                   respective 'enum GNUNET_TESTBED_EventType'
1016  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
1017  * @param cc controller callback to invoke on events; This callback is called
1018  *          for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
1019  *          set in the event_mask as this is the only way get access to the
1020  *          handle of each peer
1021  * @param cc_cls closure for cc
1022  * @param test_master this callback will be called once the test is ready
1023  * @param test_master_cls closure for 'test_master'.
1024  */
1025 void
1026 GNUNET_TESTBED_run (const char *host_filename,
1027                     const struct GNUNET_CONFIGURATION_Handle *cfg,
1028                     unsigned int num_peers, uint64_t event_mask,
1029                     GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
1030                     GNUNET_TESTBED_TestMaster test_master,
1031                     void *test_master_cls)
1032 {
1033   struct RunContext *rc;
1034   char *topology;
1035   unsigned long long random_links;
1036   unsigned int hid;
1037   unsigned int nhost;
1038   
1039   GNUNET_assert (num_peers > 0);
1040   rc = GNUNET_malloc (sizeof (struct RunContext));
1041   if (NULL != host_filename)
1042   {
1043     rc->num_hosts =
1044         GNUNET_TESTBED_hosts_load_from_file (host_filename, &rc->hosts);
1045     if (0 == rc->num_hosts)
1046     {
1047       LOG (GNUNET_ERROR_TYPE_WARNING,
1048            _("No hosts loaded. Need at least one host\n"));
1049       goto error_cleanup;
1050     }
1051   }
1052   else
1053     rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
1054   rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
1055   rc->num_peers = num_peers;
1056   rc->event_mask = event_mask;
1057   rc->cc = cc;
1058   rc->cc_cls = cc_cls;
1059   rc->test_master = test_master;
1060   rc->test_master_cls = test_master_cls;
1061   rc->state = RC_INIT;
1062   rc->topology = GNUNET_TESTBED_TOPOLOGY_NONE;  
1063   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
1064                                                           "OVERLAY_TOPOLOGY",
1065                                                           &topology))
1066   {
1067     if (GNUNET_NO == GNUNET_TESTBED_topology_get_ (&rc->topology,
1068                                                     topology))
1069     {
1070       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1071                                  "testbed", "OVERLAY_TOPLOGY",
1072                                  _("Specified topology must be supported by testbed"));
1073     }
1074     GNUNET_free (topology);
1075   }
1076   switch (rc->topology)
1077   {
1078   case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
1079   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
1080   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
1081     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (rc->cfg, "testbed",
1082                                                             "OVERLAY_RANDOM_LINKS",
1083                                                             &random_links))
1084     {
1085       /* OVERLAY option RANDOM & SMALL_WORLD_RING requires OVERLAY_RANDOM_LINKS
1086          option to be set to the number of random links to be established  */
1087       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1088                                  "testbed", "OVERLAY_RANDOM_LINKS");
1089       goto error_cleanup;
1090     }
1091     if (random_links > UINT32_MAX)
1092     {
1093       GNUNET_break (0);       /* Too big number */
1094       goto error_cleanup;
1095     }
1096     rc->random_links = (unsigned int) random_links;
1097     break;
1098   case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
1099     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
1100                                                             "OVERLAY_TOPOLOGY_FILE",
1101                                                             &rc->topo_file))
1102     {
1103       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1104                                  "testbed", "OVERLAY_TOPOLOGY_FILE");
1105       goto error_cleanup;
1106     }
1107   default:   
1108     /* Warn if OVERLAY_RANDOM_LINKS is present that it will be ignored */
1109     if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (rc->cfg, "testbed",
1110                                                        "OVERLAY_RANDOM_LINKS"))
1111       LOG (GNUNET_ERROR_TYPE_WARNING,
1112            "Ignoring value of `OVERLAY_RANDOM_LINKS' in given configuration\n");
1113     break;
1114   }
1115   if (NULL != host_filename)
1116   {
1117     rc->hc_handles = GNUNET_malloc (sizeof (struct
1118                                             GNUNET_TESTBED_HostHabitableCheckHandle *) 
1119                                     * rc->num_hosts);
1120     for (nhost = 0; nhost < rc->num_hosts; nhost++) 
1121     {    
1122       if (NULL == (rc->hc_handles[nhost] = 
1123                    GNUNET_TESTBED_is_host_habitable (rc->hosts[nhost], rc->cfg,
1124                                                      &host_habitable_cb,
1125                                                      rc)))
1126       {
1127         GNUNET_break (0);
1128         for (nhost = 0; nhost < rc->num_hosts; nhost++)
1129           if (NULL != rc->hc_handles[nhost])
1130             GNUNET_TESTBED_is_host_habitable_cancel (rc->hc_handles[nhost]);
1131         GNUNET_free (rc->hc_handles);
1132         rc->hc_handles = NULL;
1133         goto error_cleanup;
1134       }
1135     }
1136   }
1137   else
1138     rc->cproc =
1139       GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, rc->cfg,
1140                                        &controller_status_cb, rc);
1141   rc->shutdown_run_task =
1142       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1143                                     &shutdown_run, rc);
1144   return;
1145
1146  error_cleanup:
1147   if (NULL != rc->h)
1148     GNUNET_TESTBED_host_destroy (rc->h);
1149   if (NULL != rc->hosts)
1150   {
1151     for (hid = 0; hid < rc->num_hosts; hid++)
1152       if (NULL != rc->hosts[hid])
1153         GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
1154     GNUNET_free (rc->hosts);
1155   }
1156   GNUNET_free (rc);
1157 }
1158
1159
1160 /* end of testbed_api_testbed.c */