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_OPTION_END != rc->topology)
428 if (GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology)
429 rc->topology_operation =
430 GNUNET_TESTBED_overlay_configure_topology (dll_op,
435 GNUNET_TESTBED_TOPOLOGY_OPTION_END);
437 rc->topology_operation =
438 GNUNET_TESTBED_overlay_configure_topology (dll_op,
442 GNUNET_TESTBED_TOPOLOGY_OPTION_END);
443 if (NULL == rc->topology_operation)
444 LOG (GNUNET_ERROR_TYPE_WARNING,
445 "Not generating topology. Check number of peers\n");
449 rc->state = RC_READY;
450 GNUNET_SCHEDULER_add_continuation (&call_master, rc,
451 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
457 * Callback to signal successfull startup of the controller process
459 * @param cls the closure from GNUNET_TESTBED_controller_start()
460 * @param cfg the configuration with which the controller has been started;
461 * NULL if status is not GNUNET_OK
462 * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
463 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
466 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
469 struct RunContext *rc = cls;
470 struct DLLOperation *dll_op;
474 if (status != GNUNET_OK)
476 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
479 event_mask = rc->event_mask;
480 event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
481 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
482 if (rc->topology < GNUNET_TESTBED_TOPOLOGY_OPTION_END)
483 event_mask |= GNUNET_TESTBED_ET_CONNECT;
485 GNUNET_TESTBED_controller_connect (cfg, rc->h, event_mask, &event_cb, rc);
487 GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
488 GNUNET_assert (NULL != rc->c);
490 for (peer = 0; peer < rc->num_peers; peer++)
492 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
495 GNUNET_TESTBED_peer_create (rc->c, rc->h, cfg, peer_create_cb, dll_op);
496 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
502 * Stops the testbed run and releases any used resources
504 * @param cls the tesbed run handle
505 * @param tc the task context from scheduler
508 shutdown_run_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
510 struct RunContext *rc = cls;
511 struct DLLOperation *dll_op;
516 if (NULL != rc->peers)
518 if (NULL != rc->topology_operation)
520 GNUNET_TESTBED_operation_done (rc->topology_operation);
521 rc->topology_operation = NULL;
523 if (RC_INIT == rc->state)
524 rc->state = RC_READY; /* Even though we haven't called the master callback */
526 /* Check if some peers are stopped */
527 for (peer = 0; peer < rc->num_peers; peer++)
529 if (PS_STOPPED != rc->peers[peer]->state)
532 if (peer == rc->num_peers)
534 /* All peers are stopped */
535 rc->state = RC_PEERS_STOPPED;
536 for (peer = 0; peer < rc->num_peers; peer++)
538 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
539 dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer]);
540 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
545 /* Some peers are stopped */
546 for (peer = 0; peer < rc->num_peers; peer++)
548 if (PS_STARTED != rc->peers[peer]->state)
553 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
554 dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer], NULL, NULL);
555 dll_op->cls = rc->peers[peer];
556 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
559 if (rc->peer_count != rc->num_peers)
563 rc->state = RC_PEERS_DESTROYED; /* No peers are present so we consider the
564 * state where all peers are destroyed */
565 GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
570 * Convenience method for running a testbed with
571 * a single call. Underlay and overlay topology
572 * are configured using the "UNDERLAY" and "OVERLAY"
573 * options in the "[testbed]" section of the configuration\
574 * (with possible options given in "UNDERLAY_XXX" and/or
577 * The testbed is to be terminated using a call to
578 * "GNUNET_SCHEDULER_shutdown".
580 * @param host_filename name of the file with the 'hosts', NULL
581 * to run everything on 'localhost'
582 * @param cfg configuration to use (for testbed, controller and peers)
583 * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
584 * @param event_mask bit mask with set of events to call 'cc' for;
585 * or-ed values of "1LL" shifted by the
586 * respective 'enum GNUNET_TESTBED_EventType'
587 * (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
588 * @param cc controller callback to invoke on events; This callback is called
589 * for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
590 * set in the event_mask as this is the only way get access to the
591 * handle of each peer
592 * @param cc_cls closure for cc
593 * @param master task to run once the testbed is ready
597 GNUNET_TESTBED_run (const char *host_filename,
598 const struct GNUNET_CONFIGURATION_Handle *cfg,
599 unsigned int num_peers, uint64_t event_mask,
600 GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
601 GNUNET_SCHEDULER_Task master, void *master_cls)
603 struct RunContext *rc;
605 unsigned long long random_links;
607 GNUNET_break (NULL == host_filename); /* Currently we do not support host
609 GNUNET_assert (NULL != cc);
610 GNUNET_assert (num_peers > 0);
611 host_filename = NULL;
612 rc = GNUNET_malloc (sizeof (struct RunContext));
613 rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
614 GNUNET_assert (NULL != rc->h);
616 GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, cfg,
617 &controller_status_cb, rc);
618 GNUNET_assert (NULL != rc->cproc);
619 rc->num_peers = num_peers;
620 rc->event_mask = event_mask;
621 rc->event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
625 rc->master_cls = master_cls;
627 rc->topology = GNUNET_TESTBED_TOPOLOGY_OPTION_END;
628 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
632 if (0 == strcmp (topology, "RANDOM"))
634 rc->topology = GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI;
635 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
636 "OVERLAY_RANDOM_LINKS",
639 /* OVERLAY option RANDOM requires OVERLAY_RANDOM_LINKS option to */
640 /* be set to the number of random links to be established */
643 GNUNET_free (topology);
646 if (random_links > UINT32_MAX)
648 GNUNET_break (0); /* Too big number */
650 GNUNET_free (topology);
653 rc->num_oc = (unsigned int) random_links;
655 else if (0 == strcasecmp (topology, "CLIQUE"))
657 rc->topology = GNUNET_TESTBED_TOPOLOGY_CLIQUE;
658 rc->num_oc = num_peers * (num_peers - 1);
660 else if (0 == strcasecmp (topology, "LINE"))
662 rc->topology = GNUNET_TESTBED_TOPOLOGY_LINE;
663 rc->num_oc = num_peers - 1;
666 LOG (GNUNET_ERROR_TYPE_WARNING,
667 "Unknown topology %s given in configuration\n", topology);
668 GNUNET_free (topology);
670 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
671 &shutdown_run_task, rc);
676 * Configure and run a testbed using the given
677 * master controller on 'num_hosts' starting
678 * 'num_peers' using the given peer configuration.
680 * @param controller master controller for the testbed
681 * (must not be destroyed until after the
682 * testbed is destroyed).
683 * @param num_hosts number of hosts in 'hosts', 0 to only
685 * @param hosts list of hosts to use for the testbed
686 * @param num_peers number of peers to start
687 * @param peer_cfg peer configuration template to use
688 * @param underlay_topology underlay topology to create
689 * @param va topology-specific options
690 * @return handle to the testbed
692 struct GNUNET_TESTBED_Testbed *
693 GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller,
694 unsigned int num_hosts,
695 struct GNUNET_TESTBED_Host **hosts,
696 unsigned int num_peers,
697 const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
698 enum GNUNET_TESTBED_TopologyOption underlay_topology,
701 GNUNET_assert (underlay_topology < GNUNET_TESTBED_TOPOLOGY_OPTION_END);
708 * Configure and run a testbed using the given
709 * master controller on 'num_hosts' starting
710 * 'num_peers' using the given peer configuration.
712 * @param controller master controller for the testbed
713 * (must not be destroyed until after the
714 * testbed is destroyed).
715 * @param num_hosts number of hosts in 'hosts', 0 to only
717 * @param hosts list of hosts to use for the testbed
718 * @param num_peers number of peers to start
719 * @param peer_cfg peer configuration template to use
720 * @param underlay_topology underlay topology to create
721 * @param ... topology-specific options
723 struct GNUNET_TESTBED_Testbed *
724 GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller,
725 unsigned int num_hosts,
726 struct GNUNET_TESTBED_Host **hosts,
727 unsigned int num_peers,
728 const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
729 enum GNUNET_TESTBED_TopologyOption underlay_topology,
732 struct GNUNET_TESTBED_Testbed *testbed;
735 va_start (vargs, underlay_topology);
736 testbed = GNUNET_TESTBED_create_va (controller, num_hosts, hosts, num_peers,
737 peer_cfg, underlay_topology, vargs);
744 * Destroy a testbed. Stops all running peers and then
745 * destroys all peers. Does NOT destroy the master controller.
747 * @param testbed testbed to destroy
750 GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
756 /* end of testbed_api_testbed.c */