small world 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 #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
223
224 /**
225  * Task for starting peers
226  *
227  * @param cls the RunHandle
228  * @param tc the task context from scheduler
229  */
230 static void
231 start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
232 {
233   struct RunContext *rc = cls;
234   struct DLLOperation *dll_op;
235   unsigned int peer;
236
237   LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting Peers\n");
238   for (peer = 0; peer < rc->num_peers; peer++)
239   {
240     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
241     dll_op->op = GNUNET_TESTBED_peer_start (NULL, rc->peers[peer], NULL, NULL);
242     dll_op->cls = rc->peers[peer];
243     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
244   }
245   rc->peer_count = 0;
246 }
247
248
249 /**
250  * Functions of this signature are called when a peer has been successfully
251  * created
252  *
253  * @param cls the closure from GNUNET_TESTBED_peer_create()
254  * @param peer the handle for the created peer; NULL on any error during
255  *          creation
256  * @param emsg NULL if peer is not NULL; else MAY contain the error description
257  */
258 static void
259 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
260 {
261   struct DLLOperation *dll_op = cls;
262   struct RunContext *rc;
263
264   GNUNET_assert (NULL != dll_op);
265   rc = dll_op->rc;
266   GNUNET_assert (NULL != rc);
267   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
268   GNUNET_TESTBED_operation_done (dll_op->op);
269   GNUNET_free (dll_op);
270   if (NULL == peer)
271   {
272     if (NULL != emsg)
273       LOG (GNUNET_ERROR_TYPE_WARNING, "Error while creating a peer: %s\n",
274            emsg);
275     /* FIXME: GNUNET_TESTBED_shutdown_run()? */
276     return;
277   }
278   rc->peers[rc->peer_count] = peer;
279   rc->peer_count++;
280   if (rc->peer_count < rc->num_peers)
281     return;
282   LOG (GNUNET_ERROR_TYPE_DEBUG, "Required peers created successfully\n");
283   GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
284 }
285
286
287 /**
288  * Assuming all peers have been destroyed cleanup run handle
289  *
290  * @param cls the run handle
291  * @param tc the task context from scheduler
292  */
293 static void
294 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
295 {
296   struct RunContext *rc = cls;
297   struct DLLOperation *dll_op;
298
299   GNUNET_assert (NULL == rc->peers);
300   GNUNET_assert (RC_PEERS_DESTROYED == rc->state);
301   if (NULL != rc->c)
302     GNUNET_TESTBED_controller_disconnect (rc->c);
303   if (NULL != rc->cproc)
304     GNUNET_TESTBED_controller_stop (rc->cproc);
305   if (NULL != rc->h)
306     GNUNET_TESTBED_host_destroy (rc->h);
307   if (NULL != rc->dll_op_head)
308   {
309     LOG (GNUNET_ERROR_TYPE_WARNING,
310          _("Some operations are still pending. Cancelling them\n"));
311     while (NULL != (dll_op = rc->dll_op_head))
312     {
313       GNUNET_TESTBED_operation_done (dll_op->op);
314       GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
315       GNUNET_free (dll_op);
316     }
317   }
318   GNUNET_free (rc);
319 }
320
321
322 /**
323  * Task to call master task
324  *
325  * @param cls the run context
326  * @param tc the task context
327  */
328 static void
329 call_master (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
330 {
331   struct RunContext *rc = cls;
332   
333   if (NULL != rc->topology_operation)
334   {
335     GNUNET_TESTBED_operation_done (rc->topology_operation);
336     rc->topology_operation = NULL;
337   }
338   if (NULL != rc->master)
339     GNUNET_SCHEDULER_add_continuation (rc->master, rc->master_cls,
340                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
341 }
342
343
344 /**
345  * Signature of the event handler function called by the
346  * respective event controller.
347  *
348  * @param cls closure
349  * @param event information about the event
350  */
351 static void
352 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
353 {
354   struct RunContext *rc = cls;
355   struct DLLOperation *dll_op;
356   unsigned int peer_id;
357
358   if (NULL != rc->topology_operation)
359   {
360     switch (event->type)
361     {
362     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
363     case GNUNET_TESTBED_ET_CONNECT:
364       rc->oc_count++;
365       break;
366     default:
367       GNUNET_assert (0);
368     }
369     if (rc->oc_count == rc->num_oc)
370     {
371       rc->state = RC_READY;
372       GNUNET_SCHEDULER_add_continuation (&call_master, rc,
373                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
374     }
375     return;
376   }
377   if ((RC_INIT != rc->state) &&
378       ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) ||
379        (GNUNET_TESTBED_ET_PEER_STOP == event->type)))
380   {
381     for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
382     {
383       if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
384           (event->details.operation_finished.operation == dll_op->op))
385         break;
386       if ((GNUNET_TESTBED_ET_PEER_STOP == event->type) &&
387           (event->details.peer_stop.peer == dll_op->cls))
388         break;
389     }
390     if (NULL == dll_op)
391       goto call_cc;
392     GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
393     GNUNET_TESTBED_operation_done (dll_op->op);
394     GNUNET_free (dll_op);
395     rc->peer_count++;
396     if (rc->peer_count < rc->num_peers)
397       return;
398     switch (rc->state)
399     {
400     case RC_READY:
401       rc->state = RC_PEERS_STOPPED;
402       rc->peer_count = 0;
403       for (peer_id = 0; peer_id < rc->num_peers; peer_id++)
404       {
405         dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
406         dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer_id]);
407         GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
408                                           dll_op);
409       }
410       break;
411     case RC_PEERS_STOPPED:
412       rc->state = RC_PEERS_DESTROYED;
413       GNUNET_free (rc->peers);
414       rc->peers = NULL;
415       LOG (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully destroyed\n");
416       GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
417       break;
418     default:
419       GNUNET_assert (0);
420     }
421     return;
422   }
423
424 call_cc:
425   if ((0 != (rc->event_mask && (1LL << event->type))) && (NULL != rc->cc))
426     rc->cc (rc->cc_cls, event);
427   if (GNUNET_TESTBED_ET_PEER_START != event->type)
428     return;
429   for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
430     if ((NULL != dll_op->cls) &&
431         (event->details.peer_start.peer == dll_op->cls))
432       break;
433   GNUNET_assert (NULL != dll_op);
434   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
435   GNUNET_TESTBED_operation_done (dll_op->op);
436   GNUNET_free (dll_op);
437   rc->peer_count++;
438   if (rc->peer_count < rc->num_peers)
439     return;
440   LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers started successfully\n");
441   if (GNUNET_TESTBED_TOPOLOGY_NONE != rc->topology)
442   {
443     if ( (GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology)
444          || (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology)
445          || (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD == rc->topology))
446     {
447       unsigned int rand_links;
448       
449       switch (rc->topology)
450       {
451       case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
452         rand_links = rc->num_oc;
453         break;
454       case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
455         rand_links = rc->num_oc - rc->num_peers;
456         break;
457       case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
458         rand_links = GNUNET_TESTBED_2dtorus_calc_links (rc->num_peers, NULL, NULL);
459         break;
460       default:
461         GNUNET_break (0);
462         rand_links = 0;
463       }
464       rc->topology_operation =
465           GNUNET_TESTBED_overlay_configure_topology (NULL,
466                                                      rc->num_peers,
467                                                      rc->peers,
468                                                      rc->topology,
469                                                      rand_links,
470                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
471     }
472     else
473       rc->topology_operation =
474           GNUNET_TESTBED_overlay_configure_topology (NULL,
475                                                      rc->num_peers,
476                                                      rc->peers,
477                                                      rc->topology,
478                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
479     if (NULL == rc->topology_operation)
480       LOG (GNUNET_ERROR_TYPE_WARNING,
481            "Not generating topology. Check number of peers\n");
482     else
483       return;
484   }
485   rc->state = RC_READY;
486   GNUNET_SCHEDULER_add_continuation (&call_master, rc,
487                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
488 }
489
490
491
492 /**
493  * Callback to signal successfull startup of the controller process
494  *
495  * @param cls the closure from GNUNET_TESTBED_controller_start()
496  * @param cfg the configuration with which the controller has been started;
497  *          NULL if status is not GNUNET_OK
498  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
499  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
500  */
501 static void
502 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
503                       int status)
504 {
505   struct RunContext *rc = cls;
506   struct DLLOperation *dll_op;
507   uint64_t event_mask;
508   unsigned int peer;
509
510   if (status != GNUNET_OK)
511   {
512     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
513     return;
514   }
515   event_mask = rc->event_mask;
516   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
517   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
518   if (rc->topology < GNUNET_TESTBED_TOPOLOGY_NONE)
519     event_mask |= GNUNET_TESTBED_ET_CONNECT;
520   rc->c =
521       GNUNET_TESTBED_controller_connect (cfg, rc->h, event_mask, &event_cb, rc);
522   rc->peers =
523       GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
524   GNUNET_assert (NULL != rc->c);
525   rc->peer_count = 0;
526   for (peer = 0; peer < rc->num_peers; peer++)
527   {
528     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
529     dll_op->rc = rc;
530     dll_op->op =
531         GNUNET_TESTBED_peer_create (rc->c, rc->h, cfg, peer_create_cb, dll_op);
532     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
533   }
534 }
535
536
537 /**
538  * Stops the testbed run and releases any used resources
539  *
540  * @param cls the tesbed run handle
541  * @param tc the task context from scheduler
542  */
543 static void
544 shutdown_run_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
545 {
546   struct RunContext *rc = cls;
547   struct DLLOperation *dll_op;
548   unsigned int peer;
549
550   if (NULL != rc->c)
551   {
552     if (NULL != rc->peers)
553     {
554       if (NULL != rc->topology_operation)
555       {
556         GNUNET_TESTBED_operation_done (rc->topology_operation);
557         rc->topology_operation = NULL;
558       }
559       if (RC_INIT == rc->state)
560         rc->state = RC_READY;   /* Even though we haven't called the master callback */
561       rc->peer_count = 0;
562       /* Check if some peers are stopped */
563       for (peer = 0; peer < rc->num_peers; peer++)
564       {
565         if (PS_STOPPED != rc->peers[peer]->state)
566           break;
567       }
568       if (peer == rc->num_peers)
569       {
570         /* All peers are stopped */
571         rc->state = RC_PEERS_STOPPED;
572         for (peer = 0; peer < rc->num_peers; peer++)
573         {
574           dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
575           dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer]);
576           GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
577                                             dll_op);
578         }
579         return;
580       }
581       /* Some peers are stopped */
582       for (peer = 0; peer < rc->num_peers; peer++)
583       {
584         if (PS_STARTED != rc->peers[peer]->state)
585         {
586           rc->peer_count++;
587           continue;
588         }
589         dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
590         dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer], NULL, NULL);
591         dll_op->cls = rc->peers[peer];
592         GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
593                                           dll_op);
594       }
595       if (rc->peer_count != rc->num_peers)
596         return;
597     }
598   }
599   rc->state = RC_PEERS_DESTROYED;       /* No peers are present so we consider the
600                                          * state where all peers are destroyed  */
601   GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
602 }
603
604
605 /**
606  * Convenience method for running a testbed with
607  * a single call.  Underlay and overlay topology
608  * are configured using the "UNDERLAY" and "OVERLAY"
609  * options in the "[testbed]" section of the configuration\
610  * (with possible options given in "UNDERLAY_XXX" and/or
611  * "OVERLAY_XXX").
612  *
613  * The testbed is to be terminated using a call to
614  * "GNUNET_SCHEDULER_shutdown".
615  *
616  * @param host_filename name of the file with the 'hosts', NULL
617  *        to run everything on 'localhost'
618  * @param cfg configuration to use (for testbed, controller and peers)
619  * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
620  * @param event_mask bit mask with set of events to call 'cc' for;
621  *                   or-ed values of "1LL" shifted by the
622  *                   respective 'enum GNUNET_TESTBED_EventType'
623  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
624  * @param cc controller callback to invoke on events; This callback is called
625  *          for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
626  *          set in the event_mask as this is the only way get access to the
627  *          handle of each peer
628  * @param cc_cls closure for cc
629  * @param master task to run once the testbed is ready
630  * @param master_cls
631  */
632 void
633 GNUNET_TESTBED_run (const char *host_filename,
634                     const struct GNUNET_CONFIGURATION_Handle *cfg,
635                     unsigned int num_peers, uint64_t event_mask,
636                     GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
637                     GNUNET_SCHEDULER_Task master, void *master_cls)
638 {
639   struct RunContext *rc;
640   char *topology;
641   unsigned long long random_links;
642
643   GNUNET_break (NULL == host_filename); /* Currently we do not support host
644                                          * files */
645   GNUNET_assert (NULL != cc);
646   GNUNET_assert (num_peers > 0);
647   host_filename = NULL;
648   rc = GNUNET_malloc (sizeof (struct RunContext));
649   rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
650   GNUNET_assert (NULL != rc->h);
651   rc->cproc =
652       GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, cfg,
653                                        &controller_status_cb, rc);
654   GNUNET_assert (NULL != rc->cproc);
655   rc->num_peers = num_peers;
656   rc->event_mask = event_mask;
657   rc->event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
658   rc->cc = cc;
659   rc->cc_cls = cc_cls;
660   rc->master = master;
661   rc->master_cls = master_cls;
662   rc->state = RC_INIT;
663   rc->topology = GNUNET_TESTBED_TOPOLOGY_NONE;
664   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
665                                                           "OVERLAY_TOPOLOGY",
666                                                           &topology))
667   {
668     if (0 == strcasecmp (topology, "RANDOM"))
669     {
670       rc->topology = GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI;      
671     }
672     else if (0 == strcasecmp (topology, "SMALL_WORLD_RING"))
673     {
674       rc->topology = GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING;
675       rc->num_oc = num_peers;
676     }
677     else if (0 == strcasecmp (topology, "SMALL_WORLD"))
678     {
679       rc->topology = GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD;
680       rc->num_oc = GNUNET_TESTBED_2dtorus_calc_links (num_peers, NULL, NULL);
681     }
682     else if (0 == strcasecmp (topology, "CLIQUE"))
683     {
684       rc->topology = GNUNET_TESTBED_TOPOLOGY_CLIQUE;
685       rc->num_oc = num_peers * (num_peers - 1);
686     }
687     else if (0 == strcasecmp (topology, "LINE"))
688     {
689       rc->topology = GNUNET_TESTBED_TOPOLOGY_LINE;
690       rc->num_oc = num_peers - 1;
691     }
692     else if (0 == strcasecmp (topology, "RING"))
693     {
694       rc->topology = GNUNET_TESTBED_TOPOLOGY_RING;
695       rc->num_oc = num_peers;
696     }
697     else if (0 == strcasecmp (topology, "2D_TORUS"))
698     {
699       rc->topology = GNUNET_TESTBED_TOPOLOGY_2D_TORUS;
700       rc->num_oc = GNUNET_TESTBED_2dtorus_calc_links (num_peers, NULL, NULL);
701     }
702     else
703       LOG (GNUNET_ERROR_TYPE_WARNING,
704            "Unknown topology %s given in configuration\n", topology);
705     GNUNET_free (topology);
706   }
707   if ( (GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology)
708        || (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology)
709        || (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD == rc->topology))
710   { 
711     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
712                                                             "OVERLAY_RANDOM_LINKS",
713                                                             &random_links))
714     {
715       /* OVERLAY option RANDOM & SMALL_WORLD_RING requires OVERLAY_RANDOM_LINKS
716          option to be set to the number of random links to be established  */
717       GNUNET_break (0);
718       GNUNET_free (rc);
719       return;
720     }
721     if (random_links > UINT32_MAX)
722     {
723       GNUNET_break (0);       /* Too big number */
724       GNUNET_free (rc);
725       return;
726     }
727     rc->num_oc += (unsigned int) random_links;
728   }
729   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
730                                 &shutdown_run_task, rc);
731 }
732
733
734 /**
735  * Configure and run a testbed using the given
736  * master controller on 'num_hosts' starting
737  * 'num_peers' using the given peer configuration.
738  *
739  * @param controller master controller for the testbed
740  *                   (must not be destroyed until after the
741  *                    testbed is destroyed).
742  * @param num_hosts number of hosts in 'hosts', 0 to only
743  *        use 'localhost'
744  * @param hosts list of hosts to use for the testbed
745  * @param num_peers number of peers to start
746  * @param cfg the configuration to use as a template for peers and also for
747  *         checking the value of testbed helper binary
748  * @param underlay_topology underlay topology to create
749  * @param va topology-specific options
750  * @return handle to the testbed; NULL upon error (error messaage will be printed)
751  */
752 struct GNUNET_TESTBED_Testbed *
753 GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller,
754                           unsigned int num_hosts,
755                           struct GNUNET_TESTBED_Host **hosts,
756                           unsigned int num_peers,
757                           const struct GNUNET_CONFIGURATION_Handle *cfg,
758                           enum GNUNET_TESTBED_TopologyOption underlay_topology,
759                           va_list va)
760 {
761   unsigned int nhost;
762
763   GNUNET_assert (underlay_topology < GNUNET_TESTBED_TOPOLOGY_NONE);
764   if (num_hosts != 0)
765   {
766     for (nhost = 0; nhost < num_hosts; nhost++)
767     {
768       if (GNUNET_YES != GNUNET_TESTBED_is_host_habitable (hosts[nhost], cfg))
769       {
770         LOG (GNUNET_ERROR_TYPE_ERROR, _("Host %s cannot start testbed\n"),
771              GNUNET_TESTBED_host_get_hostname_ (hosts[nhost]));
772         break;
773       }
774     }
775     if (num_hosts != nhost)
776       return NULL;
777   }
778   /* We need controller callback here to get operation done events while
779      linking hosts */
780   GNUNET_break (0);
781   return NULL;
782 }
783
784
785 /**
786  * Configure and run a testbed using the given
787  * master controller on 'num_hosts' starting
788  * 'num_peers' using the given peer configuration.
789  *
790  * @param controller master controller for the testbed
791  *                   (must not be destroyed until after the
792  *                    testbed is destroyed).
793  * @param num_hosts number of hosts in 'hosts', 0 to only
794  *        use 'localhost'
795  * @param hosts list of hosts to use for the testbed
796  * @param num_peers number of peers to start
797  * @param cfg the configuration to use as a template for peers and also for
798  *         checking the value of testbed helper binary
799  * @param underlay_topology underlay topology to create
800  * @param ... topology-specific options
801  */
802 struct GNUNET_TESTBED_Testbed *
803 GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller,
804                        unsigned int num_hosts,
805                        struct GNUNET_TESTBED_Host **hosts,
806                        unsigned int num_peers,
807                        const struct GNUNET_CONFIGURATION_Handle *cfg,
808                        enum GNUNET_TESTBED_TopologyOption underlay_topology,
809                        ...)
810 {
811   struct GNUNET_TESTBED_Testbed *testbed;
812   va_list vargs;
813   
814   va_start (vargs, underlay_topology);
815   testbed = GNUNET_TESTBED_create_va (controller, num_hosts, hosts, num_peers,
816                                       cfg, underlay_topology, vargs);
817   va_end (vargs);
818   return testbed;
819 }
820
821
822 /**
823  * Destroy a testbed.  Stops all running peers and then
824  * destroys all peers.  Does NOT destroy the master controller.
825  *
826  * @param testbed testbed to destroy
827  */
828 void
829 GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
830 {
831   GNUNET_break (0);
832 }
833
834
835 /* end of testbed_api_testbed.c */