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"
32 * Generic loggins shorthand
34 #define LOG(kind,...) \
35 GNUNET_log_from (kind, "testbed-api-testbed", __VA_ARGS__)
38 * Opaque handle to an abstract operation to be executed by the testing framework.
40 struct GNUNET_TESTBED_Testbed
52 * The testbed operation handle
54 struct GNUNET_TESTBED_Operation *op;
57 * Context information for GNUNET_TESTBED_run()
59 struct RunContext *rc;
67 * The next pointer for DLL
69 struct DLLOperation *next;
72 * The prev pointer for DLL
74 struct DLLOperation *prev;
79 * States of RunContext
89 * Peers have been started
112 * The controller handle
114 struct GNUNET_TESTBED_Controller *c;
117 * Handle to the host on which the controller runs
119 struct GNUNET_TESTBED_Host *h;
122 * The handle to the controller process
124 struct GNUNET_TESTBED_ControllerProc *cproc;
127 * The callback to use as controller callback
129 GNUNET_TESTBED_ControllerCallback cc;
132 * The pointer to the controller callback
137 * Master task to call when testbed initialization is done
139 GNUNET_SCHEDULER_Task master;
142 * The closure for the master task
147 * The head element of DLL operations
149 struct DLLOperation *dll_op_head;
152 * The tail element of DLL operations
154 struct DLLOperation *dll_op_tail;
157 * Array of peers which we create
159 struct GNUNET_TESTBED_Peer **peers;
162 * The event mask for the controller
167 * State of this context
172 * Current peer count for an operation; Set this to 0 and increment for each
173 * successful operation on a peer
175 unsigned int peer_count;
178 * number of peers to start
180 unsigned int num_peers;
188 * Configure and run a testbed using the given
189 * master controller on 'num_hosts' starting
190 * 'num_peers' using the given peer configuration.
192 * @param controller master controller for the testbed
193 * (must not be destroyed until after the
194 * testbed is destroyed).
195 * @param num_hosts number of hosts in 'hosts', 0 to only
197 * @param hosts list of hosts to use for the testbed
198 * @param num_peers number of peers to start
199 * @param peer_cfg peer configuration template to use
200 * @param underlay_topology underlay topology to create
201 * @param va topology-specific options
202 * @return handle to the testbed
204 struct GNUNET_TESTBED_Testbed *
205 GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller,
206 unsigned int num_hosts,
207 struct GNUNET_TESTBED_Host **hosts,
208 unsigned int num_peers,
209 const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
210 enum GNUNET_TESTBED_TopologyOption underlay_topology,
219 * Configure and run a testbed using the given
220 * master controller on 'num_hosts' starting
221 * 'num_peers' using the given peer configuration.
223 * @param controller master controller for the testbed
224 * (must not be destroyed until after the
225 * testbed is destroyed).
226 * @param num_hosts number of hosts in 'hosts', 0 to only
228 * @param hosts list of hosts to use for the testbed
229 * @param num_peers number of peers to start
230 * @param peer_cfg peer configuration template to use
231 * @param underlay_topology underlay topology to create
232 * @param ... topology-specific options
234 struct GNUNET_TESTBED_Testbed *
235 GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller,
236 unsigned int num_hosts,
237 struct GNUNET_TESTBED_Host **hosts,
238 unsigned int num_peers,
239 const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
240 enum GNUNET_TESTBED_TopologyOption underlay_topology,
249 * Destroy a testbed. Stops all running peers and then
250 * destroys all peers. Does NOT destroy the master controller.
252 * @param testbed testbed to destroy
255 GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
262 * Task for starting peers
264 * @param cls the RunHandle
265 * @param tc the task context from scheduler
268 start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
270 struct RunContext *rc = cls;
271 struct DLLOperation *dll_op;
274 LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting Peers\n");
275 for (peer = 0; peer < rc->num_peers; peer++)
277 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
278 dll_op->op = GNUNET_TESTBED_peer_start (rc->peers[peer]);
279 dll_op->cls = rc->peers[peer];
280 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
287 * Functions of this signature are called when a peer has been successfully
290 * @param cls the closure from GNUNET_TESTBED_peer_create()
291 * @param peer the handle for the created peer; NULL on any error during
293 * @param emsg NULL if peer is not NULL; else MAY contain the error description
296 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
298 struct DLLOperation *dll_op = cls;
299 struct RunContext *rc;
301 GNUNET_assert (NULL != dll_op);
303 GNUNET_assert (NULL != rc);
304 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
305 GNUNET_TESTBED_operation_done (dll_op->op);
306 GNUNET_free (dll_op);
310 LOG (GNUNET_ERROR_TYPE_WARNING, "Error while creating a peer: %s\n",
312 /* FIXME: GNUNET_TESTBED_shutdown_run()? */
315 rc->peers[rc->peer_count] = peer;
317 if (rc->peer_count < rc->num_peers)
319 LOG (GNUNET_ERROR_TYPE_DEBUG, "Required peers created successfully\n");
320 GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
325 * Assuming all peers have been destroyed cleanup run handle
327 * @param cls the run handle
328 * @param tc the task context from scheduler
331 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
333 struct RunContext *rc = cls;
334 struct DLLOperation *dll_op;
336 GNUNET_assert (NULL == rc->peers);
337 GNUNET_assert (RC_PEERS_DESTROYED == rc->state);
339 GNUNET_TESTBED_controller_disconnect (rc->c);
340 if (NULL != rc->cproc)
341 GNUNET_TESTBED_controller_stop (rc->cproc);
343 GNUNET_TESTBED_host_destroy (rc->h);
344 if (NULL != rc->dll_op_head)
346 LOG (GNUNET_ERROR_TYPE_WARNING,
347 _("Some operations are still pending. Cancelling them\n"));
348 while (NULL != (dll_op = rc->dll_op_head))
350 GNUNET_TESTBED_operation_cancel (dll_op->op);
351 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
352 GNUNET_free (dll_op);
360 * Signature of the event handler function called by the
361 * respective event controller.
364 * @param event information about the event
367 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
369 struct RunContext *rc = cls;
370 struct DLLOperation *dll_op;
371 unsigned int peer_id;
374 if ((RC_INIT != rc->state) &&
375 ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type)||
376 (GNUNET_TESTBED_ET_PEER_STOP == event->type)))
378 for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
380 if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
381 (event->details.operation_finished.operation == dll_op->op))
383 if ((GNUNET_TESTBED_ET_PEER_STOP == event->type) &&
384 (event->details.peer_stop.peer == dll_op->cls))
389 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
390 GNUNET_TESTBED_operation_done (dll_op->op);
391 GNUNET_free (dll_op);
393 if (rc->peer_count < rc->num_peers)
397 case RC_PEERS_STARTED:
398 rc->state = RC_PEERS_STOPPED;
400 for (peer_id = 0; peer_id < rc->num_peers; peer_id++)
402 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
403 dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer_id]);
404 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
408 case RC_PEERS_STOPPED:
409 rc->state = RC_PEERS_DESTROYED;
410 GNUNET_free (rc->peers);
412 LOG (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully destroyed\n");
413 GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
422 rc->cc (rc->cc_cls, event);
423 if (GNUNET_TESTBED_ET_PEER_START != event->type)
425 for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
426 if ((NULL != dll_op->cls) &&
427 (event->details.peer_start.peer == dll_op->cls))
429 GNUNET_assert (NULL != dll_op);
430 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
431 GNUNET_TESTBED_operation_done (dll_op->op);
432 GNUNET_free (dll_op);
434 if (rc->peer_count < rc->num_peers)
436 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers started successfully\n");
437 rc->state = RC_PEERS_STARTED;
438 GNUNET_SCHEDULER_add_continuation (rc->master, rc->master_cls,
439 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
445 * Callback to signal successfull startup of the controller process
447 * @param cls the closure from GNUNET_TESTBED_controller_start()
448 * @param cfg the configuration with which the controller has been started;
449 * NULL if status is not GNUNET_OK
450 * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
451 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
454 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
457 struct RunContext *rc = cls;
458 struct DLLOperation *dll_op;
461 if (status != GNUNET_OK)
463 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
466 rc->c = GNUNET_TESTBED_controller_connect (cfg, rc->h, rc->event_mask,
468 rc->peers = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *)
470 GNUNET_assert (NULL != rc->c);
472 for (peer = 0; peer < rc->num_peers; peer++)
474 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
476 dll_op->op = GNUNET_TESTBED_peer_create (rc->c, rc->h, cfg, peer_create_cb,
478 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
484 * Stops the testbed run and releases any used resources
486 * @param rc the tesbed run handle
487 * @param tc the task context from scheduler
490 shutdown_run_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
492 struct RunContext *rc = cls;
493 struct DLLOperation *dll_op;
498 if (NULL != rc->peers)
501 for (peer = 0; peer < rc->num_peers; peer++)
503 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
504 dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer]);
505 dll_op->cls = rc->peers[peer];
506 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
512 rc->state = RC_PEERS_DESTROYED; /* No peers are present so we consider the
513 state where all peers are destroyed */
514 GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
519 * Convenience method for running a testbed with
520 * a single call. Underlay and overlay topology
521 * are configured using the "UNDERLAY" and "OVERLAY"
522 * options in the "[testbed]" section of the configuration\
523 * (with possible options given in "UNDERLAY_XXX" and/or
526 * The testbed is to be terminated using a call to
527 * "GNUNET_SCHEDULER_shutdown".
529 * @param host_filename name of the file with the 'hosts', NULL
530 * to run everything on 'localhost'
531 * @param cfg configuration to use (for testbed, controller and peers)
532 * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
533 * @param event_mask bit mask with set of events to call 'cc' for;
534 * or-ed values of "1LL" shifted by the
535 * respective 'enum GNUNET_TESTBED_EventType'
536 * (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
537 * @param cc controller callback to invoke on events
538 * @param cc_cls closure for cc
539 * @param master task to run once the testbed is ready
542 GNUNET_TESTBED_run (const char *host_filename,
543 const struct GNUNET_CONFIGURATION_Handle *cfg,
544 unsigned int num_peers,
546 GNUNET_TESTBED_ControllerCallback cc,
548 GNUNET_SCHEDULER_Task master,
551 struct RunContext *rc;
553 event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
554 rc = GNUNET_malloc (sizeof (struct RunContext));
555 GNUNET_break (NULL == host_filename); /* Currently we do not support host
557 host_filename = NULL;
558 rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
559 GNUNET_assert (NULL != rc->h);
560 rc->cproc = GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, cfg,
561 &controller_status_cb, rc);
562 GNUNET_assert (NULL != rc->cproc);
563 rc->num_peers = num_peers;
564 rc->event_mask = event_mask;
568 rc->master_cls = master_cls;
570 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
571 &shutdown_run_task, rc);
574 /* end of testbed_api_testbed.c */