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