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