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