diff options
-rw-r--r-- | src/testbed/Makefile.am | 3 | ||||
-rw-r--r-- | src/testbed/gnunet-service-testbed.c | 706 | ||||
-rw-r--r-- | src/testbed/gnunet-service-testbed.h | 33 | ||||
-rw-r--r-- | src/testbed/gnunet-service-testbed_links.c | 760 |
4 files changed, 799 insertions, 703 deletions
diff --git a/src/testbed/Makefile.am b/src/testbed/Makefile.am index 97e304ff3a..6b8b440891 100644 --- a/src/testbed/Makefile.am +++ b/src/testbed/Makefile.am @@ -32,10 +32,11 @@ bin_PROGRAMS = \ gnunet_service_testbed_SOURCES = \ gnunet-service-testbed.h \ gnunet-service-testbed.c \ + gnunet-service-testbed_links.c \ gnunet-service-testbed_peers.c \ gnunet-service-testbed_cache.c \ gnunet-service-testbed_oc.c \ - gnunet-service-testbed_cpustatus.c + gnunet-service-testbed_cpustatus.c gnunet_service_testbed_LDADD = $(XLIB) \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/core/libgnunetcore.la \ diff --git a/src/testbed/gnunet-service-testbed.c b/src/testbed/gnunet-service-testbed.c index 05668284ba..25bded7884 100644 --- a/src/testbed/gnunet-service-testbed.c +++ b/src/testbed/gnunet-service-testbed.c @@ -42,11 +42,6 @@ struct GNUNET_CONFIGURATION_Handle *our_config; struct Context *GST_context; /** - * A list of directly linked neighbours - */ -struct Slave **GST_slave_list; - -/** * Array of hosts */ struct GNUNET_TESTBED_Host **GST_host_list; @@ -77,11 +72,6 @@ const struct GNUNET_TIME_Relative GST_timeout; unsigned int GST_host_list_size; /** - * The size of directly linked neighbours list - */ -unsigned int GST_slave_list_size; - -/** * The size of the peer list */ unsigned int GST_peer_list_size; @@ -128,16 +118,6 @@ static char *hostname; static struct GNUNET_SERVER_TransmitHandle *transmit_handle; /** - * The head for the LCF queue - */ -static struct LCFContextQueue *lcfq_head; - -/** - * The tail for the LCF queue - */ -static struct LCFContextQueue *lcfq_tail; - -/** * The message queue head */ static struct MessageQueue *mq_head; @@ -153,26 +133,6 @@ static struct MessageQueue *mq_tail; static struct GNUNET_CONTAINER_MultiHashMap *ss_map; /** - * A list of routes - */ -static struct Route **route_list; - -/** - * The event mask for the events we listen from sub-controllers - */ -static uint64_t event_mask; - -/** - * The size of the route list - */ -static unsigned int route_list_size; - -/** - * The lcf_task handle - */ -static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id; - -/** * The shutdown task handle */ static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id; @@ -275,62 +235,6 @@ host_list_add (struct GNUNET_TESTBED_Host *host) /** - * Adds a route to the route list - * - * @param route the route to add - */ -static void -route_list_add (struct Route *route) -{ - if (route->dest >= route_list_size) - GST_array_grow_large_enough (route_list, route_list_size, route->dest); - GNUNET_assert (NULL == route_list[route->dest]); - route_list[route->dest] = route; -} - - -/** - * Adds a slave to the slave array - * - * @param slave the slave controller to add - */ -static void -slave_list_add (struct Slave *slave) -{ - if (slave->host_id >= GST_slave_list_size) - GST_array_grow_large_enough (GST_slave_list, GST_slave_list_size, - slave->host_id); - GNUNET_assert (NULL == GST_slave_list[slave->host_id]); - GST_slave_list[slave->host_id] = slave; -} - - -/** - * Finds the route with directly connected host as destination through which - * the destination host can be reached - * - * @param host_id the id of the destination host - * @return the route with directly connected destination host; NULL if no route - * is found - */ -struct Route * -GST_find_dest_route (uint32_t host_id) -{ - struct Route *route; - - if (route_list_size <= host_id) - return NULL; - while (NULL != (route = route_list[host_id])) - { - if (route->thru == GST_context->host_id) - break; - host_id = route->thru; - } - return route; -} - - -/** * Routes message to a host given its host_id * * @param host_id the id of the destination host @@ -395,61 +299,6 @@ GST_send_operation_success_msg (struct GNUNET_SERVER_Client *client, GST_queue_message (client, &msg->header); } - -/** - * Function to send a failure reponse for controller link operation - * - * @param client the client to send the message to - * @param operation_id the operation ID of the controller link request - * @param cfg the configuration with which the delegated controller is started. - * Can be NULL if the delegated controller is not started but just - * linked to. - * @param emsg set to an error message explaining why the controller link - * failed. Setting this to NULL signifies success. !This should be - * NULL if cfg is set! - */ -static void -send_controller_link_response (struct GNUNET_SERVER_Client *client, - uint64_t operation_id, - const struct GNUNET_CONFIGURATION_Handle - *cfg, - const char *emsg) -{ - struct GNUNET_TESTBED_ControllerLinkResponse *msg; - char *xconfig; - size_t config_size; - size_t xconfig_size; - uint16_t msize; - - GNUNET_assert ((NULL == cfg) || (NULL == emsg)); - xconfig = NULL; - xconfig_size = 0; - config_size = 0; - msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse); - if (NULL != cfg) - { - xconfig = GNUNET_TESTBED_compress_cfg_ (cfg, - &config_size, - &xconfig_size); - msize += xconfig_size; - } - if (NULL != emsg) - msize += strlen (emsg); - msg = GNUNET_malloc (msize); - msg->header.type = htons - (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT); - msg->header.size = htons (msize); - if (NULL == emsg) - msg->success = htons (GNUNET_YES); - msg->operation_id = GNUNET_htonll (operation_id); - msg->config_size = htons ((uint16_t) config_size); - if (NULL != xconfig) - memcpy (&msg[1], xconfig, xconfig_size); - if (NULL != emsg) - memcpy (&msg[1], emsg, strlen (emsg)); - GST_queue_message (client, &msg->header); -} - /** * Callback which will be called after a host registration succeeded or failed * @@ -543,55 +392,6 @@ GST_queue_host_registration (struct Slave *slave, /** - * The Link Controller forwarding task - * - * @param cls the LCFContext - * @param tc the Task context from scheduler - */ -static void -lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Completion callback for host registrations while forwarding Link Controller messages - * - * @param cls the LCFContext - * @param emsg the error message; NULL if host registration is successful - */ -static void -lcf_proc_cc (void *cls, const char *emsg) -{ - struct LCFContext *lcf = cls; - - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); - switch (lcf->state) - { - case INIT: - if (NULL != emsg) - goto registration_error; - lcf->state = DELEGATED_HOST_REGISTERED; - lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); - break; - case DELEGATED_HOST_REGISTERED: - if (NULL != emsg) - goto registration_error; - lcf->state = SLAVE_HOST_REGISTERED; - lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); - break; - default: - GNUNET_assert (0); /* Shouldn't reach here */ - } - return; - -registration_error: - LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n", - emsg); - lcf->state = FINISHED; - lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); -} - - -/** * Callback to relay the reply msg of a forwarded operation back to the client * * @param cls ForwardedOperationContext @@ -640,244 +440,6 @@ GST_forwarded_operation_timeout (void *cls, /** - * The Link Controller forwarding task - * - * @param cls the LCFContext - * @param tc the Task context from scheduler - */ -static void -lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Task to free resources when forwarded link controllers has been timedout - * - * @param cls the LCFContext - * @param tc the task context from scheduler - */ -static void -lcf_forwarded_operation_timeout (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct LCFContext *lcf = cls; - - lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK; - // GST_forwarded_operation_timeout (lcf->fopc, tc); - LOG (GNUNET_ERROR_TYPE_WARNING, - "A forwarded controller link operation has timed out\n"); - send_controller_link_response (lcf->client, lcf->operation_id, NULL, - "A forwarded controller link operation has " - "timed out\n"); - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); - lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); -} - - -/** - * The Link Controller forwarding task - * - * @param cls the LCFContext - * @param tc the Task context from scheduler - */ -static void -lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct LCFContext *lcf = cls; - struct LCFContextQueue *lcfq; - - lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK; - switch (lcf->state) - { - case INIT: - if (GNUNET_NO == - GNUNET_TESTBED_is_host_registered_ (GST_host_list - [lcf->delegated_host_id], - lcf->gateway->controller)) - { - GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf, - GST_host_list[lcf->delegated_host_id]); - } - else - { - lcf->state = DELEGATED_HOST_REGISTERED; - lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); - } - break; - case DELEGATED_HOST_REGISTERED: - if (GNUNET_NO == - GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id], - lcf->gateway->controller)) - { - GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf, - GST_host_list[lcf->slave_host_id]); - } - else - { - lcf->state = SLAVE_HOST_REGISTERED; - lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); - } - break; - case SLAVE_HOST_REGISTERED: - lcf->op = GNUNET_TESTBED_controller_link (lcf, - lcf->gateway->controller, - GST_host_list[lcf->delegated_host_id], - GST_host_list[lcf->slave_host_id], - NULL, - lcf->is_subordinate); - lcf->timeout_task = - GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout, - lcf); - lcf->state = FINISHED; - break; - case FINISHED: - lcfq = lcfq_head; - GNUNET_assert (lcfq->lcf == lcf); - GNUNET_assert (NULL != lcf->cfg); - GNUNET_CONFIGURATION_destroy (lcf->cfg); - GNUNET_SERVER_client_drop (lcf->client); - GNUNET_TESTBED_operation_done (lcf->op); - GNUNET_free (lcf); - GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq); - GNUNET_free (lcfq); - if (NULL != lcfq_head) - lcf_proc_task_id = - GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf); - } -} - - -/** - * Callback for event from slave controllers - * - * @param cls struct Slave * - * @param event information about the event - */ -static void -slave_event_callback (void *cls, - const struct GNUNET_TESTBED_EventInformation *event) -{ - struct RegisteredHostContext *rhc; - struct LCFContext *lcf; - struct GNUNET_CONFIGURATION_Handle *cfg; - struct GNUNET_TESTBED_Operation *old_op; - - /* We currently only get here when working on RegisteredHostContexts and - LCFContexts */ - GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type); - rhc = event->op_cls; - if (CLOSURE_TYPE_RHC == rhc->type) - { - GNUNET_assert (rhc->sub_op == event->op); - switch (rhc->state) - { - case RHC_GET_CFG: - cfg = event->details.operation_finished.generic; - old_op = rhc->sub_op; - rhc->state = RHC_LINK; - rhc->sub_op = - GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller, - rhc->reg_host, rhc->host, cfg, - GNUNET_NO); - GNUNET_TESTBED_operation_done (old_op); - break; - case RHC_LINK: - LOG_DEBUG ("OL: Linking controllers successfull\n"); - GNUNET_TESTBED_operation_done (rhc->sub_op); - rhc->sub_op = NULL; - rhc->state = RHC_OL_CONNECT; - GST_process_next_focc (rhc); - break; - default: - GNUNET_assert (0); - } - return; - } - lcf = event->op_cls; - if (CLOSURE_TYPE_LCF == lcf->type) - { - GNUNET_assert (lcf->op == event->op); - GNUNET_assert (FINISHED == lcf->state); - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task); - GNUNET_SCHEDULER_cancel (lcf->timeout_task); - if (NULL == event->details.operation_finished.emsg) - send_controller_link_response (lcf->client, lcf->operation_id, - GNUNET_TESTBED_host_get_cfg_ - (GST_host_list[lcf->delegated_host_id]), - NULL); - else - send_controller_link_response (lcf->client, lcf->operation_id, - NULL, - event->details.operation_finished.emsg); - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); - lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); - return; - } - GNUNET_assert (0); -} - - -/** - * Callback to signal successfull startup of the controller process - * - * @param cls the handle to the slave whose status is to be found here - * @param cfg the configuration with which the controller has been started; - * NULL if status is not GNUNET_OK - * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not, - * GNUNET_TESTBED_controller_stop() shouldn't be called in this case - */ -static void -slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, - int status) -{ - struct Slave *slave = cls; - struct LinkControllersContext *lcc; - - lcc = slave->lcc; - if (GNUNET_SYSERR == status) - { - slave->controller_proc = NULL; - GST_slave_list[slave->host_id] = NULL; - GNUNET_free (slave); - slave = NULL; - LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n"); - GNUNET_SCHEDULER_shutdown (); /* We too shutdown */ - goto clean_lcc; - } - slave->controller = - GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id], - event_mask, &slave_event_callback, - slave); - if (NULL != slave->controller) - { - send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL); - } - else - { - send_controller_link_response (lcc->client, lcc->operation_id, NULL, - "Could not connect to delegated controller"); - GNUNET_TESTBED_controller_stop (slave->controller_proc); - GST_slave_list[slave->host_id] = NULL; - GNUNET_free (slave); - slave = NULL; - } - -clean_lcc: - if (NULL != lcc) - { - if (NULL != lcc->client) - { - GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK); - GNUNET_SERVER_client_drop (lcc->client); - lcc->client = NULL; - } - GNUNET_free (lcc); - } - if (NULL != slave) - slave->lcc = NULL; -} - - -/** * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages * * @param cls NULL @@ -1139,184 +701,6 @@ handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client, /** - * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message - * - * @param cls NULL - * @param client identification of the client - * @param message the actual message - */ -static void -handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct GNUNET_TESTBED_ControllerLinkRequest *msg; - struct GNUNET_CONFIGURATION_Handle *cfg; - struct LCFContextQueue *lcfq; - struct Route *route; - struct Route *new_route; - uint32_t delegated_host_id; - uint32_t slave_host_id; - uint16_t msize; - - if (NULL == GST_context) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - msize = ntohs (message->size); - if (sizeof (struct GNUNET_TESTBED_ControllerLinkRequest) >= msize) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message; - delegated_host_id = ntohl (msg->delegated_host_id); - if (delegated_host_id == GST_context->host_id) - { - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n"); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - if ((delegated_host_id >= GST_host_list_size) || - (NULL == GST_host_list[delegated_host_id])) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "Delegated host %u not registered with us\n", delegated_host_id); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - slave_host_id = ntohl (msg->slave_host_id); - if ((slave_host_id >= GST_host_list_size) || - (NULL == GST_host_list[slave_host_id])) - { - LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n", - slave_host_id); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - if (slave_host_id == delegated_host_id) - { - LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n"); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - cfg = GNUNET_TESTBED_extract_config_ (message); /* destroy cfg here or in lcfcontext */ - if (NULL == cfg) - { - GNUNET_break (0); /* Configuration parsing error */ - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - if (slave_host_id == GST_context->host_id) /* Link from us */ - { - struct Slave *slave; - struct LinkControllersContext *lcc; - - if ((delegated_host_id < GST_slave_list_size) && - (NULL != GST_slave_list[delegated_host_id])) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - slave = GNUNET_malloc (sizeof (struct Slave)); - slave->host_id = delegated_host_id; - slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO); - slave_list_add (slave); - if (1 != msg->is_subordinate) - { - slave->controller = - GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id], - event_mask, &slave_event_callback, - slave); - if (NULL != slave->controller) - send_controller_link_response (client, - GNUNET_ntohll (msg->operation_id), - NULL, - NULL); - else - send_controller_link_response (client, - GNUNET_ntohll (msg->operation_id), - NULL, - "Could not connect to delegated controller"); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } - lcc = GNUNET_malloc (sizeof (struct LinkControllersContext)); - lcc->operation_id = GNUNET_ntohll (msg->operation_id); - GNUNET_SERVER_client_keep (client); - lcc->client = client; - slave->lcc = lcc; - slave->controller_proc = - GNUNET_TESTBED_controller_start (GST_context->master_ip, - GST_host_list[slave->host_id], cfg, - &slave_status_callback, slave); - GNUNET_CONFIGURATION_destroy (cfg); - new_route = GNUNET_malloc (sizeof (struct Route)); - new_route->dest = delegated_host_id; - new_route->thru = GST_context->host_id; - route_list_add (new_route); - return; - } - - /* Route the request */ - if (slave_host_id >= route_list_size) - { - LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host"); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue)); - lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext)); - lcfq->lcf->type = CLOSURE_TYPE_LCF; - lcfq->lcf->delegated_host_id = delegated_host_id; - lcfq->lcf->slave_host_id = slave_host_id; - route = GST_find_dest_route (slave_host_id); - GNUNET_assert (NULL != route); /* because we add routes carefully */ - GNUNET_assert (route->dest < GST_slave_list_size); - GNUNET_assert (NULL != GST_slave_list[route->dest]); - lcfq->lcf->cfg = cfg; - lcfq->lcf->is_subordinate = msg->is_subordinate; - lcfq->lcf->state = INIT; - lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id); - lcfq->lcf->gateway = GST_slave_list[route->dest]; - GNUNET_SERVER_client_keep (client); - lcfq->lcf->client = client; - if (NULL == lcfq_head) - { - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); - GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq); - lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf); - } - else - GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq); - /* FIXME: Adding a new route should happen after the controllers are linked - * successfully */ - if (1 != msg->is_subordinate) - { - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } - if ((delegated_host_id < route_list_size) && - (NULL != route_list[delegated_host_id])) - { - GNUNET_break_op (0); /* Are you trying to link delegated host twice - * with is subordinate flag set to GNUNET_YES? */ - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - new_route = GNUNET_malloc (sizeof (struct Route)); - new_route->dest = delegated_host_id; - new_route->thru = route->dest; - route_list_add (new_route); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages * * @param cls NULL @@ -1441,41 +825,6 @@ ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value) /** - * Iterator for freeing hash map entries in a slave's reghost_map - * - * @param cls handle to the slave - * @param key current key code - * @param value value in the hash map - * @return GNUNET_YES if we should continue to - * iterate, - * GNUNET_NO if not. - */ -static int -reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key, - void *value) -{ - struct Slave *slave = cls; - struct RegisteredHostContext *rhc = value; - struct ForwardedOverlayConnectContext *focc; - - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key, - value)); - while (NULL != (focc = rhc->focc_dll_head)) - { - GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc); - GST_cleanup_focc (focc); - } - if (NULL != rhc->sub_op) - GNUNET_TESTBED_operation_done (rhc->sub_op); - if (NULL != rhc->client) - GNUNET_SERVER_client_drop (rhc->client); - GNUNET_free (value); - return GNUNET_YES; -} - - -/** * Task to clean up and shutdown nicely * * @param cls NULL @@ -1484,7 +833,6 @@ reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key, static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct LCFContextQueue *lcfq; struct MessageQueue *mq_entry; uint32_t id; @@ -1495,24 +843,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_CONTAINER_multihashmap_destroy (ss_map); /* cleanup any remaining forwarded operations */ GST_clear_fopcq (); - if (NULL != lcfq_head) - { - if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id) - { - GNUNET_SCHEDULER_cancel (lcf_proc_task_id); - lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK; - } - } - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); - for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head) - { - GNUNET_SERVER_client_drop (lcfq->lcf->client); - GNUNET_assert (NULL != lcfq->lcf->cfg); - GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg); - GNUNET_free (lcfq->lcf); - GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq); - GNUNET_free (lcfq); - } + GST_free_lcfq (); GST_free_mctxq (); GST_free_occq (); GST_free_roccq (); @@ -1524,37 +855,9 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_TESTBED_host_destroy (GST_host_list[id]); GNUNET_free_non_null (GST_host_list); /* Clear route list */ - for (id = 0; id < route_list_size; id++) - if (NULL != route_list[id]) - GNUNET_free (route_list[id]); - GNUNET_free_non_null (route_list); + GST_route_list_clear (); /* Clear GST_slave_list */ - for (id = 0; id < GST_slave_list_size; id++) - if (NULL != GST_slave_list[id]) - { - struct HostRegistration *hr_entry; - - while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head)) - { - GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head, - GST_slave_list[id]->hr_dll_tail, hr_entry); - GNUNET_free (hr_entry); - } - if (NULL != GST_slave_list[id]->rhandle) - GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle); - (void) - GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list - [id]->reghost_map, - reghost_free_iterator, - GST_slave_list[id]); - GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map); - if (NULL != GST_slave_list[id]->controller) - GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller); - if (NULL != GST_slave_list[id]->controller_proc) - GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc); - GNUNET_free (GST_slave_list[id]); - } - GNUNET_free_non_null (GST_slave_list); + GST_slave_list_clear (); if (NULL != GST_context) { GNUNET_free_non_null (GST_context->master_ip); @@ -1623,7 +926,7 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server, {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST, 0}, {&handle_configure_shared_service, NULL, GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE, 0}, - {&handle_link_controllers, NULL, + {&GST_handle_link_controllers, NULL, GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS, 0}, {&GST_handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER, 0}, {&GST_handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER, @@ -1685,7 +988,6 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server, GNUNET_SCHEDULER_PRIORITY_IDLE, &shutdown_task, NULL); LOG_DEBUG ("Testbed startup complete\n"); - event_mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED; GST_stats_init (our_config); } diff --git a/src/testbed/gnunet-service-testbed.h b/src/testbed/gnunet-service-testbed.h index 4a33b92ef9..2a410a850d 100644 --- a/src/testbed/gnunet-service-testbed.h +++ b/src/testbed/gnunet-service-testbed.h @@ -748,6 +748,18 @@ GST_find_dest_route (uint32_t host_id); /** + * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message + * + * @param cls NULL + * @param client identification of the client + * @param message the actual message + */ +void +GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); + + +/** * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT messages * * @param cls NULL @@ -931,6 +943,27 @@ GST_free_mctxq (); /** + * Cleans up the queue used for forwarding link controllers requests + */ +void +GST_free_lcfq (); + + +/** + * Cleans up the route list + */ +void +GST_route_list_clear (); + + +/** + * Cleans up the slave list + */ +void +GST_slave_list_clear (); + + +/** * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext * * @param rhc the RegisteredHostContext diff --git a/src/testbed/gnunet-service-testbed_links.c b/src/testbed/gnunet-service-testbed_links.c new file mode 100644 index 0000000000..6f71d8a611 --- /dev/null +++ b/src/testbed/gnunet-service-testbed_links.c @@ -0,0 +1,760 @@ +/* + This file is part of GNUnet. + (C) 2008--2013 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file testbed/gnunet-service-testbed.c + * @brief implementation of the TESTBED service + * @author Sree Harsha Totakura + */ + +#include "gnunet-service-testbed.h" + +/** + * The event mask for the events we listen from sub-controllers + */ +#define EVENT_MASK (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED) + +/** + * A list of directly linked neighbours + */ +struct Slave **GST_slave_list; + +/** + * The size of directly linked neighbours list + */ +unsigned int GST_slave_list_size; + +/** + * A list of routes + */ +static struct Route **route_list; + +/** + * The head for the LCF queue + */ +static struct LCFContextQueue *lcfq_head; + +/** + * The tail for the LCF queue + */ +static struct LCFContextQueue *lcfq_tail; + +/** + * The lcf_task handle + */ +static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id; + +/** + * The size of the route list + */ +static unsigned int route_list_size; + + +/** + * Adds a slave to the slave array + * + * @param slave the slave controller to add + */ +static void +slave_list_add (struct Slave *slave) +{ + if (slave->host_id >= GST_slave_list_size) + GST_array_grow_large_enough (GST_slave_list, GST_slave_list_size, + slave->host_id); + GNUNET_assert (NULL == GST_slave_list[slave->host_id]); + GST_slave_list[slave->host_id] = slave; +} + + +/** + * Adds a route to the route list + * + * @param route the route to add + */ +static void +route_list_add (struct Route *route) +{ + if (route->dest >= route_list_size) + GST_array_grow_large_enough (route_list, route_list_size, route->dest); + GNUNET_assert (NULL == route_list[route->dest]); + route_list[route->dest] = route; +} + + +/** + * Cleans up the route list + */ +void +GST_route_list_clear () +{ + unsigned int id; + + for (id = 0; id < route_list_size; id++) + if (NULL != route_list[id]) + GNUNET_free (route_list[id]); + GNUNET_free_non_null (route_list); + route_list = NULL; +} + + +/** + * Iterator for freeing hash map entries in a slave's reghost_map + * + * @param cls handle to the slave + * @param key current key code + * @param value value in the hash map + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +static int +reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key, + void *value) +{ + struct Slave *slave = cls; + struct RegisteredHostContext *rhc = value; + struct ForwardedOverlayConnectContext *focc; + + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key, + value)); + while (NULL != (focc = rhc->focc_dll_head)) + { + GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc); + GST_cleanup_focc (focc); + } + if (NULL != rhc->sub_op) + GNUNET_TESTBED_operation_done (rhc->sub_op); + if (NULL != rhc->client) + GNUNET_SERVER_client_drop (rhc->client); + GNUNET_free (value); + return GNUNET_YES; +} + + +/** + * Cleans up the slave list + */ +void +GST_slave_list_clear () +{ + unsigned int id; + struct HostRegistration *hr_entry; + + for (id = 0; id < GST_slave_list_size; id++) + if (NULL != GST_slave_list[id]) + { + while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head)) + { + GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head, + GST_slave_list[id]->hr_dll_tail, hr_entry); + GNUNET_free (hr_entry); + } + if (NULL != GST_slave_list[id]->rhandle) + GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle); + (void) + GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list + [id]->reghost_map, + reghost_free_iterator, + GST_slave_list[id]); + GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map); + if (NULL != GST_slave_list[id]->controller) + GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller); + if (NULL != GST_slave_list[id]->controller_proc) + GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc); + GNUNET_free (GST_slave_list[id]); + } + GNUNET_free_non_null (GST_slave_list); + GST_slave_list = NULL; +} + + +/** + * Finds the route with directly connected host as destination through which + * the destination host can be reached + * + * @param host_id the id of the destination host + * @return the route with directly connected destination host; NULL if no route + * is found + */ +struct Route * +GST_find_dest_route (uint32_t host_id) +{ + struct Route *route; + + if (route_list_size <= host_id) + return NULL; + while (NULL != (route = route_list[host_id])) + { + if (route->thru == GST_context->host_id) + break; + host_id = route->thru; + } + return route; +} + + +/** + * Function to send a failure reponse for controller link operation + * + * @param client the client to send the message to + * @param operation_id the operation ID of the controller link request + * @param cfg the configuration with which the delegated controller is started. + * Can be NULL if the delegated controller is not started but just + * linked to. + * @param emsg set to an error message explaining why the controller link + * failed. Setting this to NULL signifies success. !This should be + * NULL if cfg is set! + */ +static void +send_controller_link_response (struct GNUNET_SERVER_Client *client, + uint64_t operation_id, + const struct GNUNET_CONFIGURATION_Handle + *cfg, + const char *emsg) +{ + struct GNUNET_TESTBED_ControllerLinkResponse *msg; + char *xconfig; + size_t config_size; + size_t xconfig_size; + uint16_t msize; + + GNUNET_assert ((NULL == cfg) || (NULL == emsg)); + xconfig = NULL; + xconfig_size = 0; + config_size = 0; + msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse); + if (NULL != cfg) + { + xconfig = GNUNET_TESTBED_compress_cfg_ (cfg, + &config_size, + &xconfig_size); + msize += xconfig_size; + } + if (NULL != emsg) + msize += strlen (emsg); + msg = GNUNET_malloc (msize); + msg->header.type = htons + (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT); + msg->header.size = htons (msize); + if (NULL == emsg) + msg->success = htons (GNUNET_YES); + msg->operation_id = GNUNET_htonll (operation_id); + msg->config_size = htons ((uint16_t) config_size); + if (NULL != xconfig) + memcpy (&msg[1], xconfig, xconfig_size); + if (NULL != emsg) + memcpy (&msg[1], emsg, strlen (emsg)); + GST_queue_message (client, &msg->header); +} + + +/** + * The Link Controller forwarding task + * + * @param cls the LCFContext + * @param tc the Task context from scheduler + */ +static void +lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Completion callback for host registrations while forwarding Link Controller messages + * + * @param cls the LCFContext + * @param emsg the error message; NULL if host registration is successful + */ +static void +lcf_proc_cc (void *cls, const char *emsg) +{ + struct LCFContext *lcf = cls; + + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); + switch (lcf->state) + { + case INIT: + if (NULL != emsg) + goto registration_error; + lcf->state = DELEGATED_HOST_REGISTERED; + lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); + break; + case DELEGATED_HOST_REGISTERED: + if (NULL != emsg) + goto registration_error; + lcf->state = SLAVE_HOST_REGISTERED; + lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); + break; + default: + GNUNET_assert (0); /* Shouldn't reach here */ + } + return; + +registration_error: + LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n", + emsg); + lcf->state = FINISHED; + lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); +} + + +/** + * The Link Controller forwarding task + * + * @param cls the LCFContext + * @param tc the Task context from scheduler + */ +static void +lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Task to free resources when forwarded link controllers has been timedout + * + * @param cls the LCFContext + * @param tc the task context from scheduler + */ +static void +lcf_forwarded_operation_timeout (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct LCFContext *lcf = cls; + + lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK; + // GST_forwarded_operation_timeout (lcf->fopc, tc); + LOG (GNUNET_ERROR_TYPE_WARNING, + "A forwarded controller link operation has timed out\n"); + send_controller_link_response (lcf->client, lcf->operation_id, NULL, + "A forwarded controller link operation has " + "timed out\n"); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); + lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); +} + + +/** + * The Link Controller forwarding task + * + * @param cls the LCFContext + * @param tc the Task context from scheduler + */ +static void +lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct LCFContext *lcf = cls; + struct LCFContextQueue *lcfq; + + lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK; + switch (lcf->state) + { + case INIT: + if (GNUNET_NO == + GNUNET_TESTBED_is_host_registered_ (GST_host_list + [lcf->delegated_host_id], + lcf->gateway->controller)) + { + GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf, + GST_host_list[lcf->delegated_host_id]); + } + else + { + lcf->state = DELEGATED_HOST_REGISTERED; + lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); + } + break; + case DELEGATED_HOST_REGISTERED: + if (GNUNET_NO == + GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id], + lcf->gateway->controller)) + { + GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf, + GST_host_list[lcf->slave_host_id]); + } + else + { + lcf->state = SLAVE_HOST_REGISTERED; + lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); + } + break; + case SLAVE_HOST_REGISTERED: + lcf->op = GNUNET_TESTBED_controller_link (lcf, + lcf->gateway->controller, + GST_host_list[lcf->delegated_host_id], + GST_host_list[lcf->slave_host_id], + NULL, + lcf->is_subordinate); + lcf->timeout_task = + GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout, + lcf); + lcf->state = FINISHED; + break; + case FINISHED: + lcfq = lcfq_head; + GNUNET_assert (lcfq->lcf == lcf); + GNUNET_assert (NULL != lcf->cfg); + GNUNET_CONFIGURATION_destroy (lcf->cfg); + GNUNET_SERVER_client_drop (lcf->client); + GNUNET_TESTBED_operation_done (lcf->op); + GNUNET_free (lcf); + GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq); + GNUNET_free (lcfq); + if (NULL != lcfq_head) + lcf_proc_task_id = + GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf); + } +} + + +/** + * Callback for event from slave controllers + * + * @param cls struct Slave * + * @param event information about the event + */ +static void +slave_event_callback (void *cls, + const struct GNUNET_TESTBED_EventInformation *event) +{ + struct RegisteredHostContext *rhc; + struct LCFContext *lcf; + struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_TESTBED_Operation *old_op; + + /* We currently only get here when working on RegisteredHostContexts and + LCFContexts */ + GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type); + rhc = event->op_cls; + if (CLOSURE_TYPE_RHC == rhc->type) + { + GNUNET_assert (rhc->sub_op == event->op); + switch (rhc->state) + { + case RHC_GET_CFG: + cfg = event->details.operation_finished.generic; + old_op = rhc->sub_op; + rhc->state = RHC_LINK; + rhc->sub_op = + GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller, + rhc->reg_host, rhc->host, cfg, + GNUNET_NO); + GNUNET_TESTBED_operation_done (old_op); + break; + case RHC_LINK: + LOG_DEBUG ("OL: Linking controllers successfull\n"); + GNUNET_TESTBED_operation_done (rhc->sub_op); + rhc->sub_op = NULL; + rhc->state = RHC_OL_CONNECT; + GST_process_next_focc (rhc); + break; + default: + GNUNET_assert (0); + } + return; + } + lcf = event->op_cls; + if (CLOSURE_TYPE_LCF == lcf->type) + { + GNUNET_assert (lcf->op == event->op); + GNUNET_assert (FINISHED == lcf->state); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task); + GNUNET_SCHEDULER_cancel (lcf->timeout_task); + if (NULL == event->details.operation_finished.emsg) + send_controller_link_response (lcf->client, lcf->operation_id, + GNUNET_TESTBED_host_get_cfg_ + (GST_host_list[lcf->delegated_host_id]), + NULL); + else + send_controller_link_response (lcf->client, lcf->operation_id, + NULL, + event->details.operation_finished.emsg); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); + lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); + return; + } + GNUNET_assert (0); +} + + +/** + * Callback to signal successfull startup of the controller process + * + * @param cls the handle to the slave whose status is to be found here + * @param cfg the configuration with which the controller has been started; + * NULL if status is not GNUNET_OK + * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not, + * GNUNET_TESTBED_controller_stop() shouldn't be called in this case + */ +static void +slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, + int status) +{ + struct Slave *slave = cls; + struct LinkControllersContext *lcc; + + lcc = slave->lcc; + if (GNUNET_SYSERR == status) + { + slave->controller_proc = NULL; + GST_slave_list[slave->host_id] = NULL; + GNUNET_free (slave); + slave = NULL; + LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n"); + GNUNET_SCHEDULER_shutdown (); /* We too shutdown */ + goto clean_lcc; + } + slave->controller = + GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id], + EVENT_MASK, &slave_event_callback, + slave); + if (NULL != slave->controller) + { + send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL); + } + else + { + send_controller_link_response (lcc->client, lcc->operation_id, NULL, + "Could not connect to delegated controller"); + GNUNET_TESTBED_controller_stop (slave->controller_proc); + GST_slave_list[slave->host_id] = NULL; + GNUNET_free (slave); + slave = NULL; + } + +clean_lcc: + if (NULL != lcc) + { + if (NULL != lcc->client) + { + GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK); + GNUNET_SERVER_client_drop (lcc->client); + lcc->client = NULL; + } + GNUNET_free (lcc); + } + if (NULL != slave) + slave->lcc = NULL; +} + + +/** + * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message + * + * @param cls NULL + * @param client identification of the client + * @param message the actual message + */ +void +GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_TESTBED_ControllerLinkRequest *msg; + struct GNUNET_CONFIGURATION_Handle *cfg; + struct LCFContextQueue *lcfq; + struct Route *route; + struct Route *new_route; + uint32_t delegated_host_id; + uint32_t slave_host_id; + uint16_t msize; + + if (NULL == GST_context) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + msize = ntohs (message->size); + if (sizeof (struct GNUNET_TESTBED_ControllerLinkRequest) >= msize) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message; + delegated_host_id = ntohl (msg->delegated_host_id); + if (delegated_host_id == GST_context->host_id) + { + GNUNET_break (0); + LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n"); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if ((delegated_host_id >= GST_host_list_size) || + (NULL == GST_host_list[delegated_host_id])) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + "Delegated host %u not registered with us\n", delegated_host_id); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + slave_host_id = ntohl (msg->slave_host_id); + if ((slave_host_id >= GST_host_list_size) || + (NULL == GST_host_list[slave_host_id])) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n", + slave_host_id); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if (slave_host_id == delegated_host_id) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n"); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + cfg = GNUNET_TESTBED_extract_config_ (message); /* destroy cfg here or in lcfcontext */ + if (NULL == cfg) + { + GNUNET_break (0); /* Configuration parsing error */ + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if (slave_host_id == GST_context->host_id) /* Link from us */ + { + struct Slave *slave; + struct LinkControllersContext *lcc; + + if ((delegated_host_id < GST_slave_list_size) && + (NULL != GST_slave_list[delegated_host_id])) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + slave = GNUNET_malloc (sizeof (struct Slave)); + slave->host_id = delegated_host_id; + slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO); + slave_list_add (slave); + if (1 != msg->is_subordinate) + { + slave->controller = + GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id], + EVENT_MASK, &slave_event_callback, + slave); + if (NULL != slave->controller) + send_controller_link_response (client, + GNUNET_ntohll (msg->operation_id), + NULL, + NULL); + else + send_controller_link_response (client, + GNUNET_ntohll (msg->operation_id), + NULL, + "Could not connect to delegated controller"); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + lcc = GNUNET_malloc (sizeof (struct LinkControllersContext)); + lcc->operation_id = GNUNET_ntohll (msg->operation_id); + GNUNET_SERVER_client_keep (client); + lcc->client = client; + slave->lcc = lcc; + slave->controller_proc = + GNUNET_TESTBED_controller_start (GST_context->master_ip, + GST_host_list[slave->host_id], cfg, + &slave_status_callback, slave); + GNUNET_CONFIGURATION_destroy (cfg); + new_route = GNUNET_malloc (sizeof (struct Route)); + new_route->dest = delegated_host_id; + new_route->thru = GST_context->host_id; + route_list_add (new_route); + return; + } + + /* Route the request */ + if (slave_host_id >= route_list_size) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host"); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue)); + lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext)); + lcfq->lcf->type = CLOSURE_TYPE_LCF; + lcfq->lcf->delegated_host_id = delegated_host_id; + lcfq->lcf->slave_host_id = slave_host_id; + route = GST_find_dest_route (slave_host_id); + GNUNET_assert (NULL != route); /* because we add routes carefully */ + GNUNET_assert (route->dest < GST_slave_list_size); + GNUNET_assert (NULL != GST_slave_list[route->dest]); + lcfq->lcf->cfg = cfg; + lcfq->lcf->is_subordinate = msg->is_subordinate; + lcfq->lcf->state = INIT; + lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id); + lcfq->lcf->gateway = GST_slave_list[route->dest]; + GNUNET_SERVER_client_keep (client); + lcfq->lcf->client = client; + if (NULL == lcfq_head) + { + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); + GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq); + lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf); + } + else + GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq); + /* FIXME: Adding a new route should happen after the controllers are linked + * successfully */ + if (1 != msg->is_subordinate) + { + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + if ((delegated_host_id < route_list_size) && + (NULL != route_list[delegated_host_id])) + { + GNUNET_break_op (0); /* Are you trying to link delegated host twice + * with is subordinate flag set to GNUNET_YES? */ + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + new_route = GNUNET_malloc (sizeof (struct Route)); + new_route->dest = delegated_host_id; + new_route->thru = route->dest; + route_list_add (new_route); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Cleans up the queue used for forwarding link controllers requests + */ +void +GST_free_lcfq () +{ + struct LCFContextQueue *lcfq; + + if (NULL != lcfq_head) + { + if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id) + { + GNUNET_SCHEDULER_cancel (lcf_proc_task_id); + lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK; + } + } + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); + for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head) + { + GNUNET_SERVER_client_drop (lcfq->lcf->client); + GNUNET_assert (NULL != lcfq->lcf->cfg); + GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg); + GNUNET_free (lcfq->lcf); + GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq); + GNUNET_free (lcfq); + } +} |