2 This file is part of GNUnet
3 (C) 2008--2012 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file testbed/testbed_api_testbed.c
23 * @brief high-level testbed management
24 * @author Christian Grothoff
25 * @author Sree Harsha Totakura
29 #include "gnunet_testbed_service.h"
30 #include "testbed_api_peers.h"
33 * Generic loggins shorthand
35 #define LOG(kind,...) \
36 GNUNET_log_from (kind, "testbed-api-testbed", __VA_ARGS__)
39 * Opaque handle to an abstract operation to be executed by the testing framework.
41 struct GNUNET_TESTBED_Testbed
53 * The testbed operation handle
55 struct GNUNET_TESTBED_Operation *op;
58 * Context information for GNUNET_TESTBED_run()
60 struct RunContext *rc;
68 * The next pointer for DLL
70 struct DLLOperation *next;
73 * The prev pointer for DLL
75 struct DLLOperation *prev;
80 * States of RunContext
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
102 * Peers are destroyed
114 * The controller handle
116 struct GNUNET_TESTBED_Controller *c;
119 * Handle to the host on which the controller runs
121 struct GNUNET_TESTBED_Host *h;
124 * The handle to the controller process
126 struct GNUNET_TESTBED_ControllerProc *cproc;
129 * The callback to use as controller callback
131 GNUNET_TESTBED_ControllerCallback cc;
134 * The pointer to the controller callback
139 * Master task to call when testbed initialization is done
141 GNUNET_SCHEDULER_Task master;
144 * The closure for the master task
149 * The head element of DLL operations
151 struct DLLOperation *dll_op_head;
154 * The tail element of DLL operations
156 struct DLLOperation *dll_op_tail;
159 * Array of peers which we create
161 struct GNUNET_TESTBED_Peer **peers;
164 * The topology generation operation. Will be null if no topology is set in
167 struct GNUNET_TESTBED_Operation *topology_operation;
170 * The event mask for the controller
175 * State of this context
180 * The topology which has to be achieved with the peers started in this context
182 enum GNUNET_TESTBED_TopologyOption topology;
185 * Current peer count for an operation; Set this to 0 and increment for each
186 * successful operation on a peer
188 unsigned int peer_count;
191 * number of peers to start
193 unsigned int num_peers;
196 * counter to count overlay connect attempts. This counter includes both
197 * successful and failed overlay connects
199 unsigned int oc_count;
202 * Expected overlay connects. Should be zero if no topology is relavant
210 * Task for starting peers
212 * @param cls the RunHandle
213 * @param tc the task context from scheduler
216 start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
218 struct RunContext *rc = cls;
219 struct DLLOperation *dll_op;
222 LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting Peers\n");
223 for (peer = 0; peer < rc->num_peers; peer++)
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);
235 * Functions of this signature are called when a peer has been successfully
238 * @param cls the closure from GNUNET_TESTBED_peer_create()
239 * @param peer the handle for the created peer; NULL on any error during
241 * @param emsg NULL if peer is not NULL; else MAY contain the error description
244 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
246 struct DLLOperation *dll_op = cls;
247 struct RunContext *rc;
249 GNUNET_assert (NULL != dll_op);
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);
258 LOG (GNUNET_ERROR_TYPE_WARNING, "Error while creating a peer: %s\n",
260 /* FIXME: GNUNET_TESTBED_shutdown_run()? */
263 rc->peers[rc->peer_count] = peer;
265 if (rc->peer_count < rc->num_peers)
267 LOG (GNUNET_ERROR_TYPE_DEBUG, "Required peers created successfully\n");
268 GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
273 * Assuming all peers have been destroyed cleanup run handle
275 * @param cls the run handle
276 * @param tc the task context from scheduler
279 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
281 struct RunContext *rc = cls;
282 struct DLLOperation *dll_op;
284 GNUNET_assert (NULL == rc->peers);
285 GNUNET_assert (RC_PEERS_DESTROYED == rc->state);
287 GNUNET_TESTBED_controller_disconnect (rc->c);
288 if (NULL != rc->cproc)
289 GNUNET_TESTBED_controller_stop (rc->cproc);
291 GNUNET_TESTBED_host_destroy (rc->h);
292 if (NULL != rc->dll_op_head)
294 LOG (GNUNET_ERROR_TYPE_WARNING,
295 _("Some operations are still pending. Cancelling them\n"));
296 while (NULL != (dll_op = rc->dll_op_head))
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);
308 * Task to call master task
310 * @param cls the run context
311 * @param tc the task context
314 call_master (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
316 struct RunContext *rc = cls;
318 if (NULL != rc->topology_operation)
320 GNUNET_TESTBED_operation_done (rc->topology_operation);
321 rc->topology_operation = NULL;
323 if (NULL != rc->master)
324 GNUNET_SCHEDULER_add_continuation (rc->master, rc->master_cls,
325 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
330 * Signature of the event handler function called by the
331 * respective event controller.
334 * @param event information about the event
337 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
339 struct RunContext *rc = cls;
340 struct DLLOperation *dll_op;
341 unsigned int peer_id;
343 if (NULL != rc->topology_operation)
347 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
348 case GNUNET_TESTBED_ET_CONNECT:
354 if (rc->oc_count == rc->num_oc)
356 rc->state = RC_READY;
357 GNUNET_SCHEDULER_add_continuation (&call_master, rc,
358 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
362 if ((RC_INIT != rc->state) &&
363 ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) ||
364 (GNUNET_TESTBED_ET_PEER_STOP == event->type)))
366 for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
368 if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
369 (event->details.operation_finished.operation == dll_op->op))
371 if ((GNUNET_TESTBED_ET_PEER_STOP == event->type) &&
372 (event->details.peer_stop.peer == dll_op->cls))
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);
381 if (rc->peer_count < rc->num_peers)
386 rc->state = RC_PEERS_STOPPED;
388 for (peer_id = 0; peer_id < rc->num_peers; peer_id++)
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,
396 case RC_PEERS_STOPPED:
397 rc->state = RC_PEERS_DESTROYED;
398 GNUNET_free (rc->peers);
400 LOG (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully destroyed\n");
401 GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
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)
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))
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);
423 if (rc->peer_count < rc->num_peers)
425 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers started successfully\n");
426 if (GNUNET_TESTBED_TOPOLOGY_NONE != rc->topology)
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,
435 (GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI
438 (rc->num_oc - rc->num_peers),
439 GNUNET_TESTBED_TOPOLOGY_OPTION_END);
441 rc->topology_operation =
442 GNUNET_TESTBED_overlay_configure_topology (NULL,
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");
453 rc->state = RC_READY;
454 GNUNET_SCHEDULER_add_continuation (&call_master, rc,
455 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
461 * Callback to signal successfull startup of the controller process
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
470 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
473 struct RunContext *rc = cls;
474 struct DLLOperation *dll_op;
478 if (status != GNUNET_OK)
480 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
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;
489 GNUNET_TESTBED_controller_connect (cfg, rc->h, event_mask, &event_cb, rc);
491 GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
492 GNUNET_assert (NULL != rc->c);
494 for (peer = 0; peer < rc->num_peers; peer++)
496 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
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);
506 * Stops the testbed run and releases any used resources
508 * @param cls the tesbed run handle
509 * @param tc the task context from scheduler
512 shutdown_run_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
514 struct RunContext *rc = cls;
515 struct DLLOperation *dll_op;
520 if (NULL != rc->peers)
522 if (NULL != rc->topology_operation)
524 GNUNET_TESTBED_operation_done (rc->topology_operation);
525 rc->topology_operation = NULL;
527 if (RC_INIT == rc->state)
528 rc->state = RC_READY; /* Even though we haven't called the master callback */
530 /* Check if some peers are stopped */
531 for (peer = 0; peer < rc->num_peers; peer++)
533 if (PS_STOPPED != rc->peers[peer]->state)
536 if (peer == rc->num_peers)
538 /* All peers are stopped */
539 rc->state = RC_PEERS_STOPPED;
540 for (peer = 0; peer < rc->num_peers; peer++)
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,
549 /* Some peers are stopped */
550 for (peer = 0; peer < rc->num_peers; peer++)
552 if (PS_STARTED != rc->peers[peer]->state)
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,
563 if (rc->peer_count != rc->num_peers)
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);
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
581 * The testbed is to be terminated using a call to
582 * "GNUNET_SCHEDULER_shutdown".
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
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)
607 struct RunContext *rc;
609 unsigned long long random_links;
611 GNUNET_break (NULL == host_filename); /* Currently we do not support host
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);
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);
629 rc->master_cls = master_cls;
631 rc->topology = GNUNET_TESTBED_TOPOLOGY_NONE;
632 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
636 if (0 == strcasecmp (topology, "RANDOM"))
638 rc->topology = GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI;
640 else if (0 == strcasecmp (topology, "SMALL_WORLD_RING"))
642 rc->topology = GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING;
644 else if (0 == strcasecmp (topology, "CLIQUE"))
646 rc->topology = GNUNET_TESTBED_TOPOLOGY_CLIQUE;
647 rc->num_oc = num_peers * (num_peers - 1);
649 else if (0 == strcasecmp (topology, "LINE"))
651 rc->topology = GNUNET_TESTBED_TOPOLOGY_LINE;
652 rc->num_oc = num_peers - 1;
654 else if (0 == strcasecmp (topology, "RING"))
656 rc->topology = GNUNET_TESTBED_TOPOLOGY_RING;
657 rc->num_oc = num_peers;
660 LOG (GNUNET_ERROR_TYPE_WARNING,
661 "Unknown topology %s given in configuration\n", topology);
662 GNUNET_free (topology);
664 if ( (GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology)
665 || (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology))
667 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
668 "OVERLAY_RANDOM_LINKS",
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 */
677 if (random_links > UINT32_MAX)
679 GNUNET_break (0); /* Too big number */
683 rc->num_oc = (unsigned int) random_links;
684 if (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology)
685 rc->num_oc += num_peers;
687 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
688 &shutdown_run_task, rc);
693 * Configure and run a testbed using the given
694 * master controller on 'num_hosts' starting
695 * 'num_peers' using the given peer configuration.
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
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
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,
718 GNUNET_assert (underlay_topology < GNUNET_TESTBED_TOPOLOGY_NONE);
725 * Configure and run a testbed using the given
726 * master controller on 'num_hosts' starting
727 * 'num_peers' using the given peer configuration.
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
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
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,
749 struct GNUNET_TESTBED_Testbed *testbed;
752 va_start (vargs, underlay_topology);
753 testbed = GNUNET_TESTBED_create_va (controller, num_hosts, hosts, num_peers,
754 peer_cfg, underlay_topology, vargs);
761 * Destroy a testbed. Stops all running peers and then
762 * destroys all peers. Does NOT destroy the master controller.
764 * @param testbed testbed to destroy
767 GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
773 /* end of testbed_api_testbed.c */