- print summary of established links
[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     DEBUG ("Overlay topology generated in %s\n", prof_time (rc));
555     GNUNET_TESTBED_operation_done (rc->topology_operation);    
556     rc->topology_operation = NULL;
557   }
558   if (NULL != rc->test_master)
559     rc->test_master (rc->test_master_cls, rc->num_peers, rc->peers);
560 }
561
562
563 /**
564  * Function to create peers
565  *
566  * @param rc the RunContext
567  */
568 static void
569 create_peers (struct RunContext *rc)
570 {
571   struct DLLOperation *dll_op;
572   unsigned int peer;
573  
574   DEBUG ("Creating peers\n");
575   rc->pstart_time = GNUNET_TIME_absolute_get ();
576   rc->peers =
577       GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
578   GNUNET_assert (NULL != rc->c);
579   rc->peer_count = 0;
580   for (peer = 0; peer < rc->num_peers; peer++)
581   {
582     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
583     dll_op->rc = rc;
584     dll_op->op =
585         GNUNET_TESTBED_peer_create (rc->c, 
586                                     (0 == rc->num_hosts)
587                                     ? rc->h : rc->hosts[peer % rc->num_hosts],
588                                     rc->cfg,
589                                     peer_create_cb, dll_op);
590     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
591   }
592 }
593
594
595 /**
596  * Signature of the event handler function called by the
597  * respective event controller.
598  *
599  * @param cls closure
600  * @param event information about the event
601  */
602 static void
603 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
604 {
605   struct RunContext *rc = cls;
606   struct DLLOperation *dll_op;
607   unsigned int peer_id;
608
609   if (RC_INIT == rc->state)
610   {
611     switch (event->type)
612     {
613     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
614       dll_op = event->details.operation_finished.op_cls;
615       if (NULL != event->details.operation_finished.emsg)
616       {
617         LOG (GNUNET_ERROR_TYPE_ERROR,
618              _("Linking controllers failed. Exiting"));
619         shutdown_now (rc);
620       }
621       else
622         rc->reg_hosts++;
623       GNUNET_assert (event->details.operation_finished.operation == dll_op->op);
624       GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
625       GNUNET_TESTBED_operation_done (dll_op->op);
626       GNUNET_free (dll_op);
627       if (rc->reg_hosts == rc->num_hosts)
628       {
629         rc->state = RC_LINKED;
630         create_peers (rc);
631       }
632       return;
633     default:
634       GNUNET_break (0);
635       shutdown_now (rc);
636       return;
637     }
638   }
639   if (NULL != rc->topology_operation)
640   {
641     switch (event->type)
642     {
643     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
644     case GNUNET_TESTBED_ET_CONNECT:
645       rc->oc_count++;
646       break;
647     default:
648       GNUNET_break (0);
649       shutdown_now (rc);
650       return;
651     }
652     if (rc->oc_count == rc->num_oc)
653     {
654       rc->state = RC_READY;
655       GNUNET_SCHEDULER_add_continuation (&call_master, rc,
656                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
657     }
658     goto call_cc;
659   }
660   for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
661   {
662     if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
663         (event->details.operation_finished.operation == dll_op->op))
664       break;
665     if ((GNUNET_TESTBED_ET_PEER_STOP == event->type) &&
666         (event->details.peer_stop.peer == dll_op->cls))
667       break;
668   }
669   if (NULL == dll_op)
670     goto call_cc;
671   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
672   GNUNET_TESTBED_operation_done (dll_op->op);
673   GNUNET_free (dll_op);
674   rc->peer_count++;
675   if (rc->peer_count < rc->num_peers)
676     return;
677   switch (rc->state)
678   {
679   case RC_LINKED:
680   case RC_READY:
681     rc->state = RC_PEERS_STOPPED;
682     DEBUG ("Peers stopped in %s\n", prof_time (rc));
683     DEBUG ("Destroying peers\n");
684     rc->pstart_time = GNUNET_TIME_absolute_get ();
685     rc->peer_count = 0;
686     for (peer_id = 0; peer_id < rc->num_peers; peer_id++)
687     {
688       dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
689       dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer_id]);
690       GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
691                                         dll_op);
692     }
693     break;
694   case RC_PEERS_STOPPED:
695     rc->state = RC_PEERS_DESTROYED;
696     GNUNET_free (rc->peers);
697     rc->peers = NULL;
698     DEBUG ("Peers destroyed in %s\n", prof_time (rc));
699     GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
700     break;
701   default:
702     GNUNET_assert (0);
703   }
704   return;
705
706 call_cc:
707   if ((0 != (rc->event_mask & (1LL << event->type))) && (NULL != rc->cc))
708     rc->cc (rc->cc_cls, event);
709   if (GNUNET_TESTBED_ET_PEER_START != event->type)
710     return;
711   for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
712     if ((NULL != dll_op->cls) &&
713         (event->details.peer_start.peer == dll_op->cls))
714       break;
715   if (NULL == dll_op)           /* Not our operation */
716     return;
717   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
718   GNUNET_TESTBED_operation_done (dll_op->op);
719   GNUNET_free (dll_op);
720   rc->peer_count++;
721   if (rc->peer_count < rc->num_peers)
722     return;  
723   DEBUG ("%u peers started in %s\n", rc->num_peers,
724          prof_time (rc));
725   if (GNUNET_TESTBED_TOPOLOGY_NONE != rc->topology)
726   {    
727     if ( (GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology)
728          || (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology)
729          || (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD == rc->topology))
730     {
731       rc->topology_operation =
732           GNUNET_TESTBED_overlay_configure_topology (NULL,
733                                                      rc->num_peers,
734                                                      rc->peers,
735                                                      &rc->num_oc,
736                                                      rc->topology,
737                                                      rc->random_links,
738                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
739     }
740     else if (GNUNET_TESTBED_TOPOLOGY_FROM_FILE == rc->topology)
741     {
742       GNUNET_assert (NULL != rc->topo_file);
743       rc->topology_operation =
744           GNUNET_TESTBED_overlay_configure_topology (NULL,
745                                                      rc->num_peers,
746                                                      rc->peers,
747                                                      &rc->num_oc,
748                                                      rc->topology,
749                                                      rc->topo_file,
750                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
751     }
752     else
753       rc->topology_operation =
754           GNUNET_TESTBED_overlay_configure_topology (NULL,
755                                                      rc->num_peers,
756                                                      rc->peers,
757                                                      &rc->num_oc,
758                                                      rc->topology,
759                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
760     if (NULL == rc->topology_operation)
761       LOG (GNUNET_ERROR_TYPE_WARNING,
762            "Not generating topology. Check number of peers\n");
763     else
764     {
765       DEBUG ("Creating overlay topology\n");
766       rc->pstart_time = GNUNET_TIME_absolute_get ();    
767       return;
768     }
769   }
770   rc->state = RC_READY;
771   GNUNET_SCHEDULER_add_continuation (&call_master, rc,
772                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
773 }
774
775
776 /**
777  * Task to register all hosts available in the global host list
778  *
779  * @param cls the RunContext
780  * @param tc the scheduler task context
781  */
782 static void
783 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
784
785
786 /**
787  * Callback which will be called to after a host registration succeeded or failed
788  *
789  * @param cls the closure
790  * @param emsg the error message; NULL if host registration is successful
791  */
792 static void
793 host_registration_completion (void *cls, const char *emsg)
794 {
795   struct RunContext *rc = cls;
796
797   rc->reg_handle = NULL;
798   if (NULL != emsg)
799   {
800     LOG (GNUNET_ERROR_TYPE_WARNING,
801          _("Host registration failed for a host. Error: %s\n"), emsg);
802     shutdown_now (rc);
803     return;
804   }
805   rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
806 }
807
808
809 /**
810  * Task to register all hosts available in the global host list
811  *
812  * @param cls RunContext
813  * @param tc the scheduler task context
814  */
815 static void
816 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
817 {
818   struct RunContext *rc = cls;
819   struct DLLOperation *dll_op;
820   unsigned int slave;
821
822   rc->register_hosts_task = GNUNET_SCHEDULER_NO_TASK;
823   if (rc->reg_hosts == rc->num_hosts)
824   {
825     DEBUG ("All hosts successfully registered\n");
826     /* Start slaves */
827     for (slave = 0; slave < rc->num_hosts; slave++)
828     {
829       dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
830       dll_op->rc = rc;
831       dll_op->op = GNUNET_TESTBED_controller_link (dll_op,
832                                                    rc->c,
833                                                    rc->hosts[slave],
834                                                    rc->h,
835                                                    rc->cfg,
836                                                    GNUNET_YES);
837       GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
838     }
839     rc->reg_hosts = 0;
840     return;
841   }
842   rc->reg_handle = GNUNET_TESTBED_register_host (rc->c,
843                                                  rc->hosts[rc->reg_hosts++],
844                                                  host_registration_completion,
845                                                  rc);
846 }
847
848
849 /**
850  * Callback to signal successfull startup of the controller process
851  *
852  * @param cls the closure from GNUNET_TESTBED_controller_start()
853  * @param cfg the configuration with which the controller has been started;
854  *          NULL if status is not GNUNET_OK
855  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
856  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
857  */
858 static void
859 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
860                       int status)
861 {
862   struct RunContext *rc = cls;
863   uint64_t event_mask;
864
865   if (status != GNUNET_OK)
866   {
867     switch (rc->state)
868     {
869     case RC_INIT:
870       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
871       return;
872     default:
873       rc->cproc = NULL;
874       shutdown_now (rc);      
875       return;
876     }
877   }
878   GNUNET_CONFIGURATION_destroy (rc->cfg);
879   rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
880   event_mask = rc->event_mask;
881   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
882   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
883   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
884   if (rc->topology < GNUNET_TESTBED_TOPOLOGY_NONE)
885     event_mask |= GNUNET_TESTBED_ET_CONNECT;
886   rc->c =
887       GNUNET_TESTBED_controller_connect (rc->cfg, rc->h, event_mask, &event_cb, rc);
888   if (0 < rc->num_hosts)
889   {
890     rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
891     return;
892   }
893   rc->state = RC_LINKED;
894   create_peers (rc);
895 }
896
897
898 /**
899  * Callback function invoked for each interface found.
900  *
901  * @param cls closure
902  * @param name name of the interface (can be NULL for unknown)
903  * @param isDefault is this presumably the default interface
904  * @param addr address of this interface (can be NULL for unknown or unassigned)
905  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
906  * @param netmask the network mask (can be NULL for unknown or unassigned))
907  * @param addrlen length of the address
908  * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort
909  */
910 static int
911 netint_proc (void *cls, const char *name,
912              int isDefault,
913              const struct sockaddr *addr,
914              const struct sockaddr *broadcast_addr,
915              const struct sockaddr *netmask,
916              socklen_t addrlen)
917 {
918    struct RunContext *rc = cls;
919    char hostip[NI_MAXHOST];
920    char *buf;
921
922    if (sizeof (struct sockaddr_in) != addrlen)
923      return GNUNET_OK;          /* Only consider IPv4 for now */
924    if (0 != getnameinfo(addr, addrlen,
925                         hostip, NI_MAXHOST,
926                         NULL, 0, NI_NUMERICHOST))
927      GNUNET_log_strerror(GNUNET_ERROR_TYPE_WARNING, "getnameinfo");
928    if (NULL == rc->trusted_ip)
929    {
930      rc->trusted_ip = GNUNET_strdup (hostip);
931      return GNUNET_YES;
932    }
933    (void) GNUNET_asprintf (&buf, "%s; %s", rc->trusted_ip, hostip);
934    GNUNET_free (rc->trusted_ip);
935    rc->trusted_ip = buf;
936    return GNUNET_YES;
937 }
938
939
940 /**
941  * Callbacks of this type are called by GNUNET_TESTBED_is_host_habitable to
942  * inform whether the given host is habitable or not. The Handle returned by
943  * GNUNET_TESTBED_is_host_habitable() is invalid after this callback is called
944  *
945  * @param cls NULL
946  * @param host the host whose status is being reported; will be NULL if the host
947  *          given to GNUNET_TESTBED_is_host_habitable() is NULL
948  * @param status GNUNET_YES if it is habitable; GNUNET_NO if not
949  */
950 static void 
951 host_habitable_cb (void *cls, const struct GNUNET_TESTBED_Host *host, int status)
952 {
953   struct RunContext *rc = cls;
954   unsigned int nhost;
955   
956   for (nhost = 0; nhost < rc->num_hosts; nhost++)
957   {
958     if (host == rc->hosts[nhost])
959       break;
960   }
961   GNUNET_assert (nhost != rc->num_hosts);
962   rc->hc_handles[nhost] = NULL;
963   if (GNUNET_NO == status)
964   {
965     if ((NULL != host) && (NULL != GNUNET_TESTBED_host_get_hostname (host)))
966       LOG (GNUNET_ERROR_TYPE_ERROR, _("Host %s cannot start testbed\n"),
967            GNUNET_TESTBED_host_get_hostname (host));
968     else
969       LOG (GNUNET_ERROR_TYPE_ERROR, _("Testbed cannot be started on localhost\n"));
970     shutdown_now (rc);
971     return;
972   }
973   rc->reg_hosts++;
974   if (rc->reg_hosts < rc->num_hosts)
975     return;
976   GNUNET_free (rc->hc_handles);
977   rc->hc_handles = NULL;
978   rc->h = rc->hosts[0];
979   rc->num_hosts--;
980   if (0 < rc->num_hosts)
981     rc->hosts = &rc->hosts[1];
982   else
983   {
984     GNUNET_free (rc->hosts);
985     rc->hosts = NULL;
986   }
987   GNUNET_OS_network_interfaces_list (netint_proc, rc);
988   if (NULL == rc->trusted_ip)
989     rc->trusted_ip = GNUNET_strdup ("127.0.0.1");
990   rc->cproc =
991       GNUNET_TESTBED_controller_start (rc->trusted_ip, rc->h, rc->cfg,
992                                        &controller_status_cb, rc);
993   GNUNET_free (rc->trusted_ip);
994   rc->trusted_ip = NULL;
995   if (NULL == rc->cproc)
996   {
997     LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot start the master controller"));
998     shutdown_now (rc);
999   }
1000 }
1001
1002
1003 /**
1004  * Convenience method for running a testbed with
1005  * a single call.  Underlay and overlay topology
1006  * are configured using the "UNDERLAY" and "OVERLAY"
1007  * options in the "[testbed]" section of the configuration\
1008  * (with possible options given in "UNDERLAY_XXX" and/or
1009  * "OVERLAY_XXX").
1010  *
1011  * The testbed is to be terminated using a call to
1012  * "GNUNET_SCHEDULER_shutdown".
1013  *
1014  * @param host_filename name of the file with the 'hosts', NULL
1015  *        to run everything on 'localhost'
1016  * @param cfg configuration to use (for testbed, controller and peers)
1017  * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
1018  * @param event_mask bit mask with set of events to call 'cc' for;
1019  *                   or-ed values of "1LL" shifted by the
1020  *                   respective 'enum GNUNET_TESTBED_EventType'
1021  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
1022  * @param cc controller callback to invoke on events; This callback is called
1023  *          for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
1024  *          set in the event_mask as this is the only way get access to the
1025  *          handle of each peer
1026  * @param cc_cls closure for cc
1027  * @param test_master this callback will be called once the test is ready
1028  * @param test_master_cls closure for 'test_master'.
1029  */
1030 void
1031 GNUNET_TESTBED_run (const char *host_filename,
1032                     const struct GNUNET_CONFIGURATION_Handle *cfg,
1033                     unsigned int num_peers, uint64_t event_mask,
1034                     GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
1035                     GNUNET_TESTBED_TestMaster test_master,
1036                     void *test_master_cls)
1037 {
1038   struct RunContext *rc;
1039   char *topology;
1040   unsigned long long random_links;
1041   unsigned int hid;
1042   unsigned int nhost;
1043   
1044   GNUNET_assert (num_peers > 0);
1045   rc = GNUNET_malloc (sizeof (struct RunContext));
1046   if (NULL != host_filename)
1047   {
1048     rc->num_hosts =
1049         GNUNET_TESTBED_hosts_load_from_file (host_filename, &rc->hosts);
1050     if (0 == rc->num_hosts)
1051     {
1052       LOG (GNUNET_ERROR_TYPE_WARNING,
1053            _("No hosts loaded. Need at least one host\n"));
1054       goto error_cleanup;
1055     }
1056   }
1057   else
1058     rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
1059   rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
1060   rc->num_peers = num_peers;
1061   rc->event_mask = event_mask;
1062   rc->cc = cc;
1063   rc->cc_cls = cc_cls;
1064   rc->test_master = test_master;
1065   rc->test_master_cls = test_master_cls;
1066   rc->state = RC_INIT;
1067   rc->topology = GNUNET_TESTBED_TOPOLOGY_NONE;  
1068   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
1069                                                           "OVERLAY_TOPOLOGY",
1070                                                           &topology))
1071   {
1072     if (GNUNET_NO == GNUNET_TESTBED_topology_get_ (&rc->topology,
1073                                                     topology))
1074     {
1075       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1076                                  "testbed", "OVERLAY_TOPLOGY",
1077                                  _("Specified topology must be supported by testbed"));
1078     }
1079     GNUNET_free (topology);
1080   }
1081   switch (rc->topology)
1082   {
1083   case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
1084   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
1085   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
1086     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (rc->cfg, "testbed",
1087                                                             "OVERLAY_RANDOM_LINKS",
1088                                                             &random_links))
1089     {
1090       /* OVERLAY option RANDOM & SMALL_WORLD_RING requires OVERLAY_RANDOM_LINKS
1091          option to be set to the number of random links to be established  */
1092       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1093                                  "testbed", "OVERLAY_RANDOM_LINKS");
1094       goto error_cleanup;
1095     }
1096     if (random_links > UINT32_MAX)
1097     {
1098       GNUNET_break (0);       /* Too big number */
1099       goto error_cleanup;
1100     }
1101     rc->random_links = (unsigned int) random_links;
1102     break;
1103   case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
1104     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
1105                                                             "OVERLAY_TOPOLOGY_FILE",
1106                                                             &rc->topo_file))
1107     {
1108       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1109                                  "testbed", "OVERLAY_TOPOLOGY_FILE");
1110       goto error_cleanup;
1111     }
1112   default:   
1113     /* Warn if OVERLAY_RANDOM_LINKS is present that it will be ignored */
1114     if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (rc->cfg, "testbed",
1115                                                        "OVERLAY_RANDOM_LINKS"))
1116       LOG (GNUNET_ERROR_TYPE_WARNING,
1117            "Ignoring value of `OVERLAY_RANDOM_LINKS' in given configuration\n");
1118     break;
1119   }
1120   if (NULL != host_filename)
1121   {
1122     rc->hc_handles = GNUNET_malloc (sizeof (struct
1123                                             GNUNET_TESTBED_HostHabitableCheckHandle *) 
1124                                     * rc->num_hosts);
1125     for (nhost = 0; nhost < rc->num_hosts; nhost++) 
1126     {    
1127       if (NULL == (rc->hc_handles[nhost] = 
1128                    GNUNET_TESTBED_is_host_habitable (rc->hosts[nhost], rc->cfg,
1129                                                      &host_habitable_cb,
1130                                                      rc)))
1131       {
1132         GNUNET_break (0);
1133         for (nhost = 0; nhost < rc->num_hosts; nhost++)
1134           if (NULL != rc->hc_handles[nhost])
1135             GNUNET_TESTBED_is_host_habitable_cancel (rc->hc_handles[nhost]);
1136         GNUNET_free (rc->hc_handles);
1137         rc->hc_handles = NULL;
1138         goto error_cleanup;
1139       }
1140     }
1141   }
1142   else
1143     rc->cproc =
1144       GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, rc->cfg,
1145                                        &controller_status_cb, rc);
1146   rc->shutdown_run_task =
1147       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1148                                     &shutdown_run, rc);
1149   return;
1150
1151  error_cleanup:
1152   if (NULL != rc->h)
1153     GNUNET_TESTBED_host_destroy (rc->h);
1154   if (NULL != rc->hosts)
1155   {
1156     for (hid = 0; hid < rc->num_hosts; hid++)
1157       if (NULL != rc->hosts[hid])
1158         GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
1159     GNUNET_free (rc->hosts);
1160   }
1161   GNUNET_free (rc);
1162 }
1163
1164
1165 /* end of testbed_api_testbed.c */