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;
135 * Notification context to be used to notify when connection to the neighbour's
136 * controller is opened
138 struct NeighbourConnectNotification
141 * DLL next for inclusion in neighbour's list of notification requests
143 struct NeighbourConnectNotification *next;
148 struct NeighbourConnectNotification *prev;
156 * The notification callback to call when we are connect to neighbour
158 GST_NeigbourConnectNotifyCallback cb;
161 * The closure for the above callback
168 * A connected controller which is not our child
173 * The controller handle
175 struct GNUNET_TESTBED_Controller *controller;
178 * Operation handle for opening a lateral connection to another controller.
179 * Will be NULL if the slave controller is started by this controller
181 struct GNUNET_TESTBED_Operation *conn_op;
184 * DLL head for the list of notification requests
186 struct NeighbourConnectNotification *nl_head;
189 * DLL tail for the list of notification requests
191 struct NeighbourConnectNotification *nl_tail;
194 * Task id for the task to call notifications from the notification list
196 struct GNUNET_SCHEDULER_Task *notify_task;
199 * How many references are present currently to this neighbour's connection
201 unsigned int reference_cnt;
204 * Is the conn_op inactivated?
206 unsigned int inactive;
209 * The id of the host this controller is running on
218 static struct Neighbour **neighbour_list;
221 * The size of the neighbour list
223 static unsigned int neighbour_list_size;
227 * Context information for establishing a link to neighbour (Used is
228 * GST_handle_link_controllers()
230 struct NeighbourConnectCtxt
233 * DLL next for inclusion in the corresponding context list
235 struct NeighbourConnectCtxt *next;
240 struct NeighbourConnectCtxt *prev;
243 * The neighbour to whom connection should be made
248 * The client requesting the connection
250 struct GNUNET_SERVICE_Client *client;
253 * Task to be run upon timeout
255 struct GNUNET_SCHEDULER_Task *timeout_task;
258 * The notification handle associated with the neighbour's connection request
260 struct NeighbourConnectNotification *nh;
263 * The id of the link-controllers operation responsible for creating this
270 * DLL head for the list of neighbour connect contexts
272 struct NeighbourConnectCtxt *ncc_head;
275 * DLL tail for the list of neighbour connect contexts
277 struct NeighbourConnectCtxt *ncc_tail;
280 * A list of directly linked neighbours
282 struct Slave **GST_slave_list;
285 * The size of directly linked neighbours list
287 unsigned int GST_slave_list_size;
292 static struct Route **route_list;
297 static struct LCFContext *lcf_head;
300 * The tail for the LCF queue
302 static struct LCFContext *lcf_tail;
305 * The lcf_task handle
307 static struct GNUNET_SCHEDULER_Task *lcf_proc_task_id;
310 * The size of the route list
312 static unsigned int route_list_size;
316 * Adds a slave to the slave array
318 * @param slave the slave controller to add
321 slave_list_add (struct Slave *slave)
323 if (slave->host_id >= GST_slave_list_size)
324 GST_array_grow_large_enough (GST_slave_list,
327 GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
328 GST_slave_list[slave->host_id] = slave;
333 * Clean up all forwarded operation overlay context matching the
334 * client given in @a cls.
336 * @param cls a `struct GNUNET_SERVICE_Client *` to match
338 * @param value the `struct RegisteredHostContext` to search for @a cls
339 * @return #GNUNET_OK (continue iterating)
342 drop_client_entries (void *cls,
343 const struct GNUNET_HashCode *key,
346 struct GNUNET_SERVICE_Client *client = cls;
347 struct RegisteredHostContext *rhc = value;
348 struct ForwardedOverlayConnectContext *focc;
349 struct ForwardedOverlayConnectContext *foccn;
351 for (focc = rhc->focc_dll_head; NULL != focc; focc = foccn)
354 if (focc->client == client)
355 GST_cleanup_focc (focc);
362 * Adds a route to the route list
364 * @param route the route to add
367 route_list_add (struct Route *route)
369 if (route->dest >= route_list_size)
370 GST_array_grow_large_enough (route_list, route_list_size, route->dest);
371 GNUNET_assert (NULL == route_list[route->dest]);
372 route_list[route->dest] = route;
377 * Add a neighbour to the neighbour list. Grows the neighbour list
380 * @param n the neighbour to add
383 neighbour_list_add (struct Neighbour *n)
385 if (n->host_id >= neighbour_list_size)
386 GST_array_grow_large_enough (neighbour_list, neighbour_list_size,
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);
634 case DELEGATED_HOST_REGISTERED:
636 goto registration_error;
637 lcf->state = SLAVE_HOST_REGISTERED;
638 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
642 GNUNET_assert (0); /* Shouldn't reach here */
647 LOG (GNUNET_ERROR_TYPE_WARNING,
648 "Host registration failed with message: %s\n",
650 lcf->state = FINISHED;
651 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
657 * The Link Controller forwarding task
659 * @param cls the LCFContext
662 lcf_proc_task (void *cls);
666 * Task to free resources when forwarded link controllers has been timedout
668 * @param cls the LCFContext
671 lcf_forwarded_operation_timeout (void *cls)
673 struct LCFContext *lcf = cls;
675 lcf->timeout_task = NULL;
676 // GST_forwarded_operation_timeout (lcf->fopc, tc);
677 LOG (GNUNET_ERROR_TYPE_WARNING,
678 "A forwarded controller link operation has timed out\n");
679 send_controller_link_response (lcf->client,
682 "A forwarded controller link operation has timed out\n");
683 GNUNET_assert (NULL == lcf_proc_task_id);
684 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
690 * The Link Controller forwarding task
692 * @param cls the LCFContext
695 lcf_proc_task (void *cls)
697 struct LCFContext *lcf = cls;
699 lcf_proc_task_id = NULL;
704 GNUNET_TESTBED_is_host_registered_ (GST_host_list
705 [lcf->delegated_host_id],
706 lcf->gateway->controller))
708 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
709 GST_host_list[lcf->delegated_host_id]);
713 lcf->state = DELEGATED_HOST_REGISTERED;
714 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
718 case DELEGATED_HOST_REGISTERED:
720 GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
721 lcf->gateway->controller))
723 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
724 GST_host_list[lcf->slave_host_id]);
728 lcf->state = SLAVE_HOST_REGISTERED;
729 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
733 case SLAVE_HOST_REGISTERED:
734 lcf->op = GNUNET_TESTBED_controller_link (lcf,
735 lcf->gateway->controller,
738 GST_host_list[lcf->slave_host_id],
739 lcf->is_subordinate);
741 GNUNET_SCHEDULER_add_delayed (GST_timeout,
742 &lcf_forwarded_operation_timeout,
744 lcf->state = FINISHED;
749 GNUNET_TESTBED_operation_done (lcf->op);
750 GNUNET_CONTAINER_DLL_remove (lcf_head,
754 if (NULL != lcf_head)
755 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
762 * Callback for event from slave controllers
765 * @param event information about the event
768 slave_event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
770 struct LCFContext *lcf;
772 /* We currently only get here when working on LCFContexts */
773 GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
775 GNUNET_assert (lcf->op == event->op);
776 GNUNET_TESTBED_operation_done (lcf->op);
778 GNUNET_assert (FINISHED == lcf->state);
779 GNUNET_assert (NULL != lcf->timeout_task);
780 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
781 if (NULL == event->details.operation_finished.emsg)
782 send_controller_link_response (lcf->client, lcf->operation_id,
783 GNUNET_TESTBED_host_get_cfg_
784 (GST_host_list[lcf->delegated_host_id]),
787 send_controller_link_response (lcf->client, lcf->operation_id,
789 event->details.operation_finished.emsg);
790 GNUNET_assert (NULL == lcf_proc_task_id);
791 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
797 * Callback to signal successfull startup of the controller process
799 * @param cls the handle to the slave whose status is to be found here
800 * @param cfg the configuration with which the controller has been started;
801 * NULL if status is not #GNUNET_OK
802 * @param status #GNUNET_OK if the startup is successfull; #GNUNET_SYSERR if not,
803 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
806 slave_status_cb (void *cls,
807 const struct GNUNET_CONFIGURATION_Handle *cfg,
810 struct Slave *slave = cls;
811 struct LinkControllersContext *lcc;
814 if (GNUNET_SYSERR == status)
816 slave->controller_proc = NULL;
817 /* Stop all link controller forwarding tasks since we shutdown here anyway
818 and as these tasks they depend on the operation queues which are created
819 through GNUNET_TESTBED_controller_connect() and in kill_slave() we call
820 the destructor function GNUNET_TESTBED_controller_disconnect() */
823 destroy_slave (slave);
825 LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
826 GNUNET_SCHEDULER_shutdown (); /* We too shutdown */
830 GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
831 EVENT_MASK, &slave_event_cb,
833 if (NULL != slave->controller)
835 send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
839 send_controller_link_response (lcc->client, lcc->operation_id, NULL,
840 "Could not connect to delegated controller");
842 destroy_slave (slave);
849 if (NULL != lcc->client)
851 GNUNET_SERVICE_client_continue (lcc->client);
862 * Trigger notification task if there are notification requests currently
863 * waiting in the given neighbour. Also activates the neighbour connect operation
864 * if it was previously inactivated so that the connection to the neighbour can
867 * @param n the neighbour
870 trigger_notifications (struct Neighbour *n);
874 * Task to call the notification queued in the notifications list of the given
877 * @param cls the neighbour
880 neighbour_connect_notify_task (void *cls)
882 struct Neighbour *n = cls;
883 struct NeighbourConnectNotification *h;
885 GNUNET_assert (NULL != (h = n->nl_head));
886 GNUNET_assert (NULL != n->notify_task);
887 n->notify_task = NULL;
888 GNUNET_assert (NULL != n->controller);
889 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
890 trigger_notifications (n);
891 h->cb (h->cb_cls, n->controller);
897 * Trigger notification task if there are notification requests currently
898 * waiting in the given neighbour. Also activates the neighbour connect operation
899 * if it was previously inactivated so that the connection to the neighbour can
902 * @param n the neighbour
905 trigger_notifications (struct Neighbour *n)
907 GNUNET_assert (NULL != n->conn_op);
908 if (NULL == n->nl_head)
910 if (NULL == n->controller)
912 if (NULL != n->notify_task)
914 if (1 == n->inactive)
916 GNUNET_assert (0 == n->reference_cnt);
917 GNUNET_TESTBED_operation_activate_ (n->conn_op);
922 GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n);
927 * Callback to be called when the neighbour connect operation is started. The
928 * connection to the neigbour is opened here and any pending notifications are
931 * @param cls the neighbour
934 opstart_neighbour_conn (void *cls)
936 struct Neighbour *n = cls;
938 GNUNET_assert (NULL != n->conn_op);
939 GNUNET_assert (NULL == n->controller);
940 LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
941 n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
945 trigger_notifications (n);
950 * Callback to be called when the neighbour connect operation is released
952 * @param cls the neighbour
955 oprelease_neighbour_conn (void *cls)
957 struct Neighbour *n = cls;
959 GNUNET_assert (0 == n->reference_cnt);
960 GNUNET_assert (NULL == n->notify_task);
961 GNUNET_assert (NULL == n->nl_head);
962 if (NULL != n->controller)
964 LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
965 GNUNET_TESTBED_controller_disconnect (n->controller);
966 n->controller = NULL;
974 * Try to open a connection to the given neigbour. If the connection is open
975 * already, then it is re-used. If not, the request is queued in the operation
976 * queues responsible for bounding the total number of file descriptors. The
977 * actual connection will happen when the operation queue marks the
978 * corresponding operation as active.
980 * @param n the neighbour to open a connection to
981 * @param cb the notification callback to call when the connection is opened
982 * @param cb_cls the closure for the above callback
984 struct NeighbourConnectNotification *
985 GST_neighbour_get_connection (struct Neighbour *n,
986 GST_NeigbourConnectNotifyCallback cb,
989 struct NeighbourConnectNotification *h;
991 GNUNET_assert (NULL != cb);
992 LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
994 h = GNUNET_new (struct NeighbourConnectNotification);
998 GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
999 if (NULL == n->conn_op)
1001 GNUNET_assert (NULL == n->controller);
1002 n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
1003 &oprelease_neighbour_conn);
1004 GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
1005 GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
1008 trigger_notifications (n);
1014 * Cancel the request for opening a connection to the neighbour
1016 * @param h the notification handle
1019 GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
1021 struct Neighbour *n;
1025 cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
1026 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
1028 if (GNUNET_NO == cleanup_task)
1030 if (NULL == n->notify_task)
1032 GNUNET_assert (0 < n->reference_cnt);
1034 GNUNET_SCHEDULER_cancel (n->notify_task);
1035 n->notify_task = NULL;
1036 if (NULL == n->nl_head)
1038 if ((0 == n->reference_cnt) && (0 == n->inactive))
1041 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1045 trigger_notifications (n);
1050 * Release the connection to the neighbour. The actual connection will be
1051 * closed if connections to other neighbour are waiting (to maintain a bound on
1052 * the total number of connections that are open).
1054 * @param n the neighbour whose connection can be closed
1057 GST_neighbour_release_connection (struct Neighbour *n)
1059 GNUNET_assert (0 == n->inactive);
1060 GNUNET_assert (0 < n->reference_cnt);
1062 if (0 == n->reference_cnt)
1065 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1071 * Cleanup neighbour connect contexts
1073 * @param ncc the neighbour connect context to cleanup
1076 cleanup_ncc (struct NeighbourConnectCtxt *ncc)
1078 if (NULL != ncc->nh)
1079 GST_neighbour_get_connection_cancel (ncc->nh);
1080 if (NULL != ncc->timeout_task)
1081 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1082 GNUNET_CONTAINER_DLL_remove (ncc_head,
1090 * Cleans up the neighbour list
1093 GST_neighbour_list_clean ()
1095 struct Neighbour *n;
1098 for (id = 0; id < neighbour_list_size; id++)
1100 if (NULL == (n = neighbour_list[id]))
1102 if (NULL != n->conn_op)
1103 GNUNET_TESTBED_operation_release_ (n->conn_op);
1105 neighbour_list[id] = NULL;
1107 GNUNET_free_non_null (neighbour_list);
1112 * Get a neighbour from the neighbour list
1114 * @param id the index of the neighbour in the neighbour list
1115 * @return the Neighbour; NULL if the given index in invalid (index greater than
1116 * the list size or neighbour at that index is NULL)
1119 GST_get_neighbour (uint32_t id)
1121 if (neighbour_list_size <= id)
1123 return neighbour_list[id];
1128 * Function to cleanup the neighbour connect contexts
1133 while (NULL != ncc_head)
1134 cleanup_ncc (ncc_head);
1139 * Task to be run upon timeout while attempting to connect to the neighbour
1141 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1144 timeout_neighbour_connect (void *cls)
1146 struct NeighbourConnectCtxt *ncc = cls;
1148 ncc->timeout_task = NULL;
1149 send_controller_link_response (ncc->client,
1152 "Could not connect to delegated controller");
1158 * Callback called when a connection to the neighbour is made
1160 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1161 * @param c the handle the neighbour's controller
1164 neighbour_connect_cb (void *cls,
1165 struct GNUNET_TESTBED_Controller *c)
1167 struct NeighbourConnectCtxt *ncc = cls;
1169 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1170 ncc->timeout_task = NULL;
1172 GST_neighbour_release_connection (ncc->n);
1173 send_controller_link_response (ncc->client,
1182 * Function to create a neigbour and add it into the neighbour list
1184 * @param host the host of the neighbour
1187 GST_create_neighbour (struct GNUNET_TESTBED_Host *host)
1189 struct Neighbour *n;
1191 n = GNUNET_new (struct Neighbour);
1192 n->host_id = GNUNET_TESTBED_host_get_id_ (host);
1193 neighbour_list_add (n); /* just add; connect on-demand */
1199 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1201 * @param cls identification of the client
1202 * @param msg the actual message
1205 handle_link_controllers (void *cls,
1206 const struct GNUNET_TESTBED_ControllerLinkRequest *msg)
1208 struct GNUNET_SERVICE_Client *client = cls;
1209 struct LCFContext *lcf;
1210 struct Route *route;
1211 struct Route *new_route;
1213 uint32_t delegated_host_id;
1214 uint32_t slave_host_id;
1216 if (NULL == GST_context)
1219 GNUNET_SERVICE_client_drop (client);
1222 delegated_host_id = ntohl (msg->delegated_host_id);
1223 if (delegated_host_id == GST_context->host_id)
1226 LOG (GNUNET_ERROR_TYPE_WARNING,
1227 "Trying to link ourselves\n");
1228 GNUNET_SERVICE_client_drop (client);
1231 if ((delegated_host_id >= GST_host_list_size) ||
1232 (NULL == GST_host_list[delegated_host_id]))
1234 LOG (GNUNET_ERROR_TYPE_WARNING,
1235 "Delegated host %u not registered with us\n",
1237 GNUNET_SERVICE_client_drop (client);
1240 slave_host_id = ntohl (msg->slave_host_id);
1241 if ((slave_host_id >= GST_host_list_size) ||
1242 (NULL == GST_host_list[slave_host_id]))
1244 LOG (GNUNET_ERROR_TYPE_WARNING,
1245 "Slave host %u not registered with us\n",
1247 GNUNET_SERVICE_client_drop (client);
1250 if (slave_host_id == delegated_host_id)
1252 LOG (GNUNET_ERROR_TYPE_WARNING,
1253 "Slave and delegated host are same\n");
1254 GNUNET_SERVICE_client_drop (client);
1257 op_id = GNUNET_ntohll (msg->operation_id);
1258 if (slave_host_id == GST_context->host_id) /* Link from us */
1260 struct Slave *slave;
1261 struct LinkControllersContext *lcc;
1263 if (1 != msg->is_subordinate)
1265 struct Neighbour *n;
1266 struct NeighbourConnectCtxt *ncc;
1268 if ((delegated_host_id < neighbour_list_size) &&
1269 (NULL != neighbour_list[delegated_host_id]))
1272 GNUNET_SERVICE_client_drop (client);
1275 LOG_DEBUG ("Received request to establish a link to host %u\n",
1277 n = GST_create_neighbour (GST_host_list[delegated_host_id]);
1278 ncc = GNUNET_new (struct NeighbourConnectCtxt);
1281 ncc->client = client;
1282 ncc->nh = GST_neighbour_get_connection (n,
1283 &neighbour_connect_cb,
1286 = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1287 &timeout_neighbour_connect,
1289 GNUNET_CONTAINER_DLL_insert_tail (ncc_head,
1292 GNUNET_SERVICE_client_continue (client);
1295 if ((delegated_host_id < GST_slave_list_size) &&
1296 (NULL != GST_slave_list[delegated_host_id]))
1299 GNUNET_SERVICE_client_drop (client);
1302 LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1304 slave = GNUNET_new (struct Slave);
1305 slave->host_id = delegated_host_id;
1306 slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100,
1308 slave_list_add (slave);
1309 lcc = GNUNET_new (struct LinkControllersContext);
1310 lcc->operation_id = op_id;
1311 lcc->client = client;
1313 slave->controller_proc
1314 = GNUNET_TESTBED_controller_start (GST_context->master_ip,
1315 GST_host_list[slave->host_id],
1318 new_route = GNUNET_new (struct Route);
1319 new_route->dest = delegated_host_id;
1320 new_route->thru = GST_context->host_id;
1321 route_list_add (new_route);
1325 /* Route the request */
1326 if (slave_host_id >= route_list_size)
1328 LOG (GNUNET_ERROR_TYPE_WARNING,
1329 "No route towards slave host");
1330 GNUNET_SERVICE_client_drop (client);
1333 lcf = GNUNET_new (struct LCFContext);
1334 lcf->delegated_host_id = delegated_host_id;
1335 lcf->slave_host_id = slave_host_id;
1336 route = GST_find_dest_route (slave_host_id);
1337 GNUNET_assert (NULL != route); /* because we add routes carefully */
1338 GNUNET_assert (route->dest < GST_slave_list_size);
1339 GNUNET_assert (NULL != GST_slave_list[route->dest]);
1340 lcf->is_subordinate = msg->is_subordinate;
1342 lcf->operation_id = op_id;
1343 lcf->gateway = GST_slave_list[route->dest];
1344 lcf->client = client;
1345 if (NULL == lcf_head)
1347 GNUNET_assert (NULL == lcf_proc_task_id);
1348 GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1351 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
1356 GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1360 /* FIXME: Adding a new route should happen after the controllers are linked
1362 if (1 != msg->is_subordinate)
1364 GNUNET_SERVICE_client_continue (client);
1367 if ((delegated_host_id < route_list_size) &&
1368 (NULL != route_list[delegated_host_id]))
1370 GNUNET_break_op (0); /* Are you trying to link delegated host twice
1371 * with is subordinate flag set to GNUNET_YES? */
1372 GNUNET_SERVICE_client_drop (client);
1375 new_route = GNUNET_new (struct Route);
1376 new_route->dest = delegated_host_id;
1377 new_route->thru = route->dest;
1378 route_list_add (new_route);
1379 GNUNET_SERVICE_client_continue (client);
1384 * Clean up @a client handle if we stored any via #handle_link_controllers(),
1385 * the given client disconnected.
1387 * @param client the client that is history
1390 GST_link_notify_disconnect (struct GNUNET_SERVICE_Client *client)
1392 struct NeighbourConnectCtxt *ncc;
1393 struct NeighbourConnectCtxt *nccn;
1394 struct LCFContext *lcf;
1395 struct LCFContext *lcfn;
1397 for (ncc = ncc_head; NULL != ncc; ncc = nccn)
1400 if (ncc->client == client)
1403 for (unsigned int i = 0; i < GST_slave_list_size; i++)
1405 struct Slave *slave = GST_slave_list[i];
1406 struct LinkControllersContext *lcc;
1410 GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map,
1411 &drop_client_entries,
1416 if (lcc->client == client)
1422 for (lcf = lcf_head; NULL != lcf; lcf = lcfn)
1425 if ((NULL != lcf) &&
1426 (client == lcf->client))
1428 if (NULL != lcf->op)
1429 GNUNET_TESTBED_operation_done (lcf->op);
1430 GNUNET_CONTAINER_DLL_remove (lcf_head,
1440 * Cleans up the queue used for forwarding link controllers requests
1445 struct LCFContext *lcf;
1447 if (NULL != lcf_head)
1449 if (NULL != lcf_proc_task_id)
1451 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1452 lcf_proc_task_id = NULL;
1455 GNUNET_assert (NULL == lcf_proc_task_id);
1456 for (lcf = lcf_head; NULL != lcf; lcf = lcf_head)
1458 if (NULL != lcf->op)
1459 GNUNET_TESTBED_operation_done (lcf->op);
1460 if (NULL != lcf->timeout_task)
1461 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
1462 GNUNET_CONTAINER_DLL_remove (lcf_head,