2 This file is part of GNUnet
3 (C) 2008--2013 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_util_lib.h"
30 #include "gnunet_testbed_service.h"
31 #include "testbed_api_peers.h"
32 #include "testbed_api_hosts.h"
33 #include "testbed_api_topology.h"
36 * Generic loggins shorthand
38 #define LOG(kind,...) \
39 GNUNET_log_from (kind, "testbed-api-testbed", __VA_ARGS__)
42 * Debug logging shortcut
45 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
48 * The default setup timeout in seconds
50 #define DEFAULT_SETUP_TIMEOUT 300
58 * Context information for the operation we start
60 struct RunContextOperation
63 * The testbed operation handle
65 struct GNUNET_TESTBED_Operation *op;
68 * Context information for GNUNET_TESTBED_run()
70 struct RunContext *rc;
81 * States of RunContext
91 * Controllers on given hosts started and linked
101 * The testbed run is ready and the master callback can be called now. At this
102 * time the peers are all started and if a topology is provided in the
103 * configuration the topology would have been attempted
108 /* * Peers are stopped */
110 /* RC_PEERS_STOPPED, */
113 /* * Peers are destroyed */
115 /* RC_PEERS_DESTROYED */
118 * All peers shutdown (stopped and destroyed)
125 * Context for host compability checks
127 struct CompatibilityCheckContext
132 struct RunContext *rc;
135 * Handle for the compability check
137 struct GNUNET_TESTBED_HostHabitableCheckHandle *h;
140 * Index of the host in the run context's hosts array
152 * The controller handle
154 struct GNUNET_TESTBED_Controller *c;
157 * The configuration of the controller. This is based on the cfg given to the
158 * function GNUNET_TESTBED_run(). We also use this config as a template while
161 struct GNUNET_CONFIGURATION_Handle *cfg;
164 * Handle to the host on which the controller runs
166 struct GNUNET_TESTBED_Host *h;
169 * The handle to the controller process
171 struct GNUNET_TESTBED_ControllerProc *cproc;
174 * The callback to use as controller callback
176 GNUNET_TESTBED_ControllerCallback cc;
179 * The pointer to the controller callback
184 * The trusted IP string
189 * TestMaster callback to call when testbed initialization is done
191 GNUNET_TESTBED_TestMaster test_master;
194 * The closure for the TestMaster callback
196 void *test_master_cls;
199 * A hashmap for operations started by us
201 struct GNUNET_CONTAINER_MultiHashMap32 *rcop_map;
204 * An array of hosts loaded from the hostkeys file
206 struct GNUNET_TESTBED_Host **hosts;
209 * Array of compatibility check contexts
211 struct CompatibilityCheckContext *hclist;
214 * Array of peers which we create
216 struct GNUNET_TESTBED_Peer **peers;
219 * The topology generation operation. Will be null if no topology is set in
222 struct GNUNET_TESTBED_Operation *topology_operation;
225 * The file containing topology data. Only used if the topology is set to 'FROM_FILE'
230 * Host registration handle
232 struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
235 * Profiling start time
237 struct GNUNET_TIME_Absolute pstart_time;
240 * Host registration task
242 GNUNET_SCHEDULER_TaskIdentifier register_hosts_task;
245 * Task to be run while shutting down
247 GNUNET_SCHEDULER_TaskIdentifier shutdown_run_task;
250 * Task to be run of a timeout
252 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
255 * Task run upon shutdown interrupts
257 GNUNET_SCHEDULER_TaskIdentifier interrupt_task;
260 * The event mask for the controller
265 * State of this context
270 * The topology which has to be achieved with the peers started in this context
272 enum GNUNET_TESTBED_TopologyOption topology;
275 * Have we already shutdown
280 * Number of hosts in the given host file
282 unsigned int num_hosts;
285 * Number of registered hosts. Also used as a counter while checking
286 * habitabillity of hosts
288 unsigned int reg_hosts;
291 * Current peer count for an operation; Set this to 0 and increment for each
292 * successful operation on a peer
294 unsigned int peer_count;
297 * number of peers to start
299 unsigned int num_peers;
302 * Expected overlay connects. Should be zero if no topology is relavant
307 * Number of random links to established
309 unsigned int random_links;
312 * the number of overlay link connection attempts that succeeded
314 unsigned int links_succeeded;
317 * the number of overlay link connection attempts that failed
319 unsigned int links_failed;
325 * Return a 32-bit key from a pointer
327 * @param rcop the pointer
331 rcop_key (void *rcop)
333 return * ((uint32_t *) &rcop);
338 * Context information used for finding a pointer in the rcop_map
343 * The operation pointer to look for
345 struct GNUNET_TESTBED_Operation *query;
348 * The Run context operation which has the operation being queried
350 struct RunContextOperation *result;
355 * Iterator for searching over the elements matching a given query
357 * @param cls the SearchContext
358 * @param key the 32-bit key
359 * @param value the RunContextOperation element
360 * @return GNUNET_YES to continue iteration; GNUNET_NO to cancel it
363 search_iterator (void *cls, uint32_t key, void *value)
365 struct RunContextOperation *rcop = value;
366 struct SearchContext *sc = cls;
368 GNUNET_assert (NULL != rcop);
369 if (sc->query == rcop->op)
371 GNUNET_assert (NULL == sc->result);
380 * Initiate a search for the given operation in the rcop_map
382 * @param rc the RunContext whose rcop_map will be searched for the given
384 * @param op the given operation to search for
385 * @return the matching RunContextOperation if found; NULL if not
387 static struct RunContextOperation *
388 search_rcop (struct RunContext *rc, struct GNUNET_TESTBED_Operation *op)
390 struct SearchContext sc;
395 GNUNET_CONTAINER_multihashmap32_get_multiple (rc->rcop_map,
400 GNUNET_assert (NULL != sc.result);
408 * Insert an RunContextOperation into the rcop_map of the given RunContext
410 * @param rc the RunContext into whose map is to be used for insertion
411 * @param rcop the RunContextOperation to insert
414 insert_rcop (struct RunContext *rc, struct RunContextOperation *rcop)
416 GNUNET_assert (GNUNET_OK ==
417 GNUNET_CONTAINER_multihashmap32_put (rc->rcop_map,
418 rcop_key (rcop->op), rcop,
419 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
424 * Remove a RunContextOperation from the rcop_map of the given RunContext
426 * @param rc the RunContext from whose map the given RunContextOperaton has to
428 * @param rcop the RunContextOperation
431 remove_rcop (struct RunContext *rc, struct RunContextOperation *rcop)
433 GNUNET_assert (GNUNET_YES ==
434 GNUNET_CONTAINER_multihashmap32_remove (rc->rcop_map,
440 * Assuming all peers have been destroyed cleanup run handle
442 * @param cls the run handle
443 * @param tc the task context from scheduler
446 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
448 struct RunContext *rc = cls;
451 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rc->register_hosts_task);
452 GNUNET_assert (NULL == rc->reg_handle);
453 GNUNET_assert (NULL == rc->peers);
454 GNUNET_assert (NULL == rc->hclist);
455 GNUNET_assert (RC_PEERS_SHUTDOWN == rc->state);
456 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (rc->rcop_map));
457 GNUNET_CONTAINER_multihashmap32_destroy (rc->rcop_map);
459 GNUNET_TESTBED_controller_disconnect (rc->c);
460 if (NULL != rc->cproc)
461 GNUNET_TESTBED_controller_stop (rc->cproc);
463 GNUNET_TESTBED_host_destroy (rc->h);
464 for (hid = 0; hid < rc->num_hosts; hid++)
465 GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
466 GNUNET_free_non_null (rc->hosts);
468 GNUNET_CONFIGURATION_destroy (rc->cfg);
469 GNUNET_free_non_null (rc->topo_file);
470 GNUNET_free_non_null (rc->trusted_ip);
476 * Iterator for cleaning up elements from rcop_map
478 * @param cls the RunContext
479 * @param key the 32-bit key
480 * @param value the RunContextOperation element
481 * @return always GNUNET_YES
484 rcop_cleanup_iterator (void *cls, uint32_t key, void *value)
486 struct RunContext *rc = cls;
487 struct RunContextOperation *rcop = value;
489 GNUNET_assert (rc == rcop->rc);
490 remove_rcop (rc, rcop);
491 GNUNET_TESTBED_operation_done (rcop->op);
498 * Frees memory, closes pending operations, cancels actives tasks of the given
501 * @param rc the RunContext
504 cleanup (struct RunContext *rc)
506 struct CompatibilityCheckContext *hc;
509 if (NULL != rc->hclist)
511 for (nhost = 0; nhost < rc->num_hosts; nhost++)
513 hc = &rc->hclist[nhost];
515 GNUNET_TESTBED_is_host_habitable_cancel (hc->h);
517 GNUNET_free (rc->hclist);
520 /* Stop register hosts task if it is running */
521 if (GNUNET_SCHEDULER_NO_TASK != rc->register_hosts_task)
523 GNUNET_SCHEDULER_cancel (rc->register_hosts_task);
524 rc->register_hosts_task = GNUNET_SCHEDULER_NO_TASK;
526 if (GNUNET_SCHEDULER_NO_TASK != rc->timeout_task)
528 GNUNET_SCHEDULER_cancel (rc->timeout_task);
529 rc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
531 if (GNUNET_SCHEDULER_NO_TASK != rc->interrupt_task)
533 GNUNET_SCHEDULER_cancel (rc->interrupt_task);
534 rc->interrupt_task = GNUNET_SCHEDULER_NO_TASK;
536 if (NULL != rc->reg_handle)
538 GNUNET_TESTBED_cancel_registration (rc->reg_handle);
539 rc->reg_handle = NULL;
541 if (NULL != rc->topology_operation)
543 GNUNET_TESTBED_operation_done (rc->topology_operation);
544 rc->topology_operation = NULL;
546 /* cancel any exiting operations */
547 GNUNET_assert (GNUNET_SYSERR !=
548 GNUNET_CONTAINER_multihashmap32_iterate (rc->rcop_map,
549 &rcop_cleanup_iterator,
555 * Stops the testbed run and releases any used resources
557 * @param cls the tesbed run handle
558 * @param tc the task context from scheduler
561 shutdown_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
563 struct RunContext *rc = cls;
564 struct RunContextOperation *rcop;
566 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != rc->shutdown_run_task);
567 rc->shutdown_run_task = GNUNET_SCHEDULER_NO_TASK;
568 GNUNET_assert (GNUNET_NO == rc->shutdown);
569 rc->shutdown = GNUNET_YES;
573 if (NULL != rc->peers)
575 rcop = GNUNET_malloc (sizeof (struct RunContextOperation));
577 rcop->op = GNUNET_TESTBED_shutdown_peers (rc->c, rcop, NULL, NULL);
578 GNUNET_assert (NULL != rcop->op);
579 DEBUG ("Shutting down peers\n");
580 rc->pstart_time = GNUNET_TIME_absolute_get ();
581 insert_rcop (rc, rcop);
585 rc->state = RC_PEERS_SHUTDOWN; /* No peers are present so we consider the
586 * state where all peers are SHUTDOWN */
587 GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
592 * Function to shutdown now
594 * @param rc the RunContext
597 shutdown_now (struct RunContext *rc)
599 if (GNUNET_YES == rc->shutdown)
601 if (GNUNET_SCHEDULER_NO_TASK != rc->shutdown_run_task)
602 GNUNET_SCHEDULER_cancel (rc->shutdown_run_task);
603 GNUNET_SCHEDULER_shutdown (); /* Trigger shutdown in programs using this API */
604 rc->shutdown_run_task = GNUNET_SCHEDULER_add_now (&shutdown_run, rc);
609 * Task run upon any interrupt. Common ones are SIGINT & SIGTERM.
611 * @param cls the RunContext which has to be acted upon
612 * @param tc the scheduler task context
615 interrupt (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
617 struct RunContext *rc = cls;
619 rc->interrupt_task = GNUNET_SCHEDULER_NO_TASK;
625 * Function to return the string representation of the duration between current
626 * time and `pstart_time' in `RunContext'
628 * @param rc the RunContext
629 * @return the representation string; this is NOT reentrant
632 prof_time (struct RunContext *rc)
634 struct GNUNET_TIME_Relative ptime;
636 ptime = GNUNET_TIME_absolute_get_duration (rc->pstart_time);
637 return GNUNET_STRINGS_relative_time_to_string (ptime, GNUNET_YES);
642 * Task for starting peers
644 * @param cls the RunHandle
645 * @param tc the task context from scheduler
648 start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
650 struct RunContext *rc = cls;
651 struct RunContextOperation *rcop;
654 DEBUG ("Starting Peers\n");
655 rc->pstart_time = GNUNET_TIME_absolute_get ();
656 for (peer = 0; peer < rc->num_peers; peer++)
658 rcop = GNUNET_malloc (sizeof (struct RunContextOperation));
660 rcop->op = GNUNET_TESTBED_peer_start (NULL, rc->peers[peer], NULL, NULL);
661 GNUNET_assert (NULL != rcop->op);
662 rcop->cls = rc->peers[peer];
663 insert_rcop (rc, rcop);
670 * Functions of this signature are called when a peer has been successfully
673 * @param cls the closure from GNUNET_TESTBED_peer_create()
674 * @param peer the handle for the created peer; NULL on any error during
676 * @param emsg NULL if peer is not NULL; else MAY contain the error description
679 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
681 struct RunContextOperation *rcop = cls;
682 struct RunContext *rc;
684 GNUNET_assert (NULL != rcop);
685 GNUNET_assert (NULL != (rc = rcop->rc));
686 remove_rcop (rc, rcop);
687 GNUNET_TESTBED_operation_done (rcop->op);
692 LOG (GNUNET_ERROR_TYPE_ERROR, "Error while creating a peer: %s\n",
697 rc->peers[rc->peer_count] = peer;
699 if (rc->peer_count < rc->num_peers)
701 DEBUG ("%u peers created in %s\n", rc->num_peers, prof_time (rc));
702 rc->state = RC_PEERS_CREATED;
703 GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
708 * call test master callback
710 * @param rc the RunContext
713 call_master (struct RunContext *rc)
715 GNUNET_SCHEDULER_cancel (rc->timeout_task);
716 rc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
717 if (NULL != rc->test_master)
718 rc->test_master (rc->test_master_cls, rc->num_peers, rc->peers,
719 rc->links_succeeded, rc->links_failed);
724 * Callbacks of this type are called when topology configuration is completed
726 * @param cls the operation closure given to
727 * GNUNET_TESTBED_overlay_configure_topology_va() and
728 * GNUNET_TESTBED_overlay_configure() calls
729 * @param nsuccess the number of successful overlay connects
730 * @param nfailures the number of overlay connects which failed
733 topology_completion_callback (void *cls, unsigned int nsuccess,
734 unsigned int nfailures)
736 struct RunContext *rc = cls;
738 DEBUG ("Overlay topology generated in %s\n", prof_time (rc));
739 GNUNET_TESTBED_operation_done (rc->topology_operation);
740 rc->topology_operation = NULL;
741 rc->links_succeeded = nsuccess;
742 rc->links_failed = nfailures;
743 rc->state = RC_READY;
749 * Function to create peers
751 * @param rc the RunContext
754 create_peers (struct RunContext *rc)
756 struct RunContextOperation *rcop;
759 DEBUG ("Creating peers\n");
760 rc->pstart_time = GNUNET_TIME_absolute_get ();
762 GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
763 GNUNET_assert (NULL != rc->c);
765 for (peer = 0; peer < rc->num_peers; peer++)
767 rcop = GNUNET_malloc (sizeof (struct RunContextOperation));
770 GNUNET_TESTBED_peer_create (rc->c,
772 rc->num_hosts) ? rc->h : rc->hosts[peer %
774 rc->cfg, &peer_create_cb, rcop);
775 GNUNET_assert (NULL != rcop->op);
776 insert_rcop (rc, rcop);
782 * Signature of the event handler function called by the
783 * respective event controller.
786 * @param event information about the event
789 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
791 struct RunContext *rc = cls;
792 struct RunContextOperation *rcop;
794 if (RC_INIT == rc->state)
798 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
799 rcop = event->op_cls;
800 if (NULL != event->details.operation_finished.emsg)
802 LOG (GNUNET_ERROR_TYPE_ERROR, _("Linking controllers failed. Exiting"));
807 GNUNET_assert (event->op == rcop->op);
808 remove_rcop (rc, rcop);
809 GNUNET_TESTBED_operation_done (rcop->op);
811 if (rc->reg_hosts == rc->num_hosts)
813 rc->state = RC_LINKED;
823 if (GNUNET_TESTBED_ET_OPERATION_FINISHED != event->type)
825 if (NULL == (rcop = search_rcop (rc, event->op)))
827 remove_rcop (rc, rcop);
828 GNUNET_TESTBED_operation_done (rcop->op);
830 if ( (GNUNET_NO == rc->shutdown)
831 && (NULL != event->details.operation_finished.emsg) )
833 LOG (GNUNET_ERROR_TYPE_ERROR, "A operation has failed with error: %s\n",
834 event->details.operation_finished.emsg);
838 GNUNET_assert (GNUNET_YES == rc->shutdown);
842 case RC_PEERS_CREATED:
844 rc->state = RC_PEERS_SHUTDOWN;
845 GNUNET_free_non_null (rc->peers);
847 DEBUG ("Peers shut down in %s\n", prof_time (rc));
848 GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
856 if ((0 != (rc->event_mask & (1LL << event->type))) && (NULL != rc->cc))
857 rc->cc (rc->cc_cls, event);
858 if (GNUNET_TESTBED_ET_PEER_START != event->type)
860 if (NULL == (rcop = search_rcop (rc, event->op))) /* Not our operation */
862 remove_rcop (rc, rcop);
863 GNUNET_TESTBED_operation_done (rcop->op);
866 if (rc->peer_count < rc->num_peers)
868 DEBUG ("%u peers started in %s\n", rc->num_peers, prof_time (rc));
869 if (GNUNET_TESTBED_TOPOLOGY_NONE != rc->topology)
871 if ((GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology) ||
872 (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology) ||
873 (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD == rc->topology))
875 rc->topology_operation =
876 GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
877 rc->peers, &rc->num_oc,
878 &topology_completion_callback,
882 GNUNET_TESTBED_TOPOLOGY_OPTION_END);
884 else if (GNUNET_TESTBED_TOPOLOGY_FROM_FILE == rc->topology)
886 GNUNET_assert (NULL != rc->topo_file);
887 rc->topology_operation =
888 GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
889 rc->peers, &rc->num_oc,
890 &topology_completion_callback,
894 GNUNET_TESTBED_TOPOLOGY_OPTION_END);
897 rc->topology_operation =
898 GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
899 rc->peers, &rc->num_oc,
900 &topology_completion_callback,
903 GNUNET_TESTBED_TOPOLOGY_OPTION_END);
904 if (NULL == rc->topology_operation)
905 LOG (GNUNET_ERROR_TYPE_WARNING,
906 "Not generating topology. Check number of peers\n");
909 DEBUG ("Creating overlay topology\n");
910 rc->pstart_time = GNUNET_TIME_absolute_get ();
914 rc->state = RC_READY;
920 * Task to register all hosts available in the global host list
922 * @param cls the RunContext
923 * @param tc the scheduler task context
926 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
930 * Callback which will be called to after a host registration succeeded or failed
932 * @param cls the closure
933 * @param emsg the error message; NULL if host registration is successful
936 host_registration_completion (void *cls, const char *emsg)
938 struct RunContext *rc = cls;
940 rc->reg_handle = NULL;
943 LOG (GNUNET_ERROR_TYPE_WARNING,
944 _("Host registration failed for a host. Error: %s\n"), emsg);
948 rc->register_hosts_task = GNUNET_SCHEDULER_add_now (®ister_hosts, rc);
953 * Task to register all hosts available in the global host list
955 * @param cls RunContext
956 * @param tc the scheduler task context
959 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
961 struct RunContext *rc = cls;
962 struct RunContextOperation *rcop;
965 rc->register_hosts_task = GNUNET_SCHEDULER_NO_TASK;
966 if (rc->reg_hosts == rc->num_hosts)
968 DEBUG ("All hosts successfully registered\n");
970 for (slave = 0; slave < rc->num_hosts; slave++)
972 rcop = GNUNET_malloc (sizeof (struct RunContextOperation));
975 GNUNET_TESTBED_controller_link (rcop, rc->c, rc->hosts[slave],
977 GNUNET_assert (NULL != rcop->op);
978 insert_rcop (rc, rcop);
984 GNUNET_TESTBED_register_host (rc->c, rc->hosts[rc->reg_hosts],
985 host_registration_completion, rc);
991 * Callback to signal successfull startup of the controller process
993 * @param cls the closure from GNUNET_TESTBED_controller_start()
994 * @param cfg the configuration with which the controller has been started;
995 * NULL if status is not GNUNET_OK
996 * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
997 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
1000 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
1003 struct RunContext *rc = cls;
1004 uint64_t event_mask;
1006 if (status != GNUNET_OK)
1008 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1009 _("Controller crash detected. Shutting down.\n"));
1012 if (NULL != rc->peers)
1014 GNUNET_free (rc->peers);
1017 if (GNUNET_YES == rc->shutdown)
1019 rc->state = RC_PEERS_SHUTDOWN;
1020 GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
1026 GNUNET_CONFIGURATION_destroy (rc->cfg);
1027 rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
1028 event_mask = rc->event_mask;
1029 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
1030 event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
1031 if (rc->topology < GNUNET_TESTBED_TOPOLOGY_NONE)
1032 event_mask |= GNUNET_TESTBED_ET_CONNECT;
1034 GNUNET_TESTBED_controller_connect (rc->h, event_mask, &event_cb, rc);
1035 if (0 < rc->num_hosts)
1038 rc->register_hosts_task = GNUNET_SCHEDULER_add_now (®ister_hosts, rc);
1041 rc->state = RC_LINKED;
1047 * Callback function invoked for each interface found.
1049 * @param cls closure
1050 * @param name name of the interface (can be NULL for unknown)
1051 * @param isDefault is this presumably the default interface
1052 * @param addr address of this interface (can be NULL for unknown or unassigned)
1053 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
1054 * @param netmask the network mask (can be NULL for unknown or unassigned))
1055 * @param addrlen length of the address
1056 * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort
1059 netint_proc (void *cls, const char *name, int isDefault,
1060 const struct sockaddr *addr, const struct sockaddr *broadcast_addr,
1061 const struct sockaddr *netmask, socklen_t addrlen)
1063 struct RunContext *rc = cls;
1064 char hostip[NI_MAXHOST];
1067 if (sizeof (struct sockaddr_in) != addrlen)
1068 return GNUNET_OK; /* Only consider IPv4 for now */
1070 getnameinfo (addr, addrlen, hostip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
1071 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "getnameinfo");
1072 if (NULL == rc->trusted_ip)
1074 rc->trusted_ip = GNUNET_strdup (hostip);
1077 (void) GNUNET_asprintf (&buf, "%s; %s", rc->trusted_ip, hostip);
1078 GNUNET_free (rc->trusted_ip);
1079 rc->trusted_ip = buf;
1085 * Callbacks of this type are called by GNUNET_TESTBED_is_host_habitable to
1086 * inform whether the given host is habitable or not. The Handle returned by
1087 * GNUNET_TESTBED_is_host_habitable() is invalid after this callback is called
1090 * @param host the host whose status is being reported; will be NULL if the host
1091 * given to GNUNET_TESTBED_is_host_habitable() is NULL
1092 * @param status GNUNET_YES if it is habitable; GNUNET_NO if not
1095 host_habitable_cb (void *cls, const struct GNUNET_TESTBED_Host *host,
1098 struct CompatibilityCheckContext *hc = cls;
1099 struct RunContext *rc;
1100 struct GNUNET_TESTBED_Host **old_hosts;
1103 GNUNET_assert (NULL != (rc = hc->rc));
1105 GNUNET_assert (nhost <= rc->num_hosts);
1106 GNUNET_assert (host == rc->hosts[nhost]);
1108 if (GNUNET_NO == status)
1110 if ((NULL != host) && (NULL != GNUNET_TESTBED_host_get_hostname (host)))
1111 LOG (GNUNET_ERROR_TYPE_ERROR, _("Host %s cannot start testbed\n"),
1112 GNUNET_TESTBED_host_get_hostname (host));
1114 LOG (GNUNET_ERROR_TYPE_ERROR,
1115 _("Testbed cannot be started on localhost\n"));
1120 if (rc->reg_hosts < rc->num_hosts)
1122 GNUNET_free (rc->hclist);
1124 rc->h = rc->hosts[0];
1126 if (0 < rc->num_hosts)
1128 old_hosts = rc->hosts;
1130 GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host *) * rc->num_hosts);
1131 memcpy (rc->hosts, &old_hosts[1],
1132 (sizeof (struct GNUNET_TESTBED_Host *) * rc->num_hosts));
1133 GNUNET_free (old_hosts);
1137 GNUNET_free (rc->hosts);
1140 GNUNET_OS_network_interfaces_list (netint_proc, rc);
1141 if (NULL == rc->trusted_ip)
1142 rc->trusted_ip = GNUNET_strdup ("127.0.0.1");
1144 GNUNET_TESTBED_controller_start (rc->trusted_ip, rc->h,
1145 &controller_status_cb, rc);
1146 GNUNET_free (rc->trusted_ip);
1147 rc->trusted_ip = NULL;
1148 if (NULL == rc->cproc)
1150 LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot start the master controller"));
1157 * Task run upon timeout while setting up the testbed
1159 * @param cls the RunContext
1160 * @param tc the task context
1163 timeout_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1165 struct RunContext *rc = cls;
1167 rc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1168 LOG (GNUNET_ERROR_TYPE_ERROR, _("Shutting down testbed due to timeout while setup.\n"));
1170 if (NULL != rc->test_master)
1171 rc->test_master (rc->test_master_cls, 0, NULL, 0, 0);
1172 rc->test_master = NULL;
1177 * Convenience method for running a testbed with
1178 * a single call. Underlay and overlay topology
1179 * are configured using the "UNDERLAY" and "OVERLAY"
1180 * options in the "[testbed]" section of the configuration\
1181 * (with possible options given in "UNDERLAY_XXX" and/or
1184 * The testbed is to be terminated using a call to
1185 * "GNUNET_SCHEDULER_shutdown".
1187 * @param host_filename name of the file with the 'hosts', NULL
1188 * to run everything on 'localhost'
1189 * @param cfg configuration to use (for testbed, controller and peers)
1190 * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
1191 * @param event_mask bit mask with set of events to call 'cc' for;
1192 * or-ed values of "1LL" shifted by the
1193 * respective 'enum GNUNET_TESTBED_EventType'
1194 * (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
1195 * @param cc controller callback to invoke on events; This callback is called
1196 * for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
1197 * set in the event_mask as this is the only way get access to the
1198 * handle of each peer
1199 * @param cc_cls closure for cc
1200 * @param test_master this callback will be called once the test is ready
1201 * @param test_master_cls closure for 'test_master'.
1204 GNUNET_TESTBED_run (const char *host_filename,
1205 const struct GNUNET_CONFIGURATION_Handle *cfg,
1206 unsigned int num_peers, uint64_t event_mask,
1207 GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
1208 GNUNET_TESTBED_TestMaster test_master,
1209 void *test_master_cls)
1211 struct RunContext *rc;
1213 struct CompatibilityCheckContext *hc;
1214 struct GNUNET_TIME_Relative timeout;
1215 unsigned long long random_links;
1219 GNUNET_assert (num_peers > 0);
1220 rc = GNUNET_malloc (sizeof (struct RunContext));
1221 rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
1223 rc->num_hosts = GNUNET_TESTBED_hosts_load_from_loadleveler (rc->cfg,
1225 if (0 == rc->num_hosts)
1227 LOG (GNUNET_ERROR_TYPE_WARNING,
1228 _("No hosts loaded from LoadLeveler. Need at least one host\n"));
1232 if (NULL != host_filename)
1235 GNUNET_TESTBED_hosts_load_from_file (host_filename, rc->cfg,
1237 if (0 == rc->num_hosts)
1239 LOG (GNUNET_ERROR_TYPE_WARNING,
1240 _("No hosts loaded. Need at least one host\n"));
1245 rc->h = GNUNET_TESTBED_host_create (NULL, NULL, rc->cfg, 0);
1247 rc->num_peers = num_peers;
1248 rc->event_mask = event_mask;
1250 rc->cc_cls = cc_cls;
1251 rc->test_master = test_master;
1252 rc->test_master_cls = test_master_cls;
1253 rc->state = RC_INIT;
1254 rc->topology = GNUNET_TESTBED_TOPOLOGY_NONE;
1256 GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
1257 "OVERLAY_TOPOLOGY", &topology))
1259 if (GNUNET_NO == GNUNET_TESTBED_topology_get_ (&rc->topology, topology))
1261 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "testbed",
1264 ("Specified topology must be supported by testbed"));
1266 GNUNET_free (topology);
1268 switch (rc->topology)
1270 case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
1271 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
1272 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
1274 GNUNET_CONFIGURATION_get_value_number (rc->cfg, "testbed",
1275 "OVERLAY_RANDOM_LINKS",
1278 /* OVERLAY option RANDOM & SMALL_WORLD_RING requires OVERLAY_RANDOM_LINKS
1279 * option to be set to the number of random links to be established */
1280 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "testbed",
1281 "OVERLAY_RANDOM_LINKS");
1284 if (random_links > UINT32_MAX)
1286 GNUNET_break (0); /* Too big number */
1289 rc->random_links = (unsigned int) random_links;
1291 case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
1293 GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
1294 "OVERLAY_TOPOLOGY_FILE",
1297 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "testbed",
1298 "OVERLAY_TOPOLOGY_FILE");
1302 /* Warn if OVERLAY_RANDOM_LINKS is present that it will be ignored */
1304 GNUNET_CONFIGURATION_have_value (rc->cfg, "testbed",
1305 "OVERLAY_RANDOM_LINKS"))
1306 LOG (GNUNET_ERROR_TYPE_WARNING,
1307 "Ignoring value of `OVERLAY_RANDOM_LINKS' in given configuration\n");
1310 if (0 != rc->num_hosts)
1312 rc->hclist = GNUNET_malloc (sizeof (struct CompatibilityCheckContext)
1314 for (nhost = 0; nhost < rc->num_hosts; nhost++)
1316 hc = &rc->hclist[nhost];
1319 hc->h = GNUNET_TESTBED_is_host_habitable (rc->hosts[nhost], rc->cfg,
1320 &host_habitable_cb, hc);
1324 for (nhost = 0; nhost < rc->num_hosts; nhost++)
1326 hc = &rc->hclist[nhost];
1328 GNUNET_TESTBED_is_host_habitable_cancel (hc->h);
1330 GNUNET_free (rc->hclist);
1338 GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h,
1339 &controller_status_cb, rc);
1340 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "TESTBED",
1344 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
1345 DEFAULT_SETUP_TIMEOUT);
1347 rc->rcop_map = GNUNET_CONTAINER_multihashmap32_create (256);
1349 GNUNET_SCHEDULER_add_delayed (timeout, &timeout_task, rc);
1350 rc->interrupt_task =
1351 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &interrupt,
1357 GNUNET_TESTBED_host_destroy (rc->h);
1358 if (NULL != rc->hosts)
1360 for (hid = 0; hid < rc->num_hosts; hid++)
1361 if (NULL != rc->hosts[hid])
1362 GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
1363 GNUNET_free (rc->hosts);
1365 if (NULL != rc->cfg)
1366 GNUNET_CONFIGURATION_destroy (rc->cfg);
1371 /* end of testbed_api_testbed.c */