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
111 * The controller handle
113 struct GNUNET_TESTBED_Controller *c;
116 * Handle to the host on which the controller runs
118 struct GNUNET_TESTBED_Host *h;
121 * The handle to the controller process
123 struct GNUNET_TESTBED_ControllerProc *cproc;
126 * The callback to use as controller callback
128 GNUNET_TESTBED_ControllerCallback cc;
131 * The pointer to the controller callback
136 * Master task to call when testbed initialization is done
138 GNUNET_SCHEDULER_Task master;
141 * The closure for the master task
146 * The head element of DLL operations
148 struct DLLOperation *dll_op_head;
151 * The tail element of DLL operations
153 struct DLLOperation *dll_op_tail;
156 * Array of peers which we create
158 struct GNUNET_TESTBED_Peer **peers;
161 * The event mask for the controller
166 * State of this context
171 * Current peer count for an operation; Set this to 0 and increment for each
172 * successful operation on a peer
174 unsigned int peer_count;
177 * number of peers to start
179 unsigned int num_peers;
187 * Configure and run a testbed using the given
188 * master controller on 'num_hosts' starting
189 * 'num_peers' using the given peer configuration.
191 * @param controller master controller for the testbed
192 * (must not be destroyed until after the
193 * testbed is destroyed).
194 * @param num_hosts number of hosts in 'hosts', 0 to only
196 * @param hosts list of hosts to use for the testbed
197 * @param num_peers number of peers to start
198 * @param peer_cfg peer configuration template to use
199 * @param underlay_topology underlay topology to create
200 * @param va topology-specific options
201 * @return handle to the testbed
203 struct GNUNET_TESTBED_Testbed *
204 GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller,
205 unsigned int num_hosts,
206 struct GNUNET_TESTBED_Host **hosts,
207 unsigned int num_peers,
208 const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
209 enum GNUNET_TESTBED_TopologyOption underlay_topology,
218 * Configure and run a testbed using the given
219 * master controller on 'num_hosts' starting
220 * 'num_peers' using the given peer configuration.
222 * @param controller master controller for the testbed
223 * (must not be destroyed until after the
224 * testbed is destroyed).
225 * @param num_hosts number of hosts in 'hosts', 0 to only
227 * @param hosts list of hosts to use for the testbed
228 * @param num_peers number of peers to start
229 * @param peer_cfg peer configuration template to use
230 * @param underlay_topology underlay topology to create
231 * @param ... topology-specific options
233 struct GNUNET_TESTBED_Testbed *
234 GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller,
235 unsigned int num_hosts,
236 struct GNUNET_TESTBED_Host **hosts,
237 unsigned int num_peers,
238 const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
239 enum GNUNET_TESTBED_TopologyOption underlay_topology,
248 * Destroy a testbed. Stops all running peers and then
249 * destroys all peers. Does NOT destroy the master controller.
251 * @param testbed testbed to destroy
254 GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
261 * Task for starting peers
263 * @param cls the RunHandle
264 * @param tc the task context from scheduler
267 start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
269 struct RunContext *rc = cls;
270 struct DLLOperation *dll_op;
273 LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting Peers\n");
274 for (peer = 0; peer < rc->num_peers; peer++)
276 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
277 dll_op->op = GNUNET_TESTBED_peer_start (rc->peers[peer]);
278 dll_op->cls = rc->peers[peer];
279 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
286 * Functions of this signature are called when a peer has been successfully
289 * @param cls the closure from GNUNET_TESTBED_peer_create()
290 * @param peer the handle for the created peer; NULL on any error during
292 * @param emsg NULL if peer is not NULL; else MAY contain the error description
295 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
297 struct DLLOperation *dll_op = cls;
298 struct RunContext *rc;
300 GNUNET_assert (NULL != dll_op);
302 GNUNET_assert (NULL != rc);
303 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
304 GNUNET_TESTBED_operation_done (dll_op->op);
305 GNUNET_free (dll_op);
309 LOG (GNUNET_ERROR_TYPE_WARNING, "Error while creating a peer: %s\n",
311 /* FIXME: GNUNET_TESTBED_shutdown_run()? */
314 rc->peers[rc->peer_count] = peer;
316 if (rc->peer_count < rc->num_peers)
318 LOG (GNUNET_ERROR_TYPE_DEBUG, "Required peers created successfully\n");
319 GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
324 * Assuming all peers have been destroyed cleanup run handle
326 * @param cls the run handle
327 * @param tc the task context from scheduler
330 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
332 struct RunContext *rc = cls;
333 struct DLLOperation *dll_op;
335 GNUNET_assert (NULL == rc->peers);
336 GNUNET_assert (RC_PEERS_DESTROYED == rc->state);
338 GNUNET_TESTBED_controller_disconnect (rc->c);
339 if (NULL != rc->cproc)
340 GNUNET_TESTBED_controller_stop (rc->cproc);
342 GNUNET_TESTBED_host_destroy (rc->h);
343 if (NULL != rc->dll_op_head)
345 LOG (GNUNET_ERROR_TYPE_WARNING,
346 _("Some operations are still pending. Cancelling them\n"));
347 while (NULL != (dll_op = rc->dll_op_head))
349 GNUNET_TESTBED_operation_cancel (dll_op->op);
350 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
351 GNUNET_free (dll_op);
359 * Signature of the event handler function called by the
360 * respective event controller.
363 * @param event information about the event
366 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
368 struct RunContext *rc = cls;
369 struct DLLOperation *dll_op;
370 unsigned int peer_id;
373 if ((RC_INIT != rc->state) &&
374 ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) ||
375 (GNUNET_TESTBED_ET_PEER_STOP == event->type)))
377 for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
379 if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
380 (event->details.operation_finished.operation == dll_op->op))
382 if ((GNUNET_TESTBED_ET_PEER_STOP == event->type) &&
383 (event->details.peer_stop.peer == dll_op->cls))
388 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
389 GNUNET_TESTBED_operation_done (dll_op->op);
390 GNUNET_free (dll_op);
392 if (rc->peer_count < rc->num_peers)
396 case RC_PEERS_STARTED:
397 rc->state = RC_PEERS_STOPPED;
399 for (peer_id = 0; peer_id < rc->num_peers; peer_id++)
401 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
402 dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer_id]);
403 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
407 case RC_PEERS_STOPPED:
408 rc->state = RC_PEERS_DESTROYED;
409 GNUNET_free (rc->peers);
411 LOG (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully destroyed\n");
412 GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
421 rc->cc (rc->cc_cls, event);
422 if (GNUNET_TESTBED_ET_PEER_START != event->type)
424 for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
425 if ((NULL != dll_op->cls) &&
426 (event->details.peer_start.peer == dll_op->cls))
428 GNUNET_assert (NULL != dll_op);
429 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
430 GNUNET_TESTBED_operation_done (dll_op->op);
431 GNUNET_free (dll_op);
433 if (rc->peer_count < rc->num_peers)
435 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers started successfully\n");
436 rc->state = RC_PEERS_STARTED;
437 GNUNET_SCHEDULER_add_continuation (rc->master, rc->master_cls,
438 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
444 * Callback to signal successfull startup of the controller process
446 * @param cls the closure from GNUNET_TESTBED_controller_start()
447 * @param cfg the configuration with which the controller has been started;
448 * NULL if status is not GNUNET_OK
449 * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
450 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
453 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
456 struct RunContext *rc = cls;
457 struct DLLOperation *dll_op;
460 if (status != GNUNET_OK)
462 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
466 GNUNET_TESTBED_controller_connect (cfg, rc->h, rc->event_mask, &event_cb,
469 GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
470 GNUNET_assert (NULL != rc->c);
472 for (peer = 0; peer < rc->num_peers; peer++)
474 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
477 GNUNET_TESTBED_peer_create (rc->c, rc->h, cfg, peer_create_cb, dll_op);
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, uint64_t event_mask,
545 GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
546 GNUNET_SCHEDULER_Task master, void *master_cls)
548 struct RunContext *rc;
550 event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
551 rc = GNUNET_malloc (sizeof (struct RunContext));
552 GNUNET_break (NULL == host_filename); /* Currently we do not support host
554 host_filename = NULL;
555 rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
556 GNUNET_assert (NULL != rc->h);
558 GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, cfg,
559 &controller_status_cb, rc);
560 GNUNET_assert (NULL != rc->cproc);
561 rc->num_peers = num_peers;
562 rc->event_mask = event_mask;
566 rc->master_cls = master_cls;
568 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
569 &shutdown_run_task, rc);
572 /* end of testbed_api_testbed.c */