2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file testbed/gnunet-service-testbed_links.c
23 * @brief TESTBED service components that deals with starting slave controllers
24 * and establishing lateral links between controllers
25 * @author Sree Harsha Totakura
28 #include "gnunet-service-testbed.h"
31 * Redefine LOG with a changed log component string
36 #define LOG(kind,...) \
37 GNUNET_log_from (kind, "testbed-links", __VA_ARGS__)
40 * The event mask for the events we listen from sub-controllers
42 #define EVENT_MASK (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED)
46 * States of LCFContext
51 * The Context has been initialized; Nothing has been done on it
56 * Delegated host has been registered at the forwarding controller
58 DELEGATED_HOST_REGISTERED,
61 * The slave host has been registred at the forwarding controller
63 SLAVE_HOST_REGISTERED,
66 * The context has been finished (may have error)
73 * Link controllers request forwarding context
80 struct LCFContext *next;
85 struct LCFContext *prev;
88 * The gateway which will pass the link message to delegated host
90 struct Slave *gateway;
93 * The client which has asked to perform this operation
95 struct GNUNET_SERVICE_Client *client;
98 * Handle for operations which are forwarded while linking controllers
100 struct GNUNET_TESTBED_Operation *op;
105 struct GNUNET_SCHEDULER_Task *timeout_task;
108 * The id of the operation which created this context
110 uint64_t operation_id;
113 * should the slave controller start the delegated controller?
118 * The state of this context
120 enum LCFContextState state;
125 uint32_t delegated_host_id;
130 uint32_t slave_host_id;
136 * Notification context to be used to notify when connection to the neighbour's
137 * controller is opened
139 struct NeighbourConnectNotification
142 * DLL next for inclusion in neighbour's list of notification requests
144 struct NeighbourConnectNotification *next;
149 struct NeighbourConnectNotification *prev;
157 * The notification callback to call when we are connect to neighbour
159 GST_NeigbourConnectNotifyCallback cb;
162 * The closure for the above callback
169 * A connected controller which is not our child
174 * The controller handle
176 struct GNUNET_TESTBED_Controller *controller;
179 * Operation handle for opening a lateral connection to another controller.
180 * Will be NULL if the slave controller is started by this controller
182 struct GNUNET_TESTBED_Operation *conn_op;
185 * DLL head for the list of notification requests
187 struct NeighbourConnectNotification *nl_head;
190 * DLL tail for the list of notification requests
192 struct NeighbourConnectNotification *nl_tail;
195 * Task id for the task to call notifications from the notification list
197 struct GNUNET_SCHEDULER_Task * notify_task;
200 * How many references are present currently to this neighbour's connection
202 unsigned int reference_cnt;
205 * Is the conn_op inactivated?
207 unsigned int inactive;
210 * The id of the host this controller is running on
219 static struct Neighbour **neighbour_list;
222 * The size of the neighbour list
224 static unsigned int neighbour_list_size;
228 * Context information for establishing a link to neighbour (Used is
229 * GST_handle_link_controllers()
231 struct NeighbourConnectCtxt
234 * DLL next for inclusion in the corresponding context list
236 struct NeighbourConnectCtxt *next;
241 struct NeighbourConnectCtxt *prev;
244 * The neighbour to whom connection should be made
249 * The client requesting the connection
251 struct GNUNET_SERVICE_Client *client;
254 * Task to be run upon timeout
256 struct GNUNET_SCHEDULER_Task *timeout_task;
259 * The notification handle associated with the neighbour's connection request
261 struct NeighbourConnectNotification *nh;
264 * The id of the link-controllers operation responsible for creating this
271 * DLL head for the list of neighbour connect contexts
273 struct NeighbourConnectCtxt *ncc_head;
276 * DLL tail for the list of neighbour connect contexts
278 struct NeighbourConnectCtxt *ncc_tail;
281 * A list of directly linked neighbours
283 struct Slave **GST_slave_list;
286 * The size of directly linked neighbours list
288 unsigned int GST_slave_list_size;
293 static struct Route **route_list;
298 static struct LCFContext *lcf_head;
301 * The tail for the LCF queue
303 static struct LCFContext *lcf_tail;
306 * The lcf_task handle
308 static struct GNUNET_SCHEDULER_Task * lcf_proc_task_id;
311 * The size of the route list
313 static unsigned int route_list_size;
317 * Adds a slave to the slave array
319 * @param slave the slave controller to add
322 slave_list_add (struct Slave *slave)
324 if (slave->host_id >= GST_slave_list_size)
325 GST_array_grow_large_enough (GST_slave_list,
328 GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
329 GST_slave_list[slave->host_id] = slave;
334 * Clean up all forwarded operation overlay context matching the
335 * client given in @a cls.
337 * @param cls a `struct GNUNET_SERVICE_Client *` to match
339 * @param value the `struct RegisteredHostContext` to search for @a cls
340 * @return #GNUNET_OK (continue iterating)
343 drop_client_entries (void *cls,
344 const struct GNUNET_HashCode *key,
347 struct GNUNET_SERVICE_Client *client = cls;
348 struct RegisteredHostContext *rhc = value;
349 struct ForwardedOverlayConnectContext *focc;
350 struct ForwardedOverlayConnectContext *foccn;
352 for (focc = rhc->focc_dll_head; NULL != focc; focc = foccn)
355 if (focc->client == client)
356 GST_cleanup_focc (focc);
363 * Adds a route to the route list
365 * @param route the route to add
368 route_list_add (struct Route *route)
370 if (route->dest >= route_list_size)
371 GST_array_grow_large_enough (route_list, route_list_size, route->dest);
372 GNUNET_assert (NULL == route_list[route->dest]);
373 route_list[route->dest] = route;
378 * Add a neighbour to the neighbour list. Grows the neighbour list
381 * @param n the neighbour to add
384 neighbour_list_add (struct Neighbour *n)
386 if (n->host_id >= neighbour_list_size)
387 GST_array_grow_large_enough (neighbour_list, neighbour_list_size, n->host_id);
388 GNUNET_assert (NULL == neighbour_list[n->host_id]);
389 neighbour_list[n->host_id] = n;
394 * Cleans up the route list
397 GST_route_list_clear ()
401 for (id = 0; id < route_list_size; id++)
402 if (NULL != route_list[id])
403 GNUNET_free (route_list[id]);
404 GNUNET_free_non_null (route_list);
410 * Iterator for freeing hash map entries in a slave's reghost_map
412 * @param cls handle to the slave
413 * @param key current key code
414 * @param value value in the hash map
415 * @return #GNUNET_YES if we should continue to iterate,
419 reghost_free_iterator (void *cls,
420 const struct GNUNET_HashCode *key,
423 struct Slave *slave = cls;
424 struct RegisteredHostContext *rhc = value;
425 struct ForwardedOverlayConnectContext *focc;
427 GNUNET_assert (GNUNET_YES ==
428 GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
430 while (NULL != (focc = rhc->focc_dll_head))
431 GST_cleanup_focc (focc);
438 * Kill a #Slave object
440 * @param slave the #Slave object
443 kill_slave (struct Slave *slave)
445 struct HostRegistration *hr_entry;
447 while (NULL != (hr_entry = slave->hr_dll_head))
449 GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail,
451 GNUNET_free (hr_entry);
453 if (NULL != slave->rhandle)
454 GNUNET_TESTBED_cancel_registration (slave->rhandle);
455 GNUNET_assert (GNUNET_SYSERR !=
456 GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map,
457 reghost_free_iterator,
459 GNUNET_CONTAINER_multihashmap_destroy (slave->reghost_map);
460 if (NULL != slave->controller)
461 GNUNET_TESTBED_controller_disconnect (slave->controller);
462 if (NULL != slave->controller_proc)
464 LOG_DEBUG ("Stopping a slave\n");
465 GNUNET_TESTBED_controller_kill_ (slave->controller_proc);
471 * Destroy a #Slave object
473 * @param slave the #Slave object
476 destroy_slave (struct Slave *slave)
478 if (NULL != slave->controller_proc)
480 GNUNET_TESTBED_controller_destroy_ (slave->controller_proc);
481 LOG_DEBUG ("Slave stopped\n");
483 GST_slave_list[slave->host_id] = NULL;
489 * Cleans up the slave list
492 GST_slave_list_clear ()
497 for (id = 0; id < GST_slave_list_size; id++)
499 slave = GST_slave_list[id];
504 for (id = 0; id < GST_slave_list_size; id++)
506 slave = GST_slave_list[id];
509 destroy_slave (slave);
511 GNUNET_free_non_null (GST_slave_list);
512 GST_slave_list = NULL;
517 * Finds the route with directly connected host as destination through which
518 * the destination host can be reached
520 * @param host_id the id of the destination host
521 * @return the route with directly connected destination host; NULL if no route
525 GST_find_dest_route (uint32_t host_id)
529 if (route_list_size <= host_id)
531 while (NULL != (route = route_list[host_id]))
533 if (route->thru == GST_context->host_id)
535 host_id = route->thru;
542 * Function to send a failure reponse for controller link operation
544 * @param client the client to send the message to
545 * @param operation_id the operation ID of the controller link request
546 * @param cfg the configuration with which the delegated controller is started.
547 * Can be NULL if the delegated controller is not started but just
549 * @param emsg set to an error message explaining why the controller link
550 * failed. Setting this to NULL signifies success. !This should be
551 * NULL if cfg is set!
554 send_controller_link_response (struct GNUNET_SERVICE_Client *client,
555 uint64_t operation_id,
556 const struct GNUNET_CONFIGURATION_Handle *cfg,
559 struct GNUNET_MQ_Envelope *env;
560 struct GNUNET_TESTBED_ControllerLinkResponse *msg;
566 GNUNET_assert ((NULL == cfg) || (NULL == emsg));
573 xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
576 msize += xconfig_size;
579 msize += strlen (emsg);
580 env = GNUNET_MQ_msg_extra (msg,
582 GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
584 msg->success = htons (GNUNET_YES);
585 msg->operation_id = GNUNET_htonll (operation_id);
586 msg->config_size = htons ((uint16_t) config_size);
589 GNUNET_memcpy (&msg[1],
592 GNUNET_free (xconfig);
595 GNUNET_memcpy (&msg[1],
598 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
604 * The Link Controller forwarding task
606 * @param cls the LCFContext
609 lcf_proc_task (void *cls);
613 * Completion callback for host registrations while forwarding Link Controller messages
615 * @param cls the LCFContext
616 * @param emsg the error message; NULL if host registration is successful
619 lcf_proc_cc (void *cls,
622 struct LCFContext *lcf = cls;
624 GNUNET_assert (NULL == lcf_proc_task_id);
629 goto registration_error;
630 lcf->state = DELEGATED_HOST_REGISTERED;
631 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
633 case DELEGATED_HOST_REGISTERED:
635 goto registration_error;
636 lcf->state = SLAVE_HOST_REGISTERED;
637 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
640 GNUNET_assert (0); /* Shouldn't reach here */
645 LOG (GNUNET_ERROR_TYPE_WARNING,
646 "Host registration failed with message: %s\n",
648 lcf->state = FINISHED;
649 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
655 * The Link Controller forwarding task
657 * @param cls the LCFContext
660 lcf_proc_task (void *cls);
664 * Task to free resources when forwarded link controllers has been timedout
666 * @param cls the LCFContext
669 lcf_forwarded_operation_timeout (void *cls)
671 struct LCFContext *lcf = cls;
673 lcf->timeout_task = NULL;
674 // GST_forwarded_operation_timeout (lcf->fopc, tc);
675 LOG (GNUNET_ERROR_TYPE_WARNING,
676 "A forwarded controller link operation has timed out\n");
677 send_controller_link_response (lcf->client,
680 "A forwarded controller link operation has timed out\n");
681 GNUNET_assert (NULL == lcf_proc_task_id);
682 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
688 * The Link Controller forwarding task
690 * @param cls the LCFContext
693 lcf_proc_task (void *cls)
695 struct LCFContext *lcf = cls;
697 lcf_proc_task_id = NULL;
702 GNUNET_TESTBED_is_host_registered_ (GST_host_list
703 [lcf->delegated_host_id],
704 lcf->gateway->controller))
706 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
707 GST_host_list[lcf->delegated_host_id]);
711 lcf->state = DELEGATED_HOST_REGISTERED;
712 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
715 case DELEGATED_HOST_REGISTERED:
717 GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
718 lcf->gateway->controller))
720 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
721 GST_host_list[lcf->slave_host_id]);
725 lcf->state = SLAVE_HOST_REGISTERED;
726 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
729 case SLAVE_HOST_REGISTERED:
730 lcf->op = GNUNET_TESTBED_controller_link (lcf,
731 lcf->gateway->controller,
732 GST_host_list[lcf->delegated_host_id],
733 GST_host_list[lcf->slave_host_id],
734 lcf->is_subordinate);
736 GNUNET_SCHEDULER_add_delayed (GST_timeout,
737 &lcf_forwarded_operation_timeout,
739 lcf->state = FINISHED;
743 GNUNET_TESTBED_operation_done (lcf->op);
744 GNUNET_CONTAINER_DLL_remove (lcf_head,
748 if (NULL != lcf_head)
749 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
756 * Callback for event from slave controllers
759 * @param event information about the event
762 slave_event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
764 struct LCFContext *lcf;
766 /* We currently only get here when working on LCFContexts */
767 GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
769 GNUNET_assert (lcf->op == event->op);
770 GNUNET_TESTBED_operation_done (lcf->op);
772 GNUNET_assert (FINISHED == lcf->state);
773 GNUNET_assert (NULL != lcf->timeout_task);
774 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
775 if (NULL == event->details.operation_finished.emsg)
776 send_controller_link_response (lcf->client, lcf->operation_id,
777 GNUNET_TESTBED_host_get_cfg_
778 (GST_host_list[lcf->delegated_host_id]),
781 send_controller_link_response (lcf->client, lcf->operation_id,
783 event->details.operation_finished.emsg);
784 GNUNET_assert (NULL == lcf_proc_task_id);
785 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
791 * Callback to signal successfull startup of the controller process
793 * @param cls the handle to the slave whose status is to be found here
794 * @param cfg the configuration with which the controller has been started;
795 * NULL if status is not #GNUNET_OK
796 * @param status #GNUNET_OK if the startup is successfull; #GNUNET_SYSERR if not,
797 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
800 slave_status_cb (void *cls,
801 const struct GNUNET_CONFIGURATION_Handle *cfg,
804 struct Slave *slave = cls;
805 struct LinkControllersContext *lcc;
808 if (GNUNET_SYSERR == status)
810 slave->controller_proc = NULL;
811 /* Stop all link controller forwarding tasks since we shutdown here anyway
812 and as these tasks they depend on the operation queues which are created
813 through GNUNET_TESTBED_controller_connect() and in kill_slave() we call
814 the destructor function GNUNET_TESTBED_controller_disconnect() */
817 destroy_slave (slave);
819 LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
820 GNUNET_SCHEDULER_shutdown (); /* We too shutdown */
824 GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
825 EVENT_MASK, &slave_event_cb,
827 if (NULL != slave->controller)
829 send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
833 send_controller_link_response (lcc->client, lcc->operation_id, NULL,
834 "Could not connect to delegated controller");
836 destroy_slave (slave);
843 if (NULL != lcc->client)
845 GNUNET_SERVICE_client_continue (lcc->client);
856 * Trigger notification task if there are notification requests currently
857 * waiting in the given neighbour. Also activates the neighbour connect operation
858 * if it was previously inactivated so that the connection to the neighbour can
861 * @param n the neighbour
864 trigger_notifications (struct Neighbour *n);
868 * Task to call the notification queued in the notifications list of the given
871 * @param cls the neighbour
874 neighbour_connect_notify_task (void *cls)
876 struct Neighbour *n = cls;
877 struct NeighbourConnectNotification *h;
879 GNUNET_assert (NULL != (h = n->nl_head));
880 GNUNET_assert (NULL != n->notify_task);
881 n->notify_task = NULL;
882 GNUNET_assert (NULL != n->controller);
883 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
884 trigger_notifications (n);
885 h->cb (h->cb_cls, n->controller);
891 * Trigger notification task if there are notification requests currently
892 * waiting in the given neighbour. Also activates the neighbour connect operation
893 * if it was previously inactivated so that the connection to the neighbour can
896 * @param n the neighbour
899 trigger_notifications (struct Neighbour *n)
901 GNUNET_assert (NULL != n->conn_op);
902 if (NULL == n->nl_head)
904 if (NULL == n->controller)
906 if (NULL != n->notify_task)
908 if (1 == n->inactive)
910 GNUNET_assert (0 == n->reference_cnt);
911 GNUNET_TESTBED_operation_activate_ (n->conn_op);
916 GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n);
921 * Callback to be called when the neighbour connect operation is started. The
922 * connection to the neigbour is opened here and any pending notifications are
925 * @param cls the neighbour
928 opstart_neighbour_conn (void *cls)
930 struct Neighbour *n = cls;
932 GNUNET_assert (NULL != n->conn_op);
933 GNUNET_assert (NULL == n->controller);
934 LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
935 n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
939 trigger_notifications (n);
944 * Callback to be called when the neighbour connect operation is released
946 * @param cls the neighbour
949 oprelease_neighbour_conn (void *cls)
951 struct Neighbour *n = cls;
953 GNUNET_assert (0 == n->reference_cnt);
954 GNUNET_assert (NULL == n->notify_task);
955 GNUNET_assert (NULL == n->nl_head);
956 if (NULL != n->controller)
958 LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
959 GNUNET_TESTBED_controller_disconnect (n->controller);
960 n->controller = NULL;
968 * Try to open a connection to the given neigbour. If the connection is open
969 * already, then it is re-used. If not, the request is queued in the operation
970 * queues responsible for bounding the total number of file descriptors. The
971 * actual connection will happen when the operation queue marks the
972 * corresponding operation as active.
974 * @param n the neighbour to open a connection to
975 * @param cb the notification callback to call when the connection is opened
976 * @param cb_cls the closure for the above callback
978 struct NeighbourConnectNotification *
979 GST_neighbour_get_connection (struct Neighbour *n,
980 GST_NeigbourConnectNotifyCallback cb,
983 struct NeighbourConnectNotification *h;
985 GNUNET_assert (NULL != cb);
986 LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
988 h = GNUNET_new (struct NeighbourConnectNotification);
992 GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
993 if (NULL == n->conn_op)
995 GNUNET_assert (NULL == n->controller);
996 n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
997 &oprelease_neighbour_conn);
998 GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
999 GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
1002 trigger_notifications (n);
1008 * Cancel the request for opening a connection to the neighbour
1010 * @param h the notification handle
1013 GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
1015 struct Neighbour *n;
1019 cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
1020 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
1022 if (GNUNET_NO == cleanup_task)
1024 if (NULL == n->notify_task)
1026 GNUNET_assert (0 < n->reference_cnt);
1028 GNUNET_SCHEDULER_cancel (n->notify_task);
1029 n->notify_task = NULL;
1030 if (NULL == n->nl_head)
1032 if ( (0 == n->reference_cnt) && (0 == n->inactive) )
1035 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1039 trigger_notifications (n);
1044 * Release the connection to the neighbour. The actual connection will be
1045 * closed if connections to other neighbour are waiting (to maintain a bound on
1046 * the total number of connections that are open).
1048 * @param n the neighbour whose connection can be closed
1051 GST_neighbour_release_connection (struct Neighbour *n)
1053 GNUNET_assert (0 == n->inactive);
1054 GNUNET_assert (0 < n->reference_cnt);
1056 if (0 == n->reference_cnt)
1059 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1065 * Cleanup neighbour connect contexts
1067 * @param ncc the neighbour connect context to cleanup
1070 cleanup_ncc (struct NeighbourConnectCtxt *ncc)
1072 if (NULL != ncc->nh)
1073 GST_neighbour_get_connection_cancel (ncc->nh);
1074 if (NULL != ncc->timeout_task)
1075 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1076 GNUNET_CONTAINER_DLL_remove (ncc_head,
1084 * Cleans up the neighbour list
1087 GST_neighbour_list_clean ()
1089 struct Neighbour *n;
1092 for (id = 0; id < neighbour_list_size; id++)
1094 if (NULL == (n = neighbour_list[id]))
1096 if (NULL != n->conn_op)
1097 GNUNET_TESTBED_operation_release_ (n->conn_op);
1099 neighbour_list[id] = NULL;
1101 GNUNET_free_non_null (neighbour_list);
1106 * Get a neighbour from the neighbour list
1108 * @param id the index of the neighbour in the neighbour list
1109 * @return the Neighbour; NULL if the given index in invalid (index greater than
1110 * the list size or neighbour at that index is NULL)
1113 GST_get_neighbour (uint32_t id)
1115 if (neighbour_list_size <= id)
1117 return neighbour_list[id];
1122 * Function to cleanup the neighbour connect contexts
1127 while (NULL != ncc_head)
1128 cleanup_ncc (ncc_head);
1133 * Task to be run upon timeout while attempting to connect to the neighbour
1135 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1138 timeout_neighbour_connect (void *cls)
1140 struct NeighbourConnectCtxt *ncc = cls;
1142 ncc->timeout_task = NULL;
1143 send_controller_link_response (ncc->client,
1146 "Could not connect to delegated controller");
1152 * Callback called when a connection to the neighbour is made
1154 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1155 * @param c the handle the neighbour's controller
1158 neighbour_connect_cb (void *cls,
1159 struct GNUNET_TESTBED_Controller *c)
1161 struct NeighbourConnectCtxt *ncc = cls;
1163 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1164 ncc->timeout_task = NULL;
1166 GST_neighbour_release_connection (ncc->n);
1167 send_controller_link_response (ncc->client,
1176 * Function to create a neigbour and add it into the neighbour list
1178 * @param host the host of the neighbour
1181 GST_create_neighbour (struct GNUNET_TESTBED_Host *host)
1183 struct Neighbour *n;
1185 n = GNUNET_new (struct Neighbour);
1186 n->host_id = GNUNET_TESTBED_host_get_id_ (host);
1187 neighbour_list_add (n); /* just add; connect on-demand */
1193 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1195 * @param cls identification of the client
1196 * @param msg the actual message
1199 handle_link_controllers (void *cls,
1200 const struct GNUNET_TESTBED_ControllerLinkRequest *msg)
1202 struct GNUNET_SERVICE_Client *client = cls;
1203 struct LCFContext *lcf;
1204 struct Route *route;
1205 struct Route *new_route;
1207 uint32_t delegated_host_id;
1208 uint32_t slave_host_id;
1210 if (NULL == GST_context)
1213 GNUNET_SERVICE_client_drop (client);
1216 delegated_host_id = ntohl (msg->delegated_host_id);
1217 if (delegated_host_id == GST_context->host_id)
1220 LOG (GNUNET_ERROR_TYPE_WARNING,
1221 "Trying to link ourselves\n");
1222 GNUNET_SERVICE_client_drop (client);
1225 if ((delegated_host_id >= GST_host_list_size) ||
1226 (NULL == GST_host_list[delegated_host_id]))
1228 LOG (GNUNET_ERROR_TYPE_WARNING,
1229 "Delegated host %u not registered with us\n",
1231 GNUNET_SERVICE_client_drop (client);
1234 slave_host_id = ntohl (msg->slave_host_id);
1235 if ((slave_host_id >= GST_host_list_size) ||
1236 (NULL == GST_host_list[slave_host_id]))
1238 LOG (GNUNET_ERROR_TYPE_WARNING,
1239 "Slave host %u not registered with us\n",
1241 GNUNET_SERVICE_client_drop (client);
1244 if (slave_host_id == delegated_host_id)
1246 LOG (GNUNET_ERROR_TYPE_WARNING,
1247 "Slave and delegated host are same\n");
1248 GNUNET_SERVICE_client_drop (client);
1251 op_id = GNUNET_ntohll (msg->operation_id);
1252 if (slave_host_id == GST_context->host_id) /* Link from us */
1254 struct Slave *slave;
1255 struct LinkControllersContext *lcc;
1257 if (1 != msg->is_subordinate)
1259 struct Neighbour *n;
1260 struct NeighbourConnectCtxt *ncc;
1262 if ((delegated_host_id < neighbour_list_size) &&
1263 (NULL != neighbour_list[delegated_host_id]))
1266 GNUNET_SERVICE_client_drop (client);
1269 LOG_DEBUG ("Received request to establish a link to host %u\n",
1271 n = GST_create_neighbour (GST_host_list[delegated_host_id]);
1272 ncc = GNUNET_new (struct NeighbourConnectCtxt);
1275 ncc->client = client;
1276 ncc->nh = GST_neighbour_get_connection (n,
1277 &neighbour_connect_cb,
1280 = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1281 &timeout_neighbour_connect,
1283 GNUNET_CONTAINER_DLL_insert_tail (ncc_head,
1286 GNUNET_SERVICE_client_continue (client);
1289 if ( (delegated_host_id < GST_slave_list_size) &&
1290 (NULL != GST_slave_list[delegated_host_id]) )
1293 GNUNET_SERVICE_client_drop (client);
1296 LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1298 slave = GNUNET_new (struct Slave);
1299 slave->host_id = delegated_host_id;
1300 slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100,
1302 slave_list_add (slave);
1303 lcc = GNUNET_new (struct LinkControllersContext);
1304 lcc->operation_id = op_id;
1305 lcc->client = client;
1307 slave->controller_proc
1308 = GNUNET_TESTBED_controller_start (GST_context->master_ip,
1309 GST_host_list[slave->host_id],
1312 new_route = GNUNET_new (struct Route);
1313 new_route->dest = delegated_host_id;
1314 new_route->thru = GST_context->host_id;
1315 route_list_add (new_route);
1319 /* Route the request */
1320 if (slave_host_id >= route_list_size)
1322 LOG (GNUNET_ERROR_TYPE_WARNING,
1323 "No route towards slave host");
1324 GNUNET_SERVICE_client_drop (client);
1327 lcf = GNUNET_new (struct LCFContext);
1328 lcf->delegated_host_id = delegated_host_id;
1329 lcf->slave_host_id = slave_host_id;
1330 route = GST_find_dest_route (slave_host_id);
1331 GNUNET_assert (NULL != route); /* because we add routes carefully */
1332 GNUNET_assert (route->dest < GST_slave_list_size);
1333 GNUNET_assert (NULL != GST_slave_list[route->dest]);
1334 lcf->is_subordinate = msg->is_subordinate;
1336 lcf->operation_id = op_id;
1337 lcf->gateway = GST_slave_list[route->dest];
1338 lcf->client = client;
1339 if (NULL == lcf_head)
1341 GNUNET_assert (NULL == lcf_proc_task_id);
1342 GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1345 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
1350 GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1354 /* FIXME: Adding a new route should happen after the controllers are linked
1356 if (1 != msg->is_subordinate)
1358 GNUNET_SERVICE_client_continue (client);
1361 if ( (delegated_host_id < route_list_size) &&
1362 (NULL != route_list[delegated_host_id]) )
1364 GNUNET_break_op (0); /* Are you trying to link delegated host twice
1365 * with is subordinate flag set to GNUNET_YES? */
1366 GNUNET_SERVICE_client_drop (client);
1369 new_route = GNUNET_new (struct Route);
1370 new_route->dest = delegated_host_id;
1371 new_route->thru = route->dest;
1372 route_list_add (new_route);
1373 GNUNET_SERVICE_client_continue (client);
1378 * Clean up @a client handle if we stored any via #handle_link_controllers(),
1379 * the given client disconnected.
1381 * @param client the client that is history
1384 GST_link_notify_disconnect (struct GNUNET_SERVICE_Client *client)
1386 struct NeighbourConnectCtxt *ncc;
1387 struct NeighbourConnectCtxt *nccn;
1388 struct LCFContext *lcf;
1389 struct LCFContext *lcfn;
1391 for (ncc = ncc_head; NULL != ncc; ncc = nccn)
1394 if (ncc->client == client)
1397 for (unsigned int i=0;i<GST_slave_list_size;i++)
1399 struct Slave *slave = GST_slave_list[i];
1400 struct LinkControllersContext *lcc;
1404 GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map,
1405 &drop_client_entries,
1410 if (lcc->client == client)
1416 for (lcf = lcf_head; NULL != lcf; lcf = lcfn)
1419 if ( (NULL != lcf) &&
1420 (client == lcf->client) )
1422 if (NULL != lcf->op)
1423 GNUNET_TESTBED_operation_done (lcf->op);
1424 GNUNET_CONTAINER_DLL_remove (lcf_head,
1434 * Cleans up the queue used for forwarding link controllers requests
1439 struct LCFContext *lcf;
1441 if (NULL != lcf_head)
1443 if (NULL != lcf_proc_task_id)
1445 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1446 lcf_proc_task_id = NULL;
1449 GNUNET_assert (NULL == lcf_proc_task_id);
1450 for (lcf = lcf_head; NULL != lcf; lcf = lcf_head)
1452 if (NULL != lcf->op)
1453 GNUNET_TESTBED_operation_done (lcf->op);
1454 if (NULL != lcf->timeout_task)
1455 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
1456 GNUNET_CONTAINER_DLL_remove (lcf_head,