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;
84 * The controller handle
86 struct GNUNET_TESTBED_Controller *c;
89 * Handle to the host on which the controller runs
91 struct GNUNET_TESTBED_Host *h;
94 * The handle to the controller process
96 struct GNUNET_TESTBED_ControllerProc *cproc;
99 * The callback to use as controller callback
101 GNUNET_TESTBED_ControllerCallback cc;
104 * The pointer to the controller callback
109 * Master task to call when testbed initialization is done
111 GNUNET_SCHEDULER_Task master;
114 * The closure for the master task
119 * The head element of DLL operations
121 struct DLLOperation *dll_op_head;
124 * The tail element of DLL operations
126 struct DLLOperation *dll_op_tail;
129 * Array of peers which we create
131 struct GNUNET_TESTBED_Peer **peers;
134 * The event mask for the controller
139 * Current peer count for an operation; Set this to 0 and increment for each
140 * successful operation on a peer
142 unsigned int peer_count;
145 * number of peers to start
147 unsigned int num_peers;
150 * Are we cleaning up?
160 * Configure and run a testbed using the given
161 * master controller on 'num_hosts' starting
162 * 'num_peers' using the given peer configuration.
164 * @param controller master controller for the testbed
165 * (must not be destroyed until after the
166 * testbed is destroyed).
167 * @param num_hosts number of hosts in 'hosts', 0 to only
169 * @param hosts list of hosts to use for the testbed
170 * @param num_peers number of peers to start
171 * @param peer_cfg peer configuration template to use
172 * @param underlay_topology underlay topology to create
173 * @param va topology-specific options
174 * @return handle to the testbed
176 struct GNUNET_TESTBED_Testbed *
177 GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller,
178 unsigned int num_hosts,
179 struct GNUNET_TESTBED_Host **hosts,
180 unsigned int num_peers,
181 const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
182 enum GNUNET_TESTBED_TopologyOption underlay_topology,
191 * Configure and run a testbed using the given
192 * master controller on 'num_hosts' starting
193 * 'num_peers' using the given peer configuration.
195 * @param controller master controller for the testbed
196 * (must not be destroyed until after the
197 * testbed is destroyed).
198 * @param num_hosts number of hosts in 'hosts', 0 to only
200 * @param hosts list of hosts to use for the testbed
201 * @param num_peers number of peers to start
202 * @param peer_cfg peer configuration template to use
203 * @param underlay_topology underlay topology to create
204 * @param ... topology-specific options
206 struct GNUNET_TESTBED_Testbed *
207 GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller,
208 unsigned int num_hosts,
209 struct GNUNET_TESTBED_Host **hosts,
210 unsigned int num_peers,
211 const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
212 enum GNUNET_TESTBED_TopologyOption underlay_topology,
221 * Destroy a testbed. Stops all running peers and then
222 * destroys all peers. Does NOT destroy the master controller.
224 * @param testbed testbed to destroy
227 GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
234 * Task for starting peers
236 * @param cls the RunHandle
237 * @param tc the task context from scheduler
240 start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
242 struct RunContext *rc = cls;
243 struct DLLOperation *dll_op;
246 LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting Peers\n");
247 for (peer = 0; peer < rc->num_peers; peer++)
249 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
250 dll_op->op = GNUNET_TESTBED_peer_start (rc->peers[peer]);
251 dll_op->cls = rc->peers[peer];
252 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
259 * Functions of this signature are called when a peer has been successfully
262 * @param cls the closure from GNUNET_TESTBED_peer_create()
263 * @param peer the handle for the created peer; NULL on any error during
265 * @param emsg NULL if peer is not NULL; else MAY contain the error description
268 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
270 struct DLLOperation *dll_op = cls;
271 struct RunContext *rc;
273 GNUNET_assert (NULL != dll_op);
275 GNUNET_assert (NULL != rc);
276 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
277 GNUNET_TESTBED_operation_done (dll_op->op);
278 GNUNET_free (dll_op);
282 LOG (GNUNET_ERROR_TYPE_WARNING, "Error while creating a peer: %s\n",
284 /* FIXME: GNUNET_TESTBED_shutdown_run()? */
287 rc->peers[rc->peer_count] = peer;
289 if (rc->peer_count < rc->num_peers)
291 LOG (GNUNET_ERROR_TYPE_DEBUG, "Required peers created successfully\n");
292 GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
297 * Assuming all peers have been destroyed cleanup run handle
299 * @param cls the run handle
300 * @param tc the task context from scheduler
303 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
305 struct RunContext *rc = cls;
306 struct DLLOperation *dll_op;
308 GNUNET_assert (NULL == rc->peers);
310 GNUNET_TESTBED_controller_disconnect (rc->c);
311 if (NULL != rc->cproc)
312 GNUNET_TESTBED_controller_stop (rc->cproc);
314 GNUNET_TESTBED_host_destroy (rc->h);
315 if (NULL != rc->dll_op_head)
317 LOG (GNUNET_ERROR_TYPE_WARNING,
318 _("Some operations are still pending. Cancelling them\n"));
319 while (NULL != (dll_op = rc->dll_op_head))
321 GNUNET_TESTBED_operation_cancel (dll_op->op);
322 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
323 GNUNET_free (dll_op);
331 * Signature of the event handler function called by the
332 * respective event controller.
335 * @param event information about the event
338 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
340 struct RunContext *rc = cls;
341 struct DLLOperation *dll_op;
343 if ((GNUNET_YES == rc->in_shutdown) &&
344 (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type))
346 for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
348 if (event->details.operation_finished.operation == dll_op->op)
353 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
354 GNUNET_TESTBED_operation_done (dll_op->op);
355 GNUNET_free (dll_op);
357 if (rc->peer_count < rc->num_peers)
359 GNUNET_free (rc->peers);
361 LOG (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully destroyed\n");
362 GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
367 rc->cc (rc->cc_cls, event);
368 if (GNUNET_TESTBED_ET_PEER_START != event->type)
370 for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
371 if ((NULL != dll_op->cls) &&
372 (event->details.peer_start.peer == dll_op->cls))
374 GNUNET_assert (NULL != dll_op);
375 GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
376 GNUNET_TESTBED_operation_done (dll_op->op);
377 GNUNET_free (dll_op);
379 if (rc->peer_count < rc->num_peers)
381 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers started successfully\n");
382 GNUNET_SCHEDULER_add_continuation (rc->master, rc->master_cls,
383 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
389 * Callback to signal successfull startup of the controller process
391 * @param cls the closure from GNUNET_TESTBED_controller_start()
392 * @param cfg the configuration with which the controller has been started;
393 * NULL if status is not GNUNET_OK
394 * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
395 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
398 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
401 struct RunContext *rc = cls;
402 struct DLLOperation *dll_op;
405 if (status != GNUNET_OK)
407 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
410 rc->c = GNUNET_TESTBED_controller_connect (cfg, rc->h, rc->event_mask,
412 rc->peers = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *)
414 GNUNET_assert (NULL != rc->c);
416 for (peer = 0; peer < rc->num_peers; peer++)
418 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
420 dll_op->op = GNUNET_TESTBED_peer_create (rc->c, rc->h, cfg, peer_create_cb,
422 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
428 * Stops the testbed run and releases any used resources
430 * @param rc the tesbed run handle
431 * @param tc the task context from scheduler
434 shutdown_run_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
436 struct RunContext *rc = cls;
437 struct DLLOperation *dll_op;
440 rc->in_shutdown = GNUNET_YES;
443 if (NULL != rc->peers)
446 for (peer = 0; peer < rc->num_peers; peer++)
448 dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
449 dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer]);
450 GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
456 GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
461 * Convenience method for running a testbed with
462 * a single call. Underlay and overlay topology
463 * are configured using the "UNDERLAY" and "OVERLAY"
464 * options in the "[testbed]" section of the configuration\
465 * (with possible options given in "UNDERLAY_XXX" and/or
468 * The testbed is to be terminated using a call to
469 * "GNUNET_SCHEDULER_shutdown".
471 * @param host_filename name of the file with the 'hosts', NULL
472 * to run everything on 'localhost'
473 * @param cfg configuration to use (for testbed, controller and peers)
474 * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
475 * @param event_mask bit mask with set of events to call 'cc' for;
476 * or-ed values of "1LL" shifted by the
477 * respective 'enum GNUNET_TESTBED_EventType'
478 * (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
479 * @param cc controller callback to invoke on events
480 * @param cc_cls closure for cc
481 * @param master task to run once the testbed is ready
484 GNUNET_TESTBED_run (const char *host_filename,
485 const struct GNUNET_CONFIGURATION_Handle *cfg,
486 unsigned int num_peers,
488 GNUNET_TESTBED_ControllerCallback cc,
490 GNUNET_SCHEDULER_Task master,
493 struct RunContext *rc;
495 event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
496 rc = GNUNET_malloc (sizeof (struct RunContext));
497 GNUNET_break (NULL == host_filename); /* Currently we do not support host
499 host_filename = NULL;
500 rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
501 GNUNET_assert (NULL != rc->h);
502 rc->cproc = GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, cfg,
503 &controller_status_cb, rc);
504 GNUNET_assert (NULL != rc->cproc);
505 rc->num_peers = num_peers;
506 rc->event_mask = event_mask;
510 rc->master_cls = master_cls;
511 rc->in_shutdown = GNUNET_NO;
512 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
513 &shutdown_run_task, rc);
516 /* end of testbed_api_testbed.c */