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 (NULL, 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 /* Check if some peers are stopped */
432 for (peer = 0; peer < rc->num_peers; peer++)
434 if (PS_STOPPED != rc->peers[peer]->state)
437 if (peer == rc->num_peers)
439 /* All peers are stopped */
440 rc->state = RC_PEERS_STOPPED;
441 for (peer = 0; peer < rc->num_peers; peer++)
443 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
444 dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer]);
445 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
450 /* Some peers are stopped */
451 for (peer = 0; peer < rc->num_peers; peer++)
453 if (PS_STARTED != rc->peers[peer]->state)
458 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
459 dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer], NULL, NULL);
460 dll_op->cls = rc->peers[peer];
461 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
464 if (rc->peer_count != rc->num_peers)
468 rc->state = RC_PEERS_DESTROYED; /* No peers are present so we consider the
469 * state where all peers are destroyed */
470 GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
475 * Convenience method for running a testbed with
476 * a single call. Underlay and overlay topology
477 * are configured using the "UNDERLAY" and "OVERLAY"
478 * options in the "[testbed]" section of the configuration\
479 * (with possible options given in "UNDERLAY_XXX" and/or
482 * The testbed is to be terminated using a call to
483 * "GNUNET_SCHEDULER_shutdown".
485 * @param host_filename name of the file with the 'hosts', NULL
486 * to run everything on 'localhost'
487 * @param cfg configuration to use (for testbed, controller and peers)
488 * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
489 * @param event_mask bit mask with set of events to call 'cc' for;
490 * or-ed values of "1LL" shifted by the
491 * respective 'enum GNUNET_TESTBED_EventType'
492 * (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
493 * @param cc controller callback to invoke on events; This callback is called
494 * for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
495 * set in the event_mask as this is the only way get access to the
496 * handle of each peer
497 * @param cc_cls closure for cc
498 * @param master task to run once the testbed is ready
502 GNUNET_TESTBED_run (const char *host_filename,
503 const struct GNUNET_CONFIGURATION_Handle *cfg,
504 unsigned int num_peers, uint64_t event_mask,
505 GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
506 GNUNET_SCHEDULER_Task master, void *master_cls)
508 struct RunContext *rc;
510 GNUNET_break (NULL == host_filename); /* Currently we do not support host
512 GNUNET_assert (NULL != cc);
513 GNUNET_assert (num_peers > 0);
514 host_filename = NULL;
515 rc = GNUNET_malloc (sizeof (struct RunContext));
516 rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
517 GNUNET_assert (NULL != rc->h);
519 GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, cfg,
520 &controller_status_cb, rc);
521 GNUNET_assert (NULL != rc->cproc);
522 rc->num_peers = num_peers;
523 rc->event_mask = event_mask;
524 rc->event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
528 rc->master_cls = master_cls;
530 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
531 &shutdown_run_task, rc);
536 * Configure and run a testbed using the given
537 * master controller on 'num_hosts' starting
538 * 'num_peers' using the given peer configuration.
540 * @param controller master controller for the testbed
541 * (must not be destroyed until after the
542 * testbed is destroyed).
543 * @param num_hosts number of hosts in 'hosts', 0 to only
545 * @param hosts list of hosts to use for the testbed
546 * @param num_peers number of peers to start
547 * @param peer_cfg peer configuration template to use
548 * @param underlay_topology underlay topology to create
549 * @param va topology-specific options
550 * @return handle to the testbed
552 struct GNUNET_TESTBED_Testbed *
553 GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller,
554 unsigned int num_hosts,
555 struct GNUNET_TESTBED_Host **hosts,
556 unsigned int num_peers,
557 const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
558 enum GNUNET_TESTBED_TopologyOption underlay_topology,
567 * Configure and run a testbed using the given
568 * master controller on 'num_hosts' starting
569 * 'num_peers' using the given peer configuration.
571 * @param controller master controller for the testbed
572 * (must not be destroyed until after the
573 * testbed is destroyed).
574 * @param num_hosts number of hosts in 'hosts', 0 to only
576 * @param hosts list of hosts to use for the testbed
577 * @param num_peers number of peers to start
578 * @param peer_cfg peer configuration template to use
579 * @param underlay_topology underlay topology to create
580 * @param ... topology-specific options
582 struct GNUNET_TESTBED_Testbed *
583 GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller,
584 unsigned int num_hosts,
585 struct GNUNET_TESTBED_Host **hosts,
586 unsigned int num_peers,
587 const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
588 enum GNUNET_TESTBED_TopologyOption underlay_topology,
597 * Destroy a testbed. Stops all running peers and then
598 * destroys all peers. Does NOT destroy the master controller.
600 * @param testbed testbed to destroy
603 GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
609 /* end of testbed_api_testbed.c */