- indent
[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 ==
587                                      rc->num_hosts) ? rc->h : rc->hosts[peer %
588                                                                         rc->num_hosts],
589                                     rc->cfg, 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, _("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, prof_time (rc));
723   if (GNUNET_TESTBED_TOPOLOGY_NONE != rc->topology)
724   {
725     if ((GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology) ||
726         (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology) ||
727         (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD == rc->topology))
728     {
729       rc->topology_operation =
730           GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
731                                                      rc->peers, &rc->num_oc,
732                                                      rc->topology,
733                                                      rc->random_links,
734                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
735     }
736     else if (GNUNET_TESTBED_TOPOLOGY_FROM_FILE == rc->topology)
737     {
738       GNUNET_assert (NULL != rc->topo_file);
739       rc->topology_operation =
740           GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
741                                                      rc->peers, &rc->num_oc,
742                                                      rc->topology,
743                                                      rc->topo_file,
744                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
745     }
746     else
747       rc->topology_operation =
748           GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
749                                                      rc->peers, &rc->num_oc,
750                                                      rc->topology,
751                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
752     if (NULL == rc->topology_operation)
753       LOG (GNUNET_ERROR_TYPE_WARNING,
754            "Not generating topology. Check number of peers\n");
755     else
756     {
757       DEBUG ("Creating overlay topology\n");
758       rc->pstart_time = GNUNET_TIME_absolute_get ();
759       return;
760     }
761   }
762   rc->state = RC_READY;
763   GNUNET_SCHEDULER_add_continuation (&call_master, rc,
764                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
765 }
766
767
768 /**
769  * Task to register all hosts available in the global host list
770  *
771  * @param cls the RunContext
772  * @param tc the scheduler task context
773  */
774 static void
775 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
776
777
778 /**
779  * Callback which will be called to after a host registration succeeded or failed
780  *
781  * @param cls the closure
782  * @param emsg the error message; NULL if host registration is successful
783  */
784 static void
785 host_registration_completion (void *cls, const char *emsg)
786 {
787   struct RunContext *rc = cls;
788
789   rc->reg_handle = NULL;
790   if (NULL != emsg)
791   {
792     LOG (GNUNET_ERROR_TYPE_WARNING,
793          _("Host registration failed for a host. Error: %s\n"), emsg);
794     shutdown_now (rc);
795     return;
796   }
797   rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
798 }
799
800
801 /**
802  * Task to register all hosts available in the global host list
803  *
804  * @param cls RunContext
805  * @param tc the scheduler task context
806  */
807 static void
808 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
809 {
810   struct RunContext *rc = cls;
811   struct DLLOperation *dll_op;
812   unsigned int slave;
813
814   rc->register_hosts_task = GNUNET_SCHEDULER_NO_TASK;
815   if (rc->reg_hosts == rc->num_hosts)
816   {
817     DEBUG ("All hosts successfully registered\n");
818     /* Start slaves */
819     for (slave = 0; slave < rc->num_hosts; slave++)
820     {
821       dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
822       dll_op->rc = rc;
823       dll_op->op =
824           GNUNET_TESTBED_controller_link (dll_op, rc->c, rc->hosts[slave],
825                                           rc->h, rc->cfg, GNUNET_YES);
826       GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
827                                         dll_op);
828     }
829     rc->reg_hosts = 0;
830     return;
831   }
832   rc->reg_handle =
833       GNUNET_TESTBED_register_host (rc->c, rc->hosts[rc->reg_hosts++],
834                                     host_registration_completion, rc);
835 }
836
837
838 /**
839  * Callback to signal successfull startup of the controller process
840  *
841  * @param cls the closure from GNUNET_TESTBED_controller_start()
842  * @param cfg the configuration with which the controller has been started;
843  *          NULL if status is not GNUNET_OK
844  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
845  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
846  */
847 static void
848 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
849                       int status)
850 {
851   struct RunContext *rc = cls;
852   uint64_t event_mask;
853
854   if (status != GNUNET_OK)
855   {
856     switch (rc->state)
857     {
858     case RC_INIT:
859       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
860       return;
861     default:
862       rc->cproc = NULL;
863       shutdown_now (rc);
864       return;
865     }
866   }
867   GNUNET_CONFIGURATION_destroy (rc->cfg);
868   rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
869   event_mask = rc->event_mask;
870   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
871   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
872   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
873   if (rc->topology < GNUNET_TESTBED_TOPOLOGY_NONE)
874     event_mask |= GNUNET_TESTBED_ET_CONNECT;
875   rc->c =
876       GNUNET_TESTBED_controller_connect (rc->cfg, rc->h, event_mask, &event_cb,
877                                          rc);
878   if (0 < rc->num_hosts)
879   {
880     rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
881     return;
882   }
883   rc->state = RC_LINKED;
884   create_peers (rc);
885 }
886
887
888 /**
889  * Callback function invoked for each interface found.
890  *
891  * @param cls closure
892  * @param name name of the interface (can be NULL for unknown)
893  * @param isDefault is this presumably the default interface
894  * @param addr address of this interface (can be NULL for unknown or unassigned)
895  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
896  * @param netmask the network mask (can be NULL for unknown or unassigned))
897  * @param addrlen length of the address
898  * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort
899  */
900 static int
901 netint_proc (void *cls, const char *name, int isDefault,
902              const struct sockaddr *addr, const struct sockaddr *broadcast_addr,
903              const struct sockaddr *netmask, socklen_t addrlen)
904 {
905   struct RunContext *rc = cls;
906   char hostip[NI_MAXHOST];
907   char *buf;
908
909   if (sizeof (struct sockaddr_in) != addrlen)
910     return GNUNET_OK;           /* Only consider IPv4 for now */
911   if (0 !=
912       getnameinfo (addr, addrlen, hostip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
913     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "getnameinfo");
914   if (NULL == rc->trusted_ip)
915   {
916     rc->trusted_ip = GNUNET_strdup (hostip);
917     return GNUNET_YES;
918   }
919   (void) GNUNET_asprintf (&buf, "%s; %s", rc->trusted_ip, hostip);
920   GNUNET_free (rc->trusted_ip);
921   rc->trusted_ip = buf;
922   return GNUNET_YES;
923 }
924
925
926 /**
927  * Callbacks of this type are called by GNUNET_TESTBED_is_host_habitable to
928  * inform whether the given host is habitable or not. The Handle returned by
929  * GNUNET_TESTBED_is_host_habitable() is invalid after this callback is called
930  *
931  * @param cls NULL
932  * @param host the host whose status is being reported; will be NULL if the host
933  *          given to GNUNET_TESTBED_is_host_habitable() is NULL
934  * @param status GNUNET_YES if it is habitable; GNUNET_NO if not
935  */
936 static void
937 host_habitable_cb (void *cls, const struct GNUNET_TESTBED_Host *host,
938                    int status)
939 {
940   struct RunContext *rc = cls;
941   unsigned int nhost;
942
943   for (nhost = 0; nhost < rc->num_hosts; nhost++)
944   {
945     if (host == rc->hosts[nhost])
946       break;
947   }
948   GNUNET_assert (nhost != rc->num_hosts);
949   rc->hc_handles[nhost] = NULL;
950   if (GNUNET_NO == status)
951   {
952     if ((NULL != host) && (NULL != GNUNET_TESTBED_host_get_hostname (host)))
953       LOG (GNUNET_ERROR_TYPE_ERROR, _("Host %s cannot start testbed\n"),
954            GNUNET_TESTBED_host_get_hostname (host));
955     else
956       LOG (GNUNET_ERROR_TYPE_ERROR,
957            _("Testbed cannot be started on localhost\n"));
958     shutdown_now (rc);
959     return;
960   }
961   rc->reg_hosts++;
962   if (rc->reg_hosts < rc->num_hosts)
963     return;
964   GNUNET_free (rc->hc_handles);
965   rc->hc_handles = NULL;
966   rc->h = rc->hosts[0];
967   rc->num_hosts--;
968   if (0 < rc->num_hosts)
969     rc->hosts = &rc->hosts[1];
970   else
971   {
972     GNUNET_free (rc->hosts);
973     rc->hosts = NULL;
974   }
975   GNUNET_OS_network_interfaces_list (netint_proc, rc);
976   if (NULL == rc->trusted_ip)
977     rc->trusted_ip = GNUNET_strdup ("127.0.0.1");
978   rc->cproc =
979       GNUNET_TESTBED_controller_start (rc->trusted_ip, rc->h, rc->cfg,
980                                        &controller_status_cb, rc);
981   GNUNET_free (rc->trusted_ip);
982   rc->trusted_ip = NULL;
983   if (NULL == rc->cproc)
984   {
985     LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot start the master controller"));
986     shutdown_now (rc);
987   }
988 }
989
990
991 /**
992  * Convenience method for running a testbed with
993  * a single call.  Underlay and overlay topology
994  * are configured using the "UNDERLAY" and "OVERLAY"
995  * options in the "[testbed]" section of the configuration\
996  * (with possible options given in "UNDERLAY_XXX" and/or
997  * "OVERLAY_XXX").
998  *
999  * The testbed is to be terminated using a call to
1000  * "GNUNET_SCHEDULER_shutdown".
1001  *
1002  * @param host_filename name of the file with the 'hosts', NULL
1003  *        to run everything on 'localhost'
1004  * @param cfg configuration to use (for testbed, controller and peers)
1005  * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
1006  * @param event_mask bit mask with set of events to call 'cc' for;
1007  *                   or-ed values of "1LL" shifted by the
1008  *                   respective 'enum GNUNET_TESTBED_EventType'
1009  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
1010  * @param cc controller callback to invoke on events; This callback is called
1011  *          for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
1012  *          set in the event_mask as this is the only way get access to the
1013  *          handle of each peer
1014  * @param cc_cls closure for cc
1015  * @param test_master this callback will be called once the test is ready
1016  * @param test_master_cls closure for 'test_master'.
1017  */
1018 void
1019 GNUNET_TESTBED_run (const char *host_filename,
1020                     const struct GNUNET_CONFIGURATION_Handle *cfg,
1021                     unsigned int num_peers, uint64_t event_mask,
1022                     GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
1023                     GNUNET_TESTBED_TestMaster test_master,
1024                     void *test_master_cls)
1025 {
1026   struct RunContext *rc;
1027   char *topology;
1028   unsigned long long random_links;
1029   unsigned int hid;
1030   unsigned int nhost;
1031
1032   GNUNET_assert (num_peers > 0);
1033   rc = GNUNET_malloc (sizeof (struct RunContext));
1034   if (NULL != host_filename)
1035   {
1036     rc->num_hosts =
1037         GNUNET_TESTBED_hosts_load_from_file (host_filename, &rc->hosts);
1038     if (0 == rc->num_hosts)
1039     {
1040       LOG (GNUNET_ERROR_TYPE_WARNING,
1041            _("No hosts loaded. Need at least one host\n"));
1042       goto error_cleanup;
1043     }
1044   }
1045   else
1046     rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
1047   rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
1048   rc->num_peers = num_peers;
1049   rc->event_mask = event_mask;
1050   rc->cc = cc;
1051   rc->cc_cls = cc_cls;
1052   rc->test_master = test_master;
1053   rc->test_master_cls = test_master_cls;
1054   rc->state = RC_INIT;
1055   rc->topology = GNUNET_TESTBED_TOPOLOGY_NONE;
1056   if (GNUNET_OK ==
1057       GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
1058                                              "OVERLAY_TOPOLOGY", &topology))
1059   {
1060     if (GNUNET_NO == GNUNET_TESTBED_topology_get_ (&rc->topology, topology))
1061     {
1062       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "testbed",
1063                                  "OVERLAY_TOPLOGY",
1064                                  _
1065                                  ("Specified topology must be supported by testbed"));
1066     }
1067     GNUNET_free (topology);
1068   }
1069   switch (rc->topology)
1070   {
1071   case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
1072   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
1073   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
1074     if (GNUNET_OK !=
1075         GNUNET_CONFIGURATION_get_value_number (rc->cfg, "testbed",
1076                                                "OVERLAY_RANDOM_LINKS",
1077                                                &random_links))
1078     {
1079       /* OVERLAY option RANDOM & SMALL_WORLD_RING requires OVERLAY_RANDOM_LINKS
1080        * option to be set to the number of random links to be established  */
1081       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "testbed",
1082                                  "OVERLAY_RANDOM_LINKS");
1083       goto error_cleanup;
1084     }
1085     if (random_links > UINT32_MAX)
1086     {
1087       GNUNET_break (0);         /* Too big number */
1088       goto error_cleanup;
1089     }
1090     rc->random_links = (unsigned int) random_links;
1091     break;
1092   case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
1093     if (GNUNET_OK !=
1094         GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
1095                                                "OVERLAY_TOPOLOGY_FILE",
1096                                                &rc->topo_file))
1097     {
1098       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "testbed",
1099                                  "OVERLAY_TOPOLOGY_FILE");
1100       goto error_cleanup;
1101     }
1102   default:
1103     /* Warn if OVERLAY_RANDOM_LINKS is present that it will be ignored */
1104     if (GNUNET_YES ==
1105         GNUNET_CONFIGURATION_have_value (rc->cfg, "testbed",
1106                                          "OVERLAY_RANDOM_LINKS"))
1107       LOG (GNUNET_ERROR_TYPE_WARNING,
1108            "Ignoring value of `OVERLAY_RANDOM_LINKS' in given configuration\n");
1109     break;
1110   }
1111   if (NULL != host_filename)
1112   {
1113     rc->hc_handles =
1114         GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HostHabitableCheckHandle *)
1115                        * rc->num_hosts);
1116     for (nhost = 0; nhost < rc->num_hosts; nhost++)
1117     {
1118       if (NULL ==
1119           (rc->hc_handles[nhost] =
1120            GNUNET_TESTBED_is_host_habitable (rc->hosts[nhost], rc->cfg,
1121                                              &host_habitable_cb, rc)))
1122       {
1123         GNUNET_break (0);
1124         for (nhost = 0; nhost < rc->num_hosts; nhost++)
1125           if (NULL != rc->hc_handles[nhost])
1126             GNUNET_TESTBED_is_host_habitable_cancel (rc->hc_handles[nhost]);
1127         GNUNET_free (rc->hc_handles);
1128         rc->hc_handles = NULL;
1129         goto error_cleanup;
1130       }
1131     }
1132   }
1133   else
1134     rc->cproc =
1135         GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, rc->cfg,
1136                                          &controller_status_cb, rc);
1137   rc->shutdown_run_task =
1138       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_run,
1139                                     rc);
1140   return;
1141
1142 error_cleanup:
1143   if (NULL != rc->h)
1144     GNUNET_TESTBED_host_destroy (rc->h);
1145   if (NULL != rc->hosts)
1146   {
1147     for (hid = 0; hid < rc->num_hosts; hid++)
1148       if (NULL != rc->hosts[hid])
1149         GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
1150     GNUNET_free (rc->hosts);
1151   }
1152   GNUNET_free (rc);
1153 }
1154
1155
1156 /* end of testbed_api_testbed.c */