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 * Peers have been started
100 * Peers are destroyed
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;
186 * Task for starting peers
188 * @param cls the RunHandle
189 * @param tc the task context from scheduler
192 start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
194 struct RunContext *rc = cls;
195 struct DLLOperation *dll_op;
198 LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting Peers\n");
199 for (peer = 0; peer < rc->num_peers; peer++)
201 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
202 dll_op->op = GNUNET_TESTBED_peer_start (rc->peers[peer], NULL, NULL);
203 dll_op->cls = rc->peers[peer];
204 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
211 * Functions of this signature are called when a peer has been successfully
214 * @param cls the closure from GNUNET_TESTBED_peer_create()
215 * @param peer the handle for the created peer; NULL on any error during
217 * @param emsg NULL if peer is not NULL; else MAY contain the error description
220 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
222 struct DLLOperation *dll_op = cls;
223 struct RunContext *rc;
225 GNUNET_assert (NULL != dll_op);
227 GNUNET_assert (NULL != rc);
228 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
229 GNUNET_TESTBED_operation_done (dll_op->op);
230 GNUNET_free (dll_op);
234 LOG (GNUNET_ERROR_TYPE_WARNING, "Error while creating a peer: %s\n",
236 /* FIXME: GNUNET_TESTBED_shutdown_run()? */
239 rc->peers[rc->peer_count] = peer;
241 if (rc->peer_count < rc->num_peers)
243 LOG (GNUNET_ERROR_TYPE_DEBUG, "Required peers created successfully\n");
244 GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
249 * Assuming all peers have been destroyed cleanup run handle
251 * @param cls the run handle
252 * @param tc the task context from scheduler
255 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
257 struct RunContext *rc = cls;
258 struct DLLOperation *dll_op;
260 GNUNET_assert (NULL == rc->peers);
261 GNUNET_assert (RC_PEERS_DESTROYED == rc->state);
263 GNUNET_TESTBED_controller_disconnect (rc->c);
264 if (NULL != rc->cproc)
265 GNUNET_TESTBED_controller_stop (rc->cproc);
267 GNUNET_TESTBED_host_destroy (rc->h);
268 if (NULL != rc->dll_op_head)
270 LOG (GNUNET_ERROR_TYPE_WARNING,
271 _("Some operations are still pending. Cancelling them\n"));
272 while (NULL != (dll_op = rc->dll_op_head))
274 GNUNET_TESTBED_operation_cancel (dll_op->op);
275 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
276 GNUNET_free (dll_op);
284 * Signature of the event handler function called by the
285 * respective event controller.
288 * @param event information about the event
291 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
293 struct RunContext *rc = cls;
294 struct DLLOperation *dll_op;
295 unsigned int peer_id;
298 if ((RC_INIT != rc->state) &&
299 ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) ||
300 (GNUNET_TESTBED_ET_PEER_STOP == event->type)))
302 for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
304 if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
305 (event->details.operation_finished.operation == dll_op->op))
307 if ((GNUNET_TESTBED_ET_PEER_STOP == event->type) &&
308 (event->details.peer_stop.peer == dll_op->cls))
313 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
314 GNUNET_TESTBED_operation_done (dll_op->op);
315 GNUNET_free (dll_op);
317 if (rc->peer_count < rc->num_peers)
321 case RC_PEERS_STARTED:
322 rc->state = RC_PEERS_STOPPED;
324 for (peer_id = 0; peer_id < rc->num_peers; peer_id++)
326 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
327 dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer_id]);
328 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
332 case RC_PEERS_STOPPED:
333 rc->state = RC_PEERS_DESTROYED;
334 GNUNET_free (rc->peers);
336 LOG (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully destroyed\n");
337 GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
346 if ((0 != (rc->event_mask && (1LL << event->type))) && (NULL != rc->cc))
347 rc->cc (rc->cc_cls, event);
348 if (GNUNET_TESTBED_ET_PEER_START != event->type)
350 for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
351 if ((NULL != dll_op->cls) &&
352 (event->details.peer_start.peer == dll_op->cls))
354 GNUNET_assert (NULL != dll_op);
355 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
356 GNUNET_TESTBED_operation_done (dll_op->op);
357 GNUNET_free (dll_op);
359 if (rc->peer_count < rc->num_peers)
361 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers started successfully\n");
362 rc->state = RC_PEERS_STARTED;
363 if (NULL != rc->master)
364 GNUNET_SCHEDULER_add_continuation (rc->master, rc->master_cls,
365 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
371 * Callback to signal successfull startup of the controller process
373 * @param cls the closure from GNUNET_TESTBED_controller_start()
374 * @param cfg the configuration with which the controller has been started;
375 * NULL if status is not GNUNET_OK
376 * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
377 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
380 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
383 struct RunContext *rc = cls;
384 struct DLLOperation *dll_op;
388 if (status != GNUNET_OK)
390 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
393 event_mask = rc->event_mask;
394 event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
395 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
397 GNUNET_TESTBED_controller_connect (cfg, rc->h, event_mask, &event_cb, rc);
399 GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
400 GNUNET_assert (NULL != rc->c);
402 for (peer = 0; peer < rc->num_peers; peer++)
404 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
407 GNUNET_TESTBED_peer_create (rc->c, rc->h, cfg, peer_create_cb, dll_op);
408 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
414 * Stops the testbed run and releases any used resources
416 * @param cls the tesbed run handle
417 * @param tc the task context from scheduler
420 shutdown_run_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
422 struct RunContext *rc = cls;
423 struct DLLOperation *dll_op;
428 if (NULL != rc->peers)
431 for (peer = 0; peer < rc->num_peers; peer++)
433 if (PS_STARTED != rc->peers[peer]->state)
438 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
439 dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer], NULL, NULL);
440 dll_op->cls = rc->peers[peer];
441 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
444 if (rc->peer_count != rc->num_peers)
448 rc->state = RC_PEERS_DESTROYED; /* No peers are present so we consider the
449 * state where all peers are destroyed */
450 GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
455 * Convenience method for running a testbed with
456 * a single call. Underlay and overlay topology
457 * are configured using the "UNDERLAY" and "OVERLAY"
458 * options in the "[testbed]" section of the configuration\
459 * (with possible options given in "UNDERLAY_XXX" and/or
462 * The testbed is to be terminated using a call to
463 * "GNUNET_SCHEDULER_shutdown".
465 * @param host_filename name of the file with the 'hosts', NULL
466 * to run everything on 'localhost'
467 * @param cfg configuration to use (for testbed, controller and peers)
468 * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
469 * @param event_mask bit mask with set of events to call 'cc' for;
470 * or-ed values of "1LL" shifted by the
471 * respective 'enum GNUNET_TESTBED_EventType'
472 * (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
473 * @param cc controller callback to invoke on events; This callback is called
474 * for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
475 * set in the event_mask as this is the only way get access to the
476 * handle of each peer
477 * @param cc_cls closure for cc
478 * @param master task to run once the testbed is ready
482 GNUNET_TESTBED_run (const char *host_filename,
483 const struct GNUNET_CONFIGURATION_Handle *cfg,
484 unsigned int num_peers, uint64_t event_mask,
485 GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
486 GNUNET_SCHEDULER_Task master, void *master_cls)
488 struct RunContext *rc;
490 GNUNET_break (NULL == host_filename); /* Currently we do not support host
492 GNUNET_assert (NULL != cc);
493 GNUNET_assert (num_peers > 0);
494 host_filename = NULL;
495 rc = GNUNET_malloc (sizeof (struct RunContext));
496 rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
497 GNUNET_assert (NULL != rc->h);
499 GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, cfg,
500 &controller_status_cb, rc);
501 GNUNET_assert (NULL != rc->cproc);
502 rc->num_peers = num_peers;
503 rc->event_mask = event_mask;
504 rc->event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
508 rc->master_cls = master_cls;
510 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
511 &shutdown_run_task, rc);
516 * Configure and run a testbed using the given
517 * master controller on 'num_hosts' starting
518 * 'num_peers' using the given peer configuration.
520 * @param controller master controller for the testbed
521 * (must not be destroyed until after the
522 * testbed is destroyed).
523 * @param num_hosts number of hosts in 'hosts', 0 to only
525 * @param hosts list of hosts to use for the testbed
526 * @param num_peers number of peers to start
527 * @param peer_cfg peer configuration template to use
528 * @param underlay_topology underlay topology to create
529 * @param va topology-specific options
530 * @return handle to the testbed
532 struct GNUNET_TESTBED_Testbed *
533 GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller,
534 unsigned int num_hosts,
535 struct GNUNET_TESTBED_Host **hosts,
536 unsigned int num_peers,
537 const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
538 enum GNUNET_TESTBED_TopologyOption underlay_topology,
547 * Configure and run a testbed using the given
548 * master controller on 'num_hosts' starting
549 * 'num_peers' using the given peer configuration.
551 * @param controller master controller for the testbed
552 * (must not be destroyed until after the
553 * testbed is destroyed).
554 * @param num_hosts number of hosts in 'hosts', 0 to only
556 * @param hosts list of hosts to use for the testbed
557 * @param num_peers number of peers to start
558 * @param peer_cfg peer configuration template to use
559 * @param underlay_topology underlay topology to create
560 * @param ... topology-specific options
562 struct GNUNET_TESTBED_Testbed *
563 GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller,
564 unsigned int num_hosts,
565 struct GNUNET_TESTBED_Host **hosts,
566 unsigned int num_peers,
567 const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
568 enum GNUNET_TESTBED_TopologyOption underlay_topology,
577 * Destroy a testbed. Stops all running peers and then
578 * destroys all peers. Does NOT destroy the master controller.
580 * @param testbed testbed to destroy
583 GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
589 /* end of testbed_api_testbed.c */