From a93954693fef730d7a41c168b4961d19e5dff90c Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Wed, 4 Jul 2012 13:49:54 +0000 Subject: [PATCH] -controller startup, connect and duals --- src/include/gnunet_testbed_service.h | 48 ++++++++-- src/testbed/gnunet-service-testbed.c | 16 +++- src/testbed/testbed_api.c | 126 ++++++++++++++++++++------- src/testbed/testbed_api_hosts.c | 76 +++++++++++----- 4 files changed, 198 insertions(+), 68 deletions(-) diff --git a/src/include/gnunet_testbed_service.h b/src/include/gnunet_testbed_service.h index 7dd799cf1..d36f5aa8e 100644 --- a/src/include/gnunet_testbed_service.h +++ b/src/include/gnunet_testbed_service.h @@ -392,15 +392,45 @@ struct GNUNET_TESTBED_EventInformation * @param event information about the event */ typedef void (*GNUNET_TESTBED_ControllerCallback)(void *cls, - const struct GNUNET_TESTBED_EventInformation *event); + const struct GNUNET_TESTBED_EventInformation *event); /** - * Start a controller process using the given configuration at the + * Opaque Handle for Controller process + */ +struct GNUNET_TESTBED_ControllerProc; + + +/** + * Starts a controller process at the host + * + * @param host the host where the controller has to be started; NULL for localhost + * @return the controller process handle + */ +struct GNUNET_TESTBED_ControllerProc * +GNUNET_TESTBED_controller_start (struct GNUNET_TESTBED_Host *host); + + +/** + * Stop the controller process (also will terminate all peers and controllers + * dependent on this controller). This function blocks until the testbed has + * been fully terminated (!). + * + * @param cproc the controller process handle + */ +void +GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_ControllerProc *cproc); + + +/** + * Connect to a controller process using the given configuration at the * given host. * * @param cfg configuration to use - * @param host host to run the controller on, NULL for 'localhost' + * @param host host to run the controller on; This should be the same host if + * the controller was previously started with + * GNUNET_TESTBED_controller_start; NULL for localhost + * @param host host where this controller is being run; * @param event_mask bit mask with set of events to call 'cc' for; * or-ed values of "1LL" shifted by the * respective 'enum GNUNET_TESTBED_EventType' @@ -410,11 +440,11 @@ typedef void (*GNUNET_TESTBED_ControllerCallback)(void *cls, * @return handle to the controller */ struct GNUNET_TESTBED_Controller * -GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTBED_Host *host, - uint64_t event_mask, - GNUNET_TESTBED_ControllerCallback cc, - void *cc_cls); +GNUNET_TESTBED_controller_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTBED_Host *host, + uint64_t event_mask, + GNUNET_TESTBED_ControllerCallback cc, + void *cc_cls); /** @@ -444,7 +474,7 @@ GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller *c * @param controller handle to controller to stop */ void -GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_Controller *controller); +GNUNET_TESTBED_controller_disconnect (struct GNUNET_TESTBED_Controller *controller); /** diff --git a/src/testbed/gnunet-service-testbed.c b/src/testbed/gnunet-service-testbed.c index c42805fff..f29005fa9 100644 --- a/src/testbed/gnunet-service-testbed.c +++ b/src/testbed/gnunet-service-testbed.c @@ -128,6 +128,11 @@ struct Route * host */ struct GNUNET_TESTBED_Controller *fcontroller; + + /** + * The controller process handle if we started the controller + */ + struct GNUNET_TESTBED_ControllerProc *fcontroller_proc; }; @@ -522,7 +527,6 @@ lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) host_list[lcf->slave_host_id], lcf->cfg, lcf->is_subordinate); lcf->state = FINISHED; - break; case FINISHED: lcfq = lcfq_head; GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg); @@ -798,7 +802,7 @@ handle_link_controllers (void *cls, return; } GNUNET_assert (config_size == dest_size); - cfg = GNUNET_CONFIGURATION_create (); + cfg = GNUNET_CONFIGURATION_create (); /* Free here or in lcfcontext */ if (GNUNET_OK != GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO)) { @@ -846,6 +850,10 @@ handle_link_controllers (void *cls, GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; + } + else + { + } GNUNET_SERVER_receive_done (client, GNUNET_OK); /* If we are not the slave controller then we have to route the request @@ -936,7 +944,9 @@ shutdown_task (void *cls, if (NULL != route_list[route_id]) { if (NULL != route_list[route_id]->fcontroller) - GNUNET_TESTBED_controller_stop (route_list[route_id]->fcontroller); + GNUNET_TESTBED_controller_disconnect (route_list[route_id]->fcontroller); + if (NULL != route_list[route_id]->fcontroller_proc) + GNUNET_TESTBED_controller_stop (route_list[route_id]->fcontroller_proc); GNUNET_free (route_list[route_id]); } GNUNET_free_non_null (route_list); diff --git a/src/testbed/testbed_api.c b/src/testbed/testbed_api.c index c61f10563..9345b1bda 100644 --- a/src/testbed/testbed_api.c +++ b/src/testbed/testbed_api.c @@ -125,12 +125,7 @@ struct GNUNET_TESTBED_Controller /** * The host where the controller is running */ - const struct GNUNET_TESTBED_Host *host; - - /** - * The helper handle - */ - struct GNUNET_TESTBED_HelperHandle *helper; + struct GNUNET_TESTBED_Host *host; /** * The controller callback @@ -192,6 +187,11 @@ struct GNUNET_TESTBED_Controller * Did we start the receive loop yet? */ int in_receive; + + /** + * Did we create the host for this? + */ + int aux_host; }; @@ -390,12 +390,69 @@ queue_message (struct GNUNET_TESTBED_Controller *controller, } +/** + * Handle for controller process + */ +struct GNUNET_TESTBED_ControllerProc +{ + /** + * The helper handle + */ + struct GNUNET_TESTBED_HelperHandle *helper; + +}; + + +/** + * Starts a controller process at the host + * + * @param host the host where the controller has to be started; NULL for localhost + * @return the controller process handle + */ +struct GNUNET_TESTBED_ControllerProc * +GNUNET_TESTBED_controller_start (struct GNUNET_TESTBED_Host *host) +{ + struct GNUNET_TESTBED_ControllerProc *cproc; + char * const binary_argv[] = { + "gnunet-service-testbed", + "gnunet-service-testbed", + NULL + }; + + cproc = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ControllerProc)); + cproc->helper = GNUNET_TESTBED_host_run_ (host, binary_argv); + if (NULL == cproc->helper) + { + GNUNET_free (cproc); + return NULL; + } + return cproc; +} + + +/** + * Stop the controller process (also will terminate all peers and controllers + * dependent on this controller). This function blocks until the testbed has + * been fully terminated (!). + * + * @param cproc the controller process handle + */ +void +GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_ControllerProc *cproc) +{ + GNUNET_TESTBED_host_stop_ (cproc->helper); + GNUNET_free (cproc); +} + + /** * Start a controller process using the given configuration at the * given host. * * @param cfg configuration to use - * @param host host to run the controller on, NULL for 'localhost' + * @param host host to run the controller on; This should be the same host if + * the controller was previously started with + * GNUNET_TESTBED_controller_start; NULL for localhost * @param event_mask bit mask with set of events to call 'cc' for; * or-ed values of "1LL" shifted by the * respective 'enum GNUNET_TESTBED_EventType' @@ -405,42 +462,46 @@ queue_message (struct GNUNET_TESTBED_Controller *controller, * @return handle to the controller */ struct GNUNET_TESTBED_Controller * -GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTBED_Host *host, - uint64_t event_mask, - GNUNET_TESTBED_ControllerCallback cc, - void *cc_cls) +GNUNET_TESTBED_controller_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTBED_Host *host, + uint64_t event_mask, + GNUNET_TESTBED_ControllerCallback cc, + void *cc_cls) { struct GNUNET_TESTBED_Controller *controller; - char * const binary_argv[] = { - "gnunet-service-testbed", - "gnunet-service-testbed", - NULL - }; struct GNUNET_TESTBED_InitMessage *msg; controller = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Controller)); - controller->helper = GNUNET_TESTBED_host_run_ (host, binary_argv); - if (NULL == controller->helper) - { - GNUNET_free (controller); - return NULL; - } - controller->host = host; controller->cc = cc; controller->cc_cls = cc_cls; controller->event_mask = event_mask; controller->cfg = GNUNET_CONFIGURATION_dup (cfg); - controller->client = GNUNET_CLIENT_connect ("testbed", controller->cfg); + controller->client = GNUNET_CLIENT_connect ("testbed", controller->cfg); if (NULL == controller->client) { - GNUNET_TESTBED_controller_stop (controller); + GNUNET_TESTBED_controller_disconnect (controller); return NULL; - } + } + if (NULL == host) + { + host = GNUNET_TESTBED_host_create_by_id_ (0); + if (NULL == host) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + "Treating NULL host as localhost. Multiple references to localhost. " + " May break when localhost freed before calling disconnect \n"); + host = GNUNET_TESTBED_host_lookup_by_id_ (0); + } + else + { + controller->aux_host = GNUNET_YES; + } + } + GNUNET_assert (NULL != host); msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage)); msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT); msg->header.size = htons (sizeof (struct GNUNET_TESTBED_InitMessage)); - msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (controller->host)); + msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host)); msg->event_mask = GNUNET_htonll (controller->event_mask); queue_message (controller, (struct GNUNET_MessageHeader *) msg); return controller; @@ -483,14 +544,12 @@ GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller *c /** - * Stop the given controller (also will terminate all peers and - * controllers dependent on this controller). This function - * blocks until the testbed has been fully terminated (!). + * disconnects from the controller. * * @param controller handle to controller to stop */ void -GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_Controller *controller) +GNUNET_TESTBED_controller_disconnect (struct GNUNET_TESTBED_Controller *controller) { struct MessageQueue *mq_entry; @@ -507,8 +566,9 @@ GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_Controller *controller) } if (NULL != controller->client) GNUNET_CLIENT_disconnect (controller->client); - GNUNET_TESTBED_host_stop_ (controller->helper); GNUNET_CONFIGURATION_destroy (controller->cfg); + if (GNUNET_YES == controller->aux_host) + GNUNET_TESTBED_host_destroy (controller->host); GNUNET_free (controller); } diff --git a/src/testbed/testbed_api_hosts.c b/src/testbed/testbed_api_hosts.c index 6c0877cea..4d9fb2e61 100644 --- a/src/testbed/testbed_api_hosts.c +++ b/src/testbed/testbed_api_hosts.c @@ -33,6 +33,18 @@ #include "gnunet_hello_lib.h" #include "gnunet_container_lib.h" +/** + * Generic logging shorthand + */ +#define LOG(kind, ...) \ + GNUNET_log_from (kind, "testbed-api-hosts", __VA_ARGS__); + +/** + * Number of extra elements we create space for when we grow host list + */ +#define HOST_LIST_GROW_STEP 10 + + /** * A list entry for registered controllers list */ @@ -54,6 +66,7 @@ struct RegisteredController struct RegisteredController *prev; }; + /** * Opaque handle to a host running experiments managed by the testing framework. * The master process must be able to SSH to this host without password (via @@ -95,7 +108,7 @@ struct GNUNET_TESTBED_Host /** * Global ID we use to refer to a host on the network */ - uint32_t unique_id; + uint32_t id; /** * The port which is to be used for SSH @@ -106,14 +119,14 @@ struct GNUNET_TESTBED_Host /** - * Head element in the list of available hosts + * Array of available hosts */ -static struct GNUNET_TESTBED_Host *host_list_head; +static struct GNUNET_TESTBED_Host **host_list; /** - * Tail element in the list of available hosts + * The size of the available hosts list */ -static struct GNUNET_TESTBED_Host *host_list_tail; +static uint32_t host_list_size; /** @@ -126,12 +139,9 @@ static struct GNUNET_TESTBED_Host *host_list_tail; struct GNUNET_TESTBED_Host * GNUNET_TESTBED_host_lookup_by_id_ (uint32_t id) { - struct GNUNET_TESTBED_Host *host; - - for (host = host_list_head; NULL != host; host=host->next) - if (id == host->unique_id) - return host; - return NULL; + if (host_list_size <= id) + return NULL; + return host_list[id]; } @@ -147,11 +157,7 @@ GNUNET_TESTBED_host_lookup_by_id_ (uint32_t id) struct GNUNET_TESTBED_Host * GNUNET_TESTBED_host_create_by_id_ (uint32_t id) { - struct GNUNET_TESTBED_Host *host; - - host = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host)); - host->unique_id = id; - return host; + return GNUNET_TESTBED_host_create_with_id (id, NULL, NULL, 0); } @@ -165,7 +171,7 @@ GNUNET_TESTBED_host_create_by_id_ (uint32_t id) uint32_t GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host *host) { - return host->unique_id; + return host->id; } @@ -226,12 +232,23 @@ GNUNET_TESTBED_host_create_with_id (uint32_t id, { struct GNUNET_TESTBED_Host *host; + if ((id < host_list_size) && (NULL != host_list[host_list_size])) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "Host with id: %u already created\n"); + return NULL; + } host = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host)); host->hostname = hostname; host->username = username; - host->unique_id = id; + host->id = id; host->port = (0 == port) ? 22 : port; - GNUNET_CONTAINER_DLL_insert_tail (host_list_head, host_list_tail, host); + if (id < host_list_size) + { + host_list_size += HOST_LIST_GROW_STEP; + host_list = GNUNET_realloc (host_list, sizeof (struct GNUNET_TESTBED_Host) + * host_list_size); + } + host_list[id] = host; return host; } @@ -286,14 +303,27 @@ void GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host) { struct RegisteredController *rc; - - GNUNET_CONTAINER_DLL_remove (host_list_head, host_list_tail, host); + uint32_t id; + + GNUNET_assert (host->id < host_list_size); + GNUNET_assert (host_list[host->id] == host); + host_list[host->id] = NULL; /* clear registered controllers list */ for (rc=host->rc_head; NULL != rc; rc=host->rc_head) { GNUNET_CONTAINER_DLL_remove (host->rc_head, host->rc_tail, rc); GNUNET_free (rc); } + for (id = 0; id < HOST_LIST_GROW_STEP; id++) + { + if ((host->id + id >= host_list_size) || (NULL != host_list[host->id + id])) + break; + } + if (HOST_LIST_GROW_STEP == id) + { + host_list_size -= HOST_LIST_GROW_STEP; + host_list = GNUNET_realloc (host_list, host_list_size); + } GNUNET_free (host); } @@ -347,7 +377,7 @@ GNUNET_TESTBED_host_run_ (const struct GNUNET_TESTBED_Host *host, argc++; h = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HelperHandle)); h->cpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES, GNUNET_NO); - if (0 == host->unique_id) + if ((NULL == host) || (0 == host->id)) { h->process = GNUNET_OS_start_process_vap (GNUNET_YES, h->cpipe, NULL, @@ -355,7 +385,7 @@ GNUNET_TESTBED_host_run_ (const struct GNUNET_TESTBED_Host *host, binary_argv); } else - { + { char *remote_args[argc + 6 + 1]; unsigned int argp; -- 2.25.1