X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftestbed%2Fgnunet-service-testbed_links.c;h=766c47471342f36919a906324d521bfc23cd8e59;hb=27c12911f4f2aba2d90099270d70de846e83854f;hp=6209bf248270f46158dc2caac4399d8820ca3db5;hpb=460223a5a382c80881b4fb01b17e592d98af0a39;p=oweals%2Fgnunet.git diff --git a/src/testbed/gnunet-service-testbed_links.c b/src/testbed/gnunet-service-testbed_links.c index 6209bf248..766c47471 100644 --- a/src/testbed/gnunet-service-testbed_links.c +++ b/src/testbed/gnunet-service-testbed_links.c @@ -4,7 +4,7 @@ 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 + by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but @@ -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 */ @@ -103,7 +98,7 @@ struct LCFContext * The id of the operation which created this context */ uint64_t operation_id; - + /** * should the slave controller start the delegated controller? */ @@ -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 */ @@ -166,46 +186,107 @@ struct Neighbour * The controller handle */ struct GNUNET_TESTBED_Controller *controller; - + /** * Operation handle for opening a lateral connection to another controller. * Will be NULL if the slave controller is started by this controller */ 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; - }; + +/** + * 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) { @@ -291,7 +379,7 @@ 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]); @@ -326,47 +414,85 @@ 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; } +/** + * Kill a #Slave object + * + * @param slave the #Slave object + */ +static void +kill_slave (struct Slave *slave) +{ + struct HostRegistration *hr_entry; + + while (NULL != (hr_entry = slave->hr_dll_head)) + { + GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail, + hr_entry); + GNUNET_free (hr_entry); + } + if (NULL != slave->rhandle) + GNUNET_TESTBED_cancel_registration (slave->rhandle); + GNUNET_assert (GNUNET_SYSERR != + GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map, + reghost_free_iterator, + slave)); + GNUNET_CONTAINER_multihashmap_destroy (slave->reghost_map); + if (NULL != slave->controller) + GNUNET_TESTBED_controller_disconnect (slave->controller); + if (NULL != slave->controller_proc) + { + LOG_DEBUG ("Stopping a slave\n"); + GNUNET_TESTBED_controller_kill_ (slave->controller_proc); + } +} + + +/** + * Destroy a #Slave object + * + * @param slave the #Slave object + */ +static void +destroy_slave (struct Slave *slave) +{ + if (NULL != slave->controller_proc) + { + GNUNET_TESTBED_controller_destroy_ (slave->controller_proc); + LOG_DEBUG ("Slave stopped\n"); + } + GST_slave_list[slave->host_id] = NULL; + GNUNET_free (slave); +} + + /** * Cleans up the slave list */ void GST_slave_list_clear () { + struct Slave *slave; 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]); - } + { + slave = GST_slave_list[id]; + if (NULL == slave) + continue; + kill_slave (slave); + } + for (id = 0; id < GST_slave_list_size; id++) + { + slave = GST_slave_list[id]; + if (NULL == slave) + continue; + destroy_slave (slave); + } GNUNET_free_non_null (GST_slave_list); GST_slave_list = NULL; } @@ -419,7 +545,7 @@ send_controller_link_response (struct GNUNET_SERVER_Client *client, struct GNUNET_TESTBED_ControllerLinkResponse *msg; char *xconfig; size_t config_size; - size_t xconfig_size; + size_t xconfig_size; uint16_t msize; GNUNET_assert ((NULL == cfg) || (NULL == emsg)); @@ -597,7 +723,8 @@ lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) lcfq = lcfq_head; GNUNET_assert (lcfq->lcf == lcf); GNUNET_SERVER_client_drop (lcf->client); - GNUNET_TESTBED_operation_done (lcf->op); + if (NULL != lcf->op) + GNUNET_TESTBED_operation_done (lcf->op); GNUNET_free (lcf); GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq); GNUNET_free (lcfq); @@ -615,68 +742,33 @@ 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_TESTBED_Operation *old_op; - /* We currently only get here when working on RegisteredHostContexts and - LCFContexts */ + /* We currently only get here when working on 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: - 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, 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_TESTBED_operation_done (lcf->op); + lcf->op = NULL; + 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 @@ -688,8 +780,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; @@ -698,8 +790,13 @@ slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, if (GNUNET_SYSERR == status) { slave->controller_proc = NULL; - GST_slave_list[slave->host_id] = NULL; - GNUNET_free (slave); + /* Stop all link controller forwarding tasks since we shutdown here anyway + and as these tasks they depend on the operation queues which are created + through GNUNET_TESTBED_controller_connect() and in kill_slave() we call + the destructor function GNUNET_TESTBED_controller_disconnect() */ + GST_free_lcfq (); + kill_slave (slave); + destroy_slave (slave); slave = NULL; LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n"); GNUNET_SCHEDULER_shutdown (); /* We too shutdown */ @@ -707,7 +804,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) { @@ -717,13 +814,12 @@ slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, { 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); + kill_slave (slave); + destroy_slave (slave); slave = NULL; } -clean_lcc: + clean_lcc: if (NULL != lcc) { if (NULL != lcc->client) @@ -738,10 +834,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 -neighbour_connect_notify_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc); +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) +{ + 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) { @@ -751,7 +889,7 @@ trigger_notifications (struct Neighbour *n) if (NULL == n->controller) return; if (GNUNET_SCHEDULER_NO_TASK != n->notify_task) - return; + return; if (1 == n->inactive) { GNUNET_assert (0 == n->reference_cnt); @@ -759,42 +897,39 @@ trigger_notifications (struct Neighbour *n) n->inactive = 0; } n->reference_cnt++; - n->notify_task = + n->notify_task = GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n); } -static void -neighbour_connect_notify_task (void *cls, - 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); -} +/** + * 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) { struct Neighbour *n = cls; - + GNUNET_assert (NULL != n->conn_op); GNUNET_assert (NULL == n->controller); 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) { @@ -813,6 +948,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, @@ -841,12 +988,18 @@ 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; - + n = h->n; cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO; GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h); @@ -871,6 +1024,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) { @@ -884,6 +1045,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) { @@ -896,6 +1063,10 @@ cleanup_ncc (struct NeighbourConnectCtxt *ncc) GNUNET_free (ncc); } + +/** + * Cleans up the neighbour list + */ void GST_neighbour_list_clean() { @@ -914,6 +1085,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) { @@ -923,6 +1102,10 @@ GST_get_neighbour (uint32_t id) return neighbour_list[id]; } + +/** + * Function to cleanup the neighbour connect contexts + */ void GST_free_nccq () { @@ -930,8 +1113,15 @@ 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, +timeout_neighbour_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct NeighbourConnectCtxt *ncc = cls; @@ -942,6 +1132,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) { @@ -955,6 +1152,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 * @@ -1018,7 +1233,7 @@ GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client, struct Slave *slave; struct LinkControllersContext *lcc; - + if (1 != msg->is_subordinate) { struct Neighbour *n; @@ -1033,19 +1248,17 @@ 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; ncc->client = client; - GNUNET_SERVER_client_keep (client); + GNUNET_SERVER_client_keep (client); ncc->nh = GST_neighbour_get_connection (n, neighbour_connect_cb, ncc); ncc->timeout_task = GNUNET_SCHEDULER_add_delayed (GST_timeout, &timeout_neighbour_connect, ncc); - GNUNET_CONTAINER_DLL_insert_tail (ncc_head, ncc_tail, ncc); + GNUNET_CONTAINER_DLL_insert_tail (ncc_head, ncc_tail, ncc); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } @@ -1070,7 +1283,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; @@ -1087,7 +1300,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); @@ -1138,7 +1350,8 @@ void GST_free_lcfq () { struct LCFContextQueue *lcfq; - + struct LCFContext *lcf; + if (NULL != lcfq_head) { if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id) @@ -1150,8 +1363,13 @@ GST_free_lcfq () 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_free (lcfq->lcf); + lcf = lcfq->lcf; + GNUNET_SERVER_client_drop (lcf->client); + if (NULL != lcf->op) + GNUNET_TESTBED_operation_done (lcf->op); + if (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task) + GNUNET_SCHEDULER_cancel (lcf->timeout_task); + GNUNET_free (lcf); GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq); GNUNET_free (lcfq); }