- test config fixes for adaptive overlay connects
[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_testbed_service.h"
30 #include "testbed_api_peers.h"
31 #include "testbed_api_hosts.h"
32
33 /**
34  * Generic loggins shorthand
35  */
36 #define LOG(kind,...)                                           \
37   GNUNET_log_from (kind, "testbed-api-testbed", __VA_ARGS__)
38
39 /**
40  * Opaque handle to an abstract operation to be executed by the testing framework.
41  */
42 struct GNUNET_TESTBED_Testbed
43 {
44   /**
45    * The array of hosts
46    */
47   struct GNUNET_TESTBED_Host **hosts;
48
49   /**
50    * The number of hosts in the hosts array
51    */
52   unsigned int num_hosts;
53
54   /**
55    * The controller handle
56    */
57   struct GNUNET_TESTBED_Controller *c;
58 };
59
60
61 /**
62  * DLL of operations
63  */
64 struct DLLOperation
65 {
66   /**
67    * The testbed operation handle
68    */
69   struct GNUNET_TESTBED_Operation *op;
70
71   /**
72    * Context information for GNUNET_TESTBED_run()
73    */
74   struct RunContext *rc;
75
76   /**
77    * Closure
78    */
79   void *cls;
80
81   /**
82    * The next pointer for DLL
83    */
84   struct DLLOperation *next;
85
86   /**
87    * The prev pointer for DLL
88    */
89   struct DLLOperation *prev;
90 };
91
92
93 /**
94  * States of RunContext
95  */
96 enum State
97 {
98   /**
99    * Initial state
100    */
101   RC_INIT = 0,
102
103   /**
104    * The testbed run is ready and the master callback can be called now. At this
105    * time the peers are all started and if a topology is provided in the
106    * configuration the topology would have been attempted
107    */
108   RC_READY,
109
110   /**
111    * Peers are stopped
112    */
113   RC_PEERS_STOPPED,
114
115   /**
116    * Peers are destroyed
117    */
118   RC_PEERS_DESTROYED
119 };
120
121
122 /**
123  * Testbed Run Handle
124  */
125 struct RunContext
126 {
127   /**
128    * The controller handle
129    */
130   struct GNUNET_TESTBED_Controller *c;
131
132   /**
133    * Handle to the host on which the controller runs
134    */
135   struct GNUNET_TESTBED_Host *h;
136
137   /**
138    * The handle to the controller process
139    */
140   struct GNUNET_TESTBED_ControllerProc *cproc;
141
142   /**
143    * The callback to use as controller callback
144    */
145   GNUNET_TESTBED_ControllerCallback cc;
146
147   /**
148    * The pointer to the controller callback
149    */
150   void *cc_cls;
151
152   /**
153    * Master task to call when testbed initialization is done
154    */
155   GNUNET_SCHEDULER_Task master;
156
157   /**
158    * The closure for the master task
159    */
160   void *master_cls;
161
162   /**
163    * The head element of DLL operations
164    */
165   struct DLLOperation *dll_op_head;
166
167   /**
168    * The tail element of DLL operations
169    */
170   struct DLLOperation *dll_op_tail;
171
172   /**
173    * Array of peers which we create
174    */
175   struct GNUNET_TESTBED_Peer **peers;
176
177   /**
178    * The topology generation operation. Will be null if no topology is set in
179    * the configuration
180    */
181   struct GNUNET_TESTBED_Operation *topology_operation;
182
183   /**
184    * The event mask for the controller
185    */
186   uint64_t event_mask;
187
188   /**
189    * State of this context
190    */
191   enum State state;
192
193   /**
194    * The topology which has to be achieved with the peers started in this context
195    */
196   enum GNUNET_TESTBED_TopologyOption topology;
197
198   /**
199    * Current peer count for an operation; Set this to 0 and increment for each
200    * successful operation on a peer
201    */
202   unsigned int peer_count;
203
204   /**
205    * number of peers to start
206    */
207   unsigned int num_peers;
208
209   /**
210    * counter to count overlay connect attempts. This counter includes both
211    * successful and failed overlay connects
212    */
213   unsigned int oc_count;
214
215   /**
216    * Expected overlay connects. Should be zero if no topology is relavant
217    */
218   unsigned int num_oc;
219   
220 };
221
222
223 /**
224  * Task for starting peers
225  *
226  * @param cls the RunHandle
227  * @param tc the task context from scheduler
228  */
229 static void
230 start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
231 {
232   struct RunContext *rc = cls;
233   struct DLLOperation *dll_op;
234   unsigned int peer;
235
236   LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting Peers\n");
237   for (peer = 0; peer < rc->num_peers; peer++)
238   {
239     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
240     dll_op->op = GNUNET_TESTBED_peer_start (NULL, rc->peers[peer], NULL, NULL);
241     dll_op->cls = rc->peers[peer];
242     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
243   }
244   rc->peer_count = 0;
245 }
246
247
248 /**
249  * Functions of this signature are called when a peer has been successfully
250  * created
251  *
252  * @param cls the closure from GNUNET_TESTBED_peer_create()
253  * @param peer the handle for the created peer; NULL on any error during
254  *          creation
255  * @param emsg NULL if peer is not NULL; else MAY contain the error description
256  */
257 static void
258 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
259 {
260   struct DLLOperation *dll_op = cls;
261   struct RunContext *rc;
262
263   GNUNET_assert (NULL != dll_op);
264   rc = dll_op->rc;
265   GNUNET_assert (NULL != rc);
266   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
267   GNUNET_TESTBED_operation_done (dll_op->op);
268   GNUNET_free (dll_op);
269   if (NULL == peer)
270   {
271     if (NULL != emsg)
272       LOG (GNUNET_ERROR_TYPE_WARNING, "Error while creating a peer: %s\n",
273            emsg);
274     /* FIXME: GNUNET_TESTBED_shutdown_run()? */
275     return;
276   }
277   rc->peers[rc->peer_count] = peer;
278   rc->peer_count++;
279   if (rc->peer_count < rc->num_peers)
280     return;
281   LOG (GNUNET_ERROR_TYPE_DEBUG, "Required peers created successfully\n");
282   GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
283 }
284
285
286 /**
287  * Assuming all peers have been destroyed cleanup run handle
288  *
289  * @param cls the run handle
290  * @param tc the task context from scheduler
291  */
292 static void
293 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
294 {
295   struct RunContext *rc = cls;
296   struct DLLOperation *dll_op;
297
298   GNUNET_assert (NULL == rc->peers);
299   GNUNET_assert (RC_PEERS_DESTROYED == rc->state);
300   if (NULL != rc->c)
301     GNUNET_TESTBED_controller_disconnect (rc->c);
302   if (NULL != rc->cproc)
303     GNUNET_TESTBED_controller_stop (rc->cproc);
304   if (NULL != rc->h)
305     GNUNET_TESTBED_host_destroy (rc->h);
306   if (NULL != rc->dll_op_head)
307   {
308     LOG (GNUNET_ERROR_TYPE_WARNING,
309          _("Some operations are still pending. Cancelling them\n"));
310     while (NULL != (dll_op = rc->dll_op_head))
311     {
312       GNUNET_TESTBED_operation_done (dll_op->op);
313       GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
314       GNUNET_free (dll_op);
315     }
316   }
317   GNUNET_free (rc);
318 }
319
320
321 /**
322  * Task to call master task
323  *
324  * @param cls the run context
325  * @param tc the task context
326  */
327 static void
328 call_master (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
329 {
330   struct RunContext *rc = cls;
331   
332   if (NULL != rc->topology_operation)
333   {
334     GNUNET_TESTBED_operation_done (rc->topology_operation);
335     rc->topology_operation = NULL;
336   }
337   if (NULL != rc->master)
338     GNUNET_SCHEDULER_add_continuation (rc->master, rc->master_cls,
339                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
340 }
341
342
343 /**
344  * Signature of the event handler function called by the
345  * respective event controller.
346  *
347  * @param cls closure
348  * @param event information about the event
349  */
350 static void
351 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
352 {
353   struct RunContext *rc = cls;
354   struct DLLOperation *dll_op;
355   unsigned int peer_id;
356
357   if (NULL != rc->topology_operation)
358   {
359     switch (event->type)
360     {
361     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
362     case GNUNET_TESTBED_ET_CONNECT:
363       rc->oc_count++;
364       break;
365     default:
366       GNUNET_assert (0);
367     }
368     if (rc->oc_count == rc->num_oc)
369     {
370       rc->state = RC_READY;
371       GNUNET_SCHEDULER_add_continuation (&call_master, rc,
372                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
373     }
374     return;
375   }
376   if ((RC_INIT != rc->state) &&
377       ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) ||
378        (GNUNET_TESTBED_ET_PEER_STOP == event->type)))
379   {
380     for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
381     {
382       if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
383           (event->details.operation_finished.operation == dll_op->op))
384         break;
385       if ((GNUNET_TESTBED_ET_PEER_STOP == event->type) &&
386           (event->details.peer_stop.peer == dll_op->cls))
387         break;
388     }
389     if (NULL == dll_op)
390       goto call_cc;
391     GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
392     GNUNET_TESTBED_operation_done (dll_op->op);
393     GNUNET_free (dll_op);
394     rc->peer_count++;
395     if (rc->peer_count < rc->num_peers)
396       return;
397     switch (rc->state)
398     {
399     case RC_READY:
400       rc->state = RC_PEERS_STOPPED;
401       rc->peer_count = 0;
402       for (peer_id = 0; peer_id < rc->num_peers; peer_id++)
403       {
404         dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
405         dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer_id]);
406         GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
407                                           dll_op);
408       }
409       break;
410     case RC_PEERS_STOPPED:
411       rc->state = RC_PEERS_DESTROYED;
412       GNUNET_free (rc->peers);
413       rc->peers = NULL;
414       LOG (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully destroyed\n");
415       GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
416       break;
417     default:
418       GNUNET_assert (0);
419     }
420     return;
421   }
422
423 call_cc:
424   if ((0 != (rc->event_mask && (1LL << event->type))) && (NULL != rc->cc))
425     rc->cc (rc->cc_cls, event);
426   if (GNUNET_TESTBED_ET_PEER_START != event->type)
427     return;
428   for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
429     if ((NULL != dll_op->cls) &&
430         (event->details.peer_start.peer == dll_op->cls))
431       break;
432   GNUNET_assert (NULL != dll_op);
433   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
434   GNUNET_TESTBED_operation_done (dll_op->op);
435   GNUNET_free (dll_op);
436   rc->peer_count++;
437   if (rc->peer_count < rc->num_peers)
438     return;
439   LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers started successfully\n");
440   if (GNUNET_TESTBED_TOPOLOGY_NONE != rc->topology)
441   {
442     if ( (GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology)
443          || (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology))
444       rc->topology_operation =
445           GNUNET_TESTBED_overlay_configure_topology (NULL,
446                                                      rc->num_peers,
447                                                      rc->peers,
448                                                      rc->topology,
449                                                      (GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI
450                                                       == rc->topology) ?
451                                                      rc->num_oc : 
452                                                      (rc->num_oc - rc->num_peers),
453                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
454     else
455       rc->topology_operation =
456           GNUNET_TESTBED_overlay_configure_topology (NULL,
457                                                      rc->num_peers,
458                                                      rc->peers,
459                                                      rc->topology,
460                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
461     if (NULL == rc->topology_operation)
462       LOG (GNUNET_ERROR_TYPE_WARNING,
463            "Not generating topology. Check number of peers\n");
464     else
465       return;
466   }
467   rc->state = RC_READY;
468   GNUNET_SCHEDULER_add_continuation (&call_master, rc,
469                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
470 }
471
472
473
474 /**
475  * Callback to signal successfull startup of the controller process
476  *
477  * @param cls the closure from GNUNET_TESTBED_controller_start()
478  * @param cfg the configuration with which the controller has been started;
479  *          NULL if status is not GNUNET_OK
480  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
481  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
482  */
483 static void
484 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
485                       int status)
486 {
487   struct RunContext *rc = cls;
488   struct DLLOperation *dll_op;
489   uint64_t event_mask;
490   unsigned int peer;
491
492   if (status != GNUNET_OK)
493   {
494     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
495     return;
496   }
497   event_mask = rc->event_mask;
498   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
499   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
500   if (rc->topology < GNUNET_TESTBED_TOPOLOGY_NONE)
501     event_mask |= GNUNET_TESTBED_ET_CONNECT;
502   rc->c =
503       GNUNET_TESTBED_controller_connect (cfg, rc->h, event_mask, &event_cb, rc);
504   rc->peers =
505       GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
506   GNUNET_assert (NULL != rc->c);
507   rc->peer_count = 0;
508   for (peer = 0; peer < rc->num_peers; peer++)
509   {
510     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
511     dll_op->rc = rc;
512     dll_op->op =
513         GNUNET_TESTBED_peer_create (rc->c, rc->h, cfg, peer_create_cb, dll_op);
514     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
515   }
516 }
517
518
519 /**
520  * Stops the testbed run and releases any used resources
521  *
522  * @param cls the tesbed run handle
523  * @param tc the task context from scheduler
524  */
525 static void
526 shutdown_run_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
527 {
528   struct RunContext *rc = cls;
529   struct DLLOperation *dll_op;
530   unsigned int peer;
531
532   if (NULL != rc->c)
533   {
534     if (NULL != rc->peers)
535     {
536       if (NULL != rc->topology_operation)
537       {
538         GNUNET_TESTBED_operation_done (rc->topology_operation);
539         rc->topology_operation = NULL;
540       }
541       if (RC_INIT == rc->state)
542         rc->state = RC_READY;   /* Even though we haven't called the master callback */
543       rc->peer_count = 0;
544       /* Check if some peers are stopped */
545       for (peer = 0; peer < rc->num_peers; peer++)
546       {
547         if (PS_STOPPED != rc->peers[peer]->state)
548           break;
549       }
550       if (peer == rc->num_peers)
551       {
552         /* All peers are stopped */
553         rc->state = RC_PEERS_STOPPED;
554         for (peer = 0; peer < rc->num_peers; peer++)
555         {
556           dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
557           dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer]);
558           GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
559                                             dll_op);
560         }
561         return;
562       }
563       /* Some peers are stopped */
564       for (peer = 0; peer < rc->num_peers; peer++)
565       {
566         if (PS_STARTED != rc->peers[peer]->state)
567         {
568           rc->peer_count++;
569           continue;
570         }
571         dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
572         dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer], NULL, NULL);
573         dll_op->cls = rc->peers[peer];
574         GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
575                                           dll_op);
576       }
577       if (rc->peer_count != rc->num_peers)
578         return;
579     }
580   }
581   rc->state = RC_PEERS_DESTROYED;       /* No peers are present so we consider the
582                                          * state where all peers are destroyed  */
583   GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
584 }
585
586
587 /**
588  * Convenience method for running a testbed with
589  * a single call.  Underlay and overlay topology
590  * are configured using the "UNDERLAY" and "OVERLAY"
591  * options in the "[testbed]" section of the configuration\
592  * (with possible options given in "UNDERLAY_XXX" and/or
593  * "OVERLAY_XXX").
594  *
595  * The testbed is to be terminated using a call to
596  * "GNUNET_SCHEDULER_shutdown".
597  *
598  * @param host_filename name of the file with the 'hosts', NULL
599  *        to run everything on 'localhost'
600  * @param cfg configuration to use (for testbed, controller and peers)
601  * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
602  * @param event_mask bit mask with set of events to call 'cc' for;
603  *                   or-ed values of "1LL" shifted by the
604  *                   respective 'enum GNUNET_TESTBED_EventType'
605  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
606  * @param cc controller callback to invoke on events; This callback is called
607  *          for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
608  *          set in the event_mask as this is the only way get access to the
609  *          handle of each peer
610  * @param cc_cls closure for cc
611  * @param master task to run once the testbed is ready
612  * @param master_cls
613  */
614 void
615 GNUNET_TESTBED_run (const char *host_filename,
616                     const struct GNUNET_CONFIGURATION_Handle *cfg,
617                     unsigned int num_peers, uint64_t event_mask,
618                     GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
619                     GNUNET_SCHEDULER_Task master, void *master_cls)
620 {
621   struct RunContext *rc;
622   char *topology;
623   unsigned long long random_links;
624
625   GNUNET_break (NULL == host_filename); /* Currently we do not support host
626                                          * files */
627   GNUNET_assert (NULL != cc);
628   GNUNET_assert (num_peers > 0);
629   host_filename = NULL;
630   rc = GNUNET_malloc (sizeof (struct RunContext));
631   rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
632   GNUNET_assert (NULL != rc->h);
633   rc->cproc =
634       GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, cfg,
635                                        &controller_status_cb, rc);
636   GNUNET_assert (NULL != rc->cproc);
637   rc->num_peers = num_peers;
638   rc->event_mask = event_mask;
639   rc->event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
640   rc->cc = cc;
641   rc->cc_cls = cc_cls;
642   rc->master = master;
643   rc->master_cls = master_cls;
644   rc->state = RC_INIT;
645   rc->topology = GNUNET_TESTBED_TOPOLOGY_NONE;
646   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
647                                                           "OVERLAY_TOPOLOGY",
648                                                           &topology))
649   {
650     if (0 == strcasecmp (topology, "RANDOM"))
651     {
652       rc->topology = GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI;      
653     }
654     else if (0 == strcasecmp (topology, "SMALL_WORLD_RING"))
655     {
656       rc->topology = GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING;
657     }
658     else if (0 == strcasecmp (topology, "CLIQUE"))
659     {
660       rc->topology = GNUNET_TESTBED_TOPOLOGY_CLIQUE;
661       rc->num_oc = num_peers * (num_peers - 1);
662     }
663     else if (0 == strcasecmp (topology, "LINE"))
664     {
665       rc->topology = GNUNET_TESTBED_TOPOLOGY_LINE;
666       rc->num_oc = num_peers - 1;
667     }
668     else if (0 == strcasecmp (topology, "RING"))
669     {
670       rc->topology = GNUNET_TESTBED_TOPOLOGY_RING;
671       rc->num_oc = num_peers;
672     }
673     else
674       LOG (GNUNET_ERROR_TYPE_WARNING,
675            "Unknown topology %s given in configuration\n", topology);
676     GNUNET_free (topology);
677   }
678   if ( (GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology)
679        || (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology))
680   { 
681     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
682                                                             "OVERLAY_RANDOM_LINKS",
683                                                             &random_links))
684     {
685       /* OVERLAY option RANDOM & SMALL_WORLD_RING requires OVERLAY_RANDOM_LINKS
686          option to be set to the number of random links to be established  */
687       GNUNET_break (0);
688       GNUNET_free (rc);
689       return;
690     }
691     if (random_links > UINT32_MAX)
692     {
693       GNUNET_break (0);       /* Too big number */
694       GNUNET_free (rc);
695       return;
696     }
697     rc->num_oc = (unsigned int) random_links;
698     if (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology)
699       rc->num_oc += num_peers;
700   }
701   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
702                                 &shutdown_run_task, rc);
703 }
704
705
706 /**
707  * Configure and run a testbed using the given
708  * master controller on 'num_hosts' starting
709  * 'num_peers' using the given peer configuration.
710  *
711  * @param controller master controller for the testbed
712  *                   (must not be destroyed until after the
713  *                    testbed is destroyed).
714  * @param num_hosts number of hosts in 'hosts', 0 to only
715  *        use 'localhost'
716  * @param hosts list of hosts to use for the testbed
717  * @param num_peers number of peers to start
718  * @param cfg the configuration to use as a template for peers and also for
719  *         checking the value of testbed helper binary
720  * @param underlay_topology underlay topology to create
721  * @param va topology-specific options
722  * @return handle to the testbed; NULL upon error (error messaage will be printed)
723  */
724 struct GNUNET_TESTBED_Testbed *
725 GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller,
726                           unsigned int num_hosts,
727                           struct GNUNET_TESTBED_Host **hosts,
728                           unsigned int num_peers,
729                           const struct GNUNET_CONFIGURATION_Handle *cfg,
730                           enum GNUNET_TESTBED_TopologyOption underlay_topology,
731                           va_list va)
732 {
733   unsigned int nhost;
734
735   GNUNET_assert (underlay_topology < GNUNET_TESTBED_TOPOLOGY_NONE);
736   if (num_hosts != 0)
737   {
738     for (nhost = 0; nhost < num_hosts; nhost++)
739     {
740       if (GNUNET_YES != GNUNET_TESTBED_is_host_habitable (hosts[nhost], cfg))
741       {
742         LOG (GNUNET_ERROR_TYPE_ERROR, _("Host %s cannot start testbed\n"),
743              GNUNET_TESTBED_host_get_hostname_ (hosts[nhost]));
744         break;
745       }
746     }
747     if (num_hosts != nhost)
748       return NULL;
749   }
750   /* We need controller callback here to get operation done events while
751      linking hosts */
752   GNUNET_break (0);
753   return NULL;
754 }
755
756
757 /**
758  * Configure and run a testbed using the given
759  * master controller on 'num_hosts' starting
760  * 'num_peers' using the given peer configuration.
761  *
762  * @param controller master controller for the testbed
763  *                   (must not be destroyed until after the
764  *                    testbed is destroyed).
765  * @param num_hosts number of hosts in 'hosts', 0 to only
766  *        use 'localhost'
767  * @param hosts list of hosts to use for the testbed
768  * @param num_peers number of peers to start
769  * @param cfg the configuration to use as a template for peers and also for
770  *         checking the value of testbed helper binary
771  * @param underlay_topology underlay topology to create
772  * @param ... topology-specific options
773  */
774 struct GNUNET_TESTBED_Testbed *
775 GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller,
776                        unsigned int num_hosts,
777                        struct GNUNET_TESTBED_Host **hosts,
778                        unsigned int num_peers,
779                        const struct GNUNET_CONFIGURATION_Handle *cfg,
780                        enum GNUNET_TESTBED_TopologyOption underlay_topology,
781                        ...)
782 {
783   struct GNUNET_TESTBED_Testbed *testbed;
784   va_list vargs;
785   
786   va_start (vargs, underlay_topology);
787   testbed = GNUNET_TESTBED_create_va (controller, num_hosts, hosts, num_peers,
788                                       cfg, underlay_topology, vargs);
789   va_end (vargs);
790   return testbed;
791 }
792
793
794 /**
795  * Destroy a testbed.  Stops all running peers and then
796  * destroys all peers.  Does NOT destroy the master controller.
797  *
798  * @param testbed testbed to destroy
799  */
800 void
801 GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
802 {
803   GNUNET_break (0);
804 }
805
806
807 /* end of testbed_api_testbed.c */