implementing small world ring topology
[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_NONE != rc->topology)
427   {
428     if ( (GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology)
429          || (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology))
430       rc->topology_operation =
431           GNUNET_TESTBED_overlay_configure_topology (NULL,
432                                                      rc->num_peers,
433                                                      rc->peers,
434                                                      rc->topology,
435                                                      (GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI
436                                                       == rc->topology) ?
437                                                      rc->num_oc : 
438                                                      (rc->num_oc - rc->num_peers),
439                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
440     else
441       rc->topology_operation =
442           GNUNET_TESTBED_overlay_configure_topology (NULL,
443                                                      rc->num_peers,
444                                                      rc->peers,
445                                                      rc->topology,
446                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
447     if (NULL == rc->topology_operation)
448       LOG (GNUNET_ERROR_TYPE_WARNING,
449            "Not generating topology. Check number of peers\n");
450     else
451       return;
452   }
453   rc->state = RC_READY;
454   GNUNET_SCHEDULER_add_continuation (&call_master, rc,
455                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
456 }
457
458
459
460 /**
461  * Callback to signal successfull startup of the controller process
462  *
463  * @param cls the closure from GNUNET_TESTBED_controller_start()
464  * @param cfg the configuration with which the controller has been started;
465  *          NULL if status is not GNUNET_OK
466  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
467  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
468  */
469 static void
470 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
471                       int status)
472 {
473   struct RunContext *rc = cls;
474   struct DLLOperation *dll_op;
475   uint64_t event_mask;
476   unsigned int peer;
477
478   if (status != GNUNET_OK)
479   {
480     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
481     return;
482   }
483   event_mask = rc->event_mask;
484   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
485   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
486   if (rc->topology < GNUNET_TESTBED_TOPOLOGY_NONE)
487     event_mask |= GNUNET_TESTBED_ET_CONNECT;
488   rc->c =
489       GNUNET_TESTBED_controller_connect (cfg, rc->h, event_mask, &event_cb, rc);
490   rc->peers =
491       GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
492   GNUNET_assert (NULL != rc->c);
493   rc->peer_count = 0;
494   for (peer = 0; peer < rc->num_peers; peer++)
495   {
496     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
497     dll_op->rc = rc;
498     dll_op->op =
499         GNUNET_TESTBED_peer_create (rc->c, rc->h, cfg, peer_create_cb, dll_op);
500     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
501   }
502 }
503
504
505 /**
506  * Stops the testbed run and releases any used resources
507  *
508  * @param cls the tesbed run handle
509  * @param tc the task context from scheduler
510  */
511 static void
512 shutdown_run_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
513 {
514   struct RunContext *rc = cls;
515   struct DLLOperation *dll_op;
516   unsigned int peer;
517
518   if (NULL != rc->c)
519   {
520     if (NULL != rc->peers)
521     {
522       if (NULL != rc->topology_operation)
523       {
524         GNUNET_TESTBED_operation_done (rc->topology_operation);
525         rc->topology_operation = NULL;
526       }
527       if (RC_INIT == rc->state)
528         rc->state = RC_READY;   /* Even though we haven't called the master callback */
529       rc->peer_count = 0;
530       /* Check if some peers are stopped */
531       for (peer = 0; peer < rc->num_peers; peer++)
532       {
533         if (PS_STOPPED != rc->peers[peer]->state)
534           break;
535       }
536       if (peer == rc->num_peers)
537       {
538         /* All peers are stopped */
539         rc->state = RC_PEERS_STOPPED;
540         for (peer = 0; peer < rc->num_peers; peer++)
541         {
542           dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
543           dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer]);
544           GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
545                                             dll_op);
546         }
547         return;
548       }
549       /* Some peers are stopped */
550       for (peer = 0; peer < rc->num_peers; peer++)
551       {
552         if (PS_STARTED != rc->peers[peer]->state)
553         {
554           rc->peer_count++;
555           continue;
556         }
557         dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
558         dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer], NULL, NULL);
559         dll_op->cls = rc->peers[peer];
560         GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
561                                           dll_op);
562       }
563       if (rc->peer_count != rc->num_peers)
564         return;
565     }
566   }
567   rc->state = RC_PEERS_DESTROYED;       /* No peers are present so we consider the
568                                          * state where all peers are destroyed  */
569   GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
570 }
571
572
573 /**
574  * Convenience method for running a testbed with
575  * a single call.  Underlay and overlay topology
576  * are configured using the "UNDERLAY" and "OVERLAY"
577  * options in the "[testbed]" section of the configuration\
578  * (with possible options given in "UNDERLAY_XXX" and/or
579  * "OVERLAY_XXX").
580  *
581  * The testbed is to be terminated using a call to
582  * "GNUNET_SCHEDULER_shutdown".
583  *
584  * @param host_filename name of the file with the 'hosts', NULL
585  *        to run everything on 'localhost'
586  * @param cfg configuration to use (for testbed, controller and peers)
587  * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
588  * @param event_mask bit mask with set of events to call 'cc' for;
589  *                   or-ed values of "1LL" shifted by the
590  *                   respective 'enum GNUNET_TESTBED_EventType'
591  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
592  * @param cc controller callback to invoke on events; This callback is called
593  *          for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
594  *          set in the event_mask as this is the only way get access to the
595  *          handle of each peer
596  * @param cc_cls closure for cc
597  * @param master task to run once the testbed is ready
598  * @param master_cls
599  */
600 void
601 GNUNET_TESTBED_run (const char *host_filename,
602                     const struct GNUNET_CONFIGURATION_Handle *cfg,
603                     unsigned int num_peers, uint64_t event_mask,
604                     GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
605                     GNUNET_SCHEDULER_Task master, void *master_cls)
606 {
607   struct RunContext *rc;
608   char *topology;
609   unsigned long long random_links;
610
611   GNUNET_break (NULL == host_filename); /* Currently we do not support host
612                                          * files */
613   GNUNET_assert (NULL != cc);
614   GNUNET_assert (num_peers > 0);
615   host_filename = NULL;
616   rc = GNUNET_malloc (sizeof (struct RunContext));
617   rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
618   GNUNET_assert (NULL != rc->h);
619   rc->cproc =
620       GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, cfg,
621                                        &controller_status_cb, rc);
622   GNUNET_assert (NULL != rc->cproc);
623   rc->num_peers = num_peers;
624   rc->event_mask = event_mask;
625   rc->event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
626   rc->cc = cc;
627   rc->cc_cls = cc_cls;
628   rc->master = master;
629   rc->master_cls = master_cls;
630   rc->state = RC_INIT;
631   rc->topology = GNUNET_TESTBED_TOPOLOGY_NONE;
632   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
633                                                           "OVERLAY_TOPOLOGY",
634                                                           &topology))
635   {
636     if (0 == strcasecmp (topology, "RANDOM"))
637     {
638       rc->topology = GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI;      
639     }
640     else if (0 == strcasecmp (topology, "SMALL_WORLD_RING"))
641     {
642       rc->topology = GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING;
643     }
644     else if (0 == strcasecmp (topology, "CLIQUE"))
645     {
646       rc->topology = GNUNET_TESTBED_TOPOLOGY_CLIQUE;
647       rc->num_oc = num_peers * (num_peers - 1);
648     }
649     else if (0 == strcasecmp (topology, "LINE"))
650     {
651       rc->topology = GNUNET_TESTBED_TOPOLOGY_LINE;
652       rc->num_oc = num_peers - 1;
653     }
654     else if (0 == strcasecmp (topology, "RING"))
655     {
656       rc->topology = GNUNET_TESTBED_TOPOLOGY_RING;
657       rc->num_oc = num_peers;
658     }
659     else
660       LOG (GNUNET_ERROR_TYPE_WARNING,
661            "Unknown topology %s given in configuration\n", topology);
662     GNUNET_free (topology);
663   }
664   if ( (GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology)
665        || (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology))
666   { 
667     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
668                                                             "OVERLAY_RANDOM_LINKS",
669                                                             &random_links))
670     {
671       /* OVERLAY option RANDOM & SMALL_WORLD_RING requires OVERLAY_RANDOM_LINKS
672          option to be set to the number of random links to be established  */
673       GNUNET_break (0);
674       GNUNET_free (rc);
675       return;
676     }
677     if (random_links > UINT32_MAX)
678     {
679       GNUNET_break (0);       /* Too big number */
680       GNUNET_free (rc);
681       return;
682     }
683     rc->num_oc = (unsigned int) random_links;
684     if (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology)
685       rc->num_oc += num_peers;
686   }
687   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
688                                 &shutdown_run_task, rc);
689 }
690
691
692 /**
693  * Configure and run a testbed using the given
694  * master controller on 'num_hosts' starting
695  * 'num_peers' using the given peer configuration.
696  *
697  * @param controller master controller for the testbed
698  *                   (must not be destroyed until after the
699  *                    testbed is destroyed).
700  * @param num_hosts number of hosts in 'hosts', 0 to only
701  *        use 'localhost'
702  * @param hosts list of hosts to use for the testbed
703  * @param num_peers number of peers to start
704  * @param peer_cfg peer configuration template to use
705  * @param underlay_topology underlay topology to create
706  * @param va topology-specific options
707  * @return handle to the testbed
708  */
709 struct GNUNET_TESTBED_Testbed *
710 GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller,
711                           unsigned int num_hosts,
712                           struct GNUNET_TESTBED_Host **hosts,
713                           unsigned int num_peers,
714                           const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
715                           enum GNUNET_TESTBED_TopologyOption underlay_topology,
716                           va_list va)
717 {
718   GNUNET_assert (underlay_topology < GNUNET_TESTBED_TOPOLOGY_NONE);
719   GNUNET_break (0);
720   return NULL;
721 }
722
723
724 /**
725  * Configure and run a testbed using the given
726  * master controller on 'num_hosts' starting
727  * 'num_peers' using the given peer configuration.
728  *
729  * @param controller master controller for the testbed
730  *                   (must not be destroyed until after the
731  *                    testbed is destroyed).
732  * @param num_hosts number of hosts in 'hosts', 0 to only
733  *        use 'localhost'
734  * @param hosts list of hosts to use for the testbed
735  * @param num_peers number of peers to start
736  * @param peer_cfg peer configuration template to use
737  * @param underlay_topology underlay topology to create
738  * @param ... topology-specific options
739  */
740 struct GNUNET_TESTBED_Testbed *
741 GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller,
742                        unsigned int num_hosts,
743                        struct GNUNET_TESTBED_Host **hosts,
744                        unsigned int num_peers,
745                        const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
746                        enum GNUNET_TESTBED_TopologyOption underlay_topology,
747                        ...)
748 {
749   struct GNUNET_TESTBED_Testbed *testbed;
750   va_list vargs;
751   
752   va_start (vargs, underlay_topology);
753   testbed = GNUNET_TESTBED_create_va (controller, num_hosts, hosts, num_peers,
754                                       peer_cfg, underlay_topology, vargs);
755   va_end (vargs);
756   return testbed;
757 }
758
759
760 /**
761  * Destroy a testbed.  Stops all running peers and then
762  * destroys all peers.  Does NOT destroy the master controller.
763  *
764  * @param testbed testbed to destroy
765  */
766 void
767 GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
768 {
769   GNUNET_break (0);
770 }
771
772
773 /* end of testbed_api_testbed.c */