X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftestbed%2Fgnunet-service-testbed_links.c;h=7b0006d1fbf22e34cae44ad808de543fce8e5d49;hb=a900b29ddaa9ea46c731b054b5e3ef3e725b95a8;hp=0ee8c63858441a772abbff1f0cc679da5a84ae0d;hpb=b4c73ec17d2446202b3f5f21bc512c0c91774020;p=oweals%2Fgnunet.git diff --git a/src/testbed/gnunet-service-testbed_links.c b/src/testbed/gnunet-service-testbed_links.c index 0ee8c6385..7b0006d1f 100644 --- a/src/testbed/gnunet-service-testbed_links.c +++ b/src/testbed/gnunet-service-testbed_links.c @@ -74,11 +74,6 @@ enum LCFContextState */ struct LCFContext { - /** - * The type of this data structure. Set this to CLOSURE_TYPE_LCF - */ - enum ClosureType type; - /** * The gateway which will pass the link message to delegated host */ @@ -148,15 +143,40 @@ struct LCFContextQueue struct LCFContextQueue *prev; }; + +/** + * Notification context to be used to notify when connection to the neighbour's + * controller is opened + */ struct NeighbourConnectNotification { + /** + * DLL next for inclusion in neighbour's list of notification requests + */ struct NeighbourConnectNotification *next; + + /** + * DLL prev + */ struct NeighbourConnectNotification *prev; + + /** + * The neighbour + */ struct Neighbour *n; + + /** + * The notification callback to call when we are connect to neighbour + */ GST_NeigbourConnectNotifyCallback cb; + + /** + * The closure for the above callback + */ void *cb_cls; }; - + + /** * A connected controller which is not our child */ @@ -173,39 +193,100 @@ struct Neighbour */ struct GNUNET_TESTBED_Operation *conn_op; + /** + * DLL head for the list of notification requests + */ struct NeighbourConnectNotification *nl_head; + /** + * DLL tail for the list of notification requests + */ struct NeighbourConnectNotification *nl_tail; + /** + * Task id for the task to call notifications from the notification list + */ GNUNET_SCHEDULER_TaskIdentifier notify_task; + /** + * How many references are present currently to this neighbour's connection + */ unsigned int reference_cnt; + /** + * Is the conn_op inactivated? + */ unsigned int inactive; - /** * The id of the host this controller is running on */ - uint32_t host_id; - + uint32_t host_id; }; + +/** + * The neighbour list + */ static struct Neighbour **neighbour_list; + +/** + * The size of the neighbour list + */ static unsigned int neighbour_list_size; + +/** + * Context information for establishing a link to neighbour (Used is + * GST_handle_link_controllers() + */ struct NeighbourConnectCtxt { + /** + * DLL next for inclusion in the corresponding context list + */ struct NeighbourConnectCtxt *next; + + /** + * DLL tail + */ struct NeighbourConnectCtxt *prev; + + /** + * The neighbour to whom connection should be made + */ struct Neighbour *n; + + /** + * The client requesting the connection + */ struct GNUNET_SERVER_Client *client; + + /** + * Task to be run upon timeout + */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * The notification handle associated with the neighbour's connection request + */ struct NeighbourConnectNotification *nh; + + /** + * The id of the link-controllers operation responsible for creating this + * context + */ uint64_t op_id; }; +/** + * DLL head for the list of neighbour connect contexts + */ struct NeighbourConnectCtxt *ncc_head; + +/** + * DLL tail for the list of neighbour connect contexts + */ struct NeighbourConnectCtxt *ncc_tail; /** @@ -274,6 +355,13 @@ route_list_add (struct Route *route) route_list[route->dest] = route; } + +/** + * Add a neighbour to the neighbour list. Grows the neighbour list + * automatically. + * + * @param n the neighbour to add + */ static void neighbour_list_add (struct Neighbour *n) { @@ -326,10 +414,6 @@ reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key, 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; } @@ -341,32 +425,47 @@ reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key, void GST_slave_list_clear () { - unsigned int id; struct HostRegistration *hr_entry; + struct GNUNET_TESTBED_ControllerProc *cproc; + unsigned int id; for (id = 0; id < GST_slave_list_size; id++) - if (NULL != GST_slave_list[id]) + { + if (NULL == GST_slave_list[id]) + continue; + while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head)) { - 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_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 != (cproc = GST_slave_list[id]->controller_proc)) + { + LOG_DEBUG ("Stopping a slave\n"); + GNUNET_TESTBED_controller_kill_ (cproc); } + } + for (id = 0; id < GST_slave_list_size; id++) + { + if (NULL == GST_slave_list[id]) + continue; + if (NULL != (cproc = GST_slave_list[id]->controller_proc)) + { + GNUNET_TESTBED_controller_destroy_ (cproc); + LOG_DEBUG ("Slave stopped\n"); + } + GNUNET_free (GST_slave_list[id]); + } GNUNET_free_non_null (GST_slave_list); GST_slave_list = NULL; } @@ -587,7 +686,6 @@ lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 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, @@ -616,71 +714,32 @@ lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) * @param event information about the event */ static void -slave_event_callback (void *cls, - const struct GNUNET_TESTBED_EventInformation *event) +slave_event_cb (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); + 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; } -static void -slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, - int status); /** * Callback to signal successfull startup of the controller process @@ -692,8 +751,8 @@ slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, * 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) +slave_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, + int status) { struct Slave *slave = cls; struct LinkControllersContext *lcc; @@ -711,7 +770,7 @@ slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, } slave->controller = GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id], - EVENT_MASK, &slave_event_callback, + EVENT_MASK, &slave_event_cb, slave); if (NULL != slave->controller) { @@ -742,10 +801,52 @@ clean_lcc: slave->lcc = NULL; } + +/** + * Trigger notification task if there are notification requests currently + * waiting in the given neighbour. Also activates the neighbour connect operation + * if it was previously inactivated so that the connection to the neighbour can + * be re-used + * + * @param n the neighbour + */ +static void +trigger_notifications (struct Neighbour *n); + + +/** + * Task to call the notification queued in the notifications list of the given + * neighbour + * + * @param cls the neighbour + * @param tc scheduler task context + */ static void neighbour_connect_notify_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc); + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Neighbour *n = cls; + struct NeighbourConnectNotification *h; + + GNUNET_assert (NULL != (h = n->nl_head)); + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->notify_task); + n->notify_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (NULL != n->controller); + GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h); + trigger_notifications (n); + h->cb (h->cb_cls, n->controller); + GNUNET_free (h); +} + +/** + * Trigger notification task if there are notification requests currently + * waiting in the given neighbour. Also activates the neighbour connect operation + * if it was previously inactivated so that the connection to the neighbour can + * be re-used + * + * @param n the neighbour + */ static void trigger_notifications (struct Neighbour *n) { @@ -762,28 +863,19 @@ trigger_notifications (struct Neighbour *n) GNUNET_TESTBED_operation_activate_ (n->conn_op); n->inactive = 0; } + n->reference_cnt++; n->notify_task = - GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n->nl_head); + GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n); } -static void -neighbour_connect_notify_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct NeighbourConnectNotification *h = cls; - struct Neighbour *n; - - n = h->n; - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->notify_task); - n->notify_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_assert (NULL != n->controller); - GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h); - trigger_notifications (n); - n->reference_cnt++; - h->cb (h->cb_cls, n->controller); - GNUNET_free (h); -} +/** + * Callback to be called when the neighbour connect operation is started. The + * connection to the neigbour is opened here and any pending notifications are + * trigger. + * + * @param cls the neighbour + */ static void opstart_neighbour_conn (void *cls) { @@ -794,11 +886,17 @@ opstart_neighbour_conn (void *cls) LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id); n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id], EVENT_MASK, - &slave_event_callback, + &slave_event_cb, NULL); trigger_notifications (n); } + +/** + * Callback to be called when the neighbour connect operation is released + * + * @param cls the neighbour + */ static void oprelease_neighbour_conn (void *cls) { @@ -817,6 +915,18 @@ oprelease_neighbour_conn (void *cls) n->inactive = 0; } + +/** + * Try to open a connection to the given neigbour. If the connection is open + * already, then it is re-used. If not, the request is queued in the operation + * queues responsible for bounding the total number of file descriptors. The + * actual connection will happen when the operation queue marks the + * corresponding operation as active. + * + * @param n the neighbour to open a connection to + * @param cb the notification callback to call when the connection is opened + * @param cb_cls the closure for the above callback + */ struct NeighbourConnectNotification * GST_neighbour_get_connection (struct Neighbour *n, GST_NeigbourConnectNotifyCallback cb, @@ -845,20 +955,28 @@ GST_neighbour_get_connection (struct Neighbour *n, return h; } + +/** + * Cancel the request for opening a connection to the neighbour + * + * @param h the notification handle + */ void GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h) { struct Neighbour *n; int cleanup_task; - cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO; n = h->n; + cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO; GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h); GNUNET_free (h); if (GNUNET_NO == cleanup_task) return; if (GNUNET_SCHEDULER_NO_TASK == n->notify_task) return; + GNUNET_assert (0 < n->reference_cnt); + n->reference_cnt--; GNUNET_SCHEDULER_cancel (n->notify_task); n->notify_task = GNUNET_SCHEDULER_NO_TASK; if (NULL == n->nl_head) @@ -873,6 +991,14 @@ GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h) trigger_notifications (n); } + +/** + * Release the connection to the neighbour. The actual connection will be + * closed if connections to other neighbour are waiting (to maintain a bound on + * the total number of connections that are open). + * + * @param n the neighbour whose connection can be closed + */ void GST_neighbour_release_connection (struct Neighbour *n) { @@ -886,6 +1012,12 @@ GST_neighbour_release_connection (struct Neighbour *n) } } + +/** + * Cleanup neighbour connect contexts + * + * @param ncc the neighbour connect context to cleanup + */ static void cleanup_ncc (struct NeighbourConnectCtxt *ncc) { @@ -898,6 +1030,10 @@ cleanup_ncc (struct NeighbourConnectCtxt *ncc) GNUNET_free (ncc); } + +/** + * Cleans up the neighbour list + */ void GST_neighbour_list_clean() { @@ -916,6 +1052,14 @@ GST_neighbour_list_clean() GNUNET_free_non_null (neighbour_list); } + +/** + * Get a neighbour from the neighbour list + * + * @param id the index of the neighbour in the neighbour list + * @return the Neighbour; NULL if the given index in invalid (index greater than + * the list size or neighbour at that index is NULL) + */ struct Neighbour * GST_get_neighbour (uint32_t id) { @@ -925,6 +1069,10 @@ GST_get_neighbour (uint32_t id) return neighbour_list[id]; } + +/** + * Function to cleanup the neighbour connect contexts + */ void GST_free_nccq () { @@ -932,6 +1080,13 @@ GST_free_nccq () cleanup_ncc (ncc_head); } + +/** + * Task to be run upon timeout while attempting to connect to the neighbour + * + * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers() + * @param tc the scheduler task context + */ static void timeout_neighbour_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) @@ -944,6 +1099,13 @@ timeout_neighbour_connect (void *cls, cleanup_ncc (ncc); } + +/** + * Callback called when a connection to the neighbour is made + * + * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers() + * @param c the handle the neighbour's controller + */ static void neighbour_connect_cb (void *cls, struct GNUNET_TESTBED_Controller *c) { @@ -957,6 +1119,24 @@ neighbour_connect_cb (void *cls, struct GNUNET_TESTBED_Controller *c) cleanup_ncc (ncc); } + +/** + * Function to create a neigbour and add it into the neighbour list + * + * @param host the host of the neighbour + */ +struct Neighbour * +GST_create_neighbour (struct GNUNET_TESTBED_Host *host) +{ + struct Neighbour *n; + + n = GNUNET_malloc (sizeof (struct Neighbour)); + n->host_id = GNUNET_TESTBED_host_get_id_ (host); + neighbour_list_add (n); /* just add; connect on-demand */ + return n; +} + + /** * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message * @@ -1035,9 +1215,7 @@ GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client, } LOG_DEBUG ("Received request to establish a link to host %u\n", delegated_host_id); - n = GNUNET_malloc (sizeof (struct Neighbour)); - n->host_id = delegated_host_id; - neighbour_list_add (n); /* just add; connect on-demand */ + n = GST_create_neighbour (GST_host_list[delegated_host_id]); ncc = GNUNET_malloc (sizeof (struct NeighbourConnectCtxt)); ncc->n = n; ncc->op_id = op_id; @@ -1072,7 +1250,7 @@ GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client, slave->controller_proc = GNUNET_TESTBED_controller_start (GST_context->master_ip, GST_host_list[slave->host_id], - &slave_status_callback, slave); + &slave_status_cb, slave); new_route = GNUNET_malloc (sizeof (struct Route)); new_route->dest = delegated_host_id; new_route->thru = GST_context->host_id; @@ -1089,7 +1267,6 @@ GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client, } 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);