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