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/>.
20 * @file testbed/gnunet-service-testbed_links.c
21 * @brief TESTBED service components that deals with starting slave controllers
22 * and establishing lateral links between controllers
23 * @author Sree Harsha Totakura
26 #include "gnunet-service-testbed.h"
29 * Redefine LOG with a changed log component string
34 #define LOG(kind,...) \
35 GNUNET_log_from (kind, "testbed-links", __VA_ARGS__)
38 * The event mask for the events we listen from sub-controllers
40 #define EVENT_MASK (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED)
44 * States of LCFContext
49 * The Context has been initialized; Nothing has been done on it
54 * Delegated host has been registered at the forwarding controller
56 DELEGATED_HOST_REGISTERED,
59 * The slave host has been registred at the forwarding controller
61 SLAVE_HOST_REGISTERED,
64 * The context has been finished (may have error)
71 * Link controllers request forwarding context
78 struct LCFContext *next;
83 struct LCFContext *prev;
86 * The gateway which will pass the link message to delegated host
88 struct Slave *gateway;
91 * The client which has asked to perform this operation
93 struct GNUNET_SERVICE_Client *client;
96 * Handle for operations which are forwarded while linking controllers
98 struct GNUNET_TESTBED_Operation *op;
103 struct GNUNET_SCHEDULER_Task *timeout_task;
106 * The id of the operation which created this context
108 uint64_t operation_id;
111 * should the slave controller start the delegated controller?
116 * The state of this context
118 enum LCFContextState state;
123 uint32_t delegated_host_id;
128 uint32_t slave_host_id;
134 * Notification context to be used to notify when connection to the neighbour's
135 * controller is opened
137 struct NeighbourConnectNotification
140 * DLL next for inclusion in neighbour's list of notification requests
142 struct NeighbourConnectNotification *next;
147 struct NeighbourConnectNotification *prev;
155 * The notification callback to call when we are connect to neighbour
157 GST_NeigbourConnectNotifyCallback cb;
160 * The closure for the above callback
167 * A connected controller which is not our child
172 * The controller handle
174 struct GNUNET_TESTBED_Controller *controller;
177 * Operation handle for opening a lateral connection to another controller.
178 * Will be NULL if the slave controller is started by this controller
180 struct GNUNET_TESTBED_Operation *conn_op;
183 * DLL head for the list of notification requests
185 struct NeighbourConnectNotification *nl_head;
188 * DLL tail for the list of notification requests
190 struct NeighbourConnectNotification *nl_tail;
193 * Task id for the task to call notifications from the notification list
195 struct GNUNET_SCHEDULER_Task * notify_task;
198 * How many references are present currently to this neighbour's connection
200 unsigned int reference_cnt;
203 * Is the conn_op inactivated?
205 unsigned int inactive;
208 * The id of the host this controller is running on
217 static struct Neighbour **neighbour_list;
220 * The size of the neighbour list
222 static unsigned int neighbour_list_size;
226 * Context information for establishing a link to neighbour (Used is
227 * GST_handle_link_controllers()
229 struct NeighbourConnectCtxt
232 * DLL next for inclusion in the corresponding context list
234 struct NeighbourConnectCtxt *next;
239 struct NeighbourConnectCtxt *prev;
242 * The neighbour to whom connection should be made
247 * The client requesting the connection
249 struct GNUNET_SERVICE_Client *client;
252 * Task to be run upon timeout
254 struct GNUNET_SCHEDULER_Task *timeout_task;
257 * The notification handle associated with the neighbour's connection request
259 struct NeighbourConnectNotification *nh;
262 * The id of the link-controllers operation responsible for creating this
269 * DLL head for the list of neighbour connect contexts
271 struct NeighbourConnectCtxt *ncc_head;
274 * DLL tail for the list of neighbour connect contexts
276 struct NeighbourConnectCtxt *ncc_tail;
279 * A list of directly linked neighbours
281 struct Slave **GST_slave_list;
284 * The size of directly linked neighbours list
286 unsigned int GST_slave_list_size;
291 static struct Route **route_list;
296 static struct LCFContext *lcf_head;
299 * The tail for the LCF queue
301 static struct LCFContext *lcf_tail;
304 * The lcf_task handle
306 static struct GNUNET_SCHEDULER_Task * lcf_proc_task_id;
309 * The size of the route list
311 static unsigned int route_list_size;
315 * Adds a slave to the slave array
317 * @param slave the slave controller to add
320 slave_list_add (struct Slave *slave)
322 if (slave->host_id >= GST_slave_list_size)
323 GST_array_grow_large_enough (GST_slave_list,
326 GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
327 GST_slave_list[slave->host_id] = slave;
332 * Clean up all forwarded operation overlay context matching the
333 * client given in @a cls.
335 * @param cls a `struct GNUNET_SERVICE_Client *` to match
337 * @param value the `struct RegisteredHostContext` to search for @a cls
338 * @return #GNUNET_OK (continue iterating)
341 drop_client_entries (void *cls,
342 const struct GNUNET_HashCode *key,
345 struct GNUNET_SERVICE_Client *client = cls;
346 struct RegisteredHostContext *rhc = value;
347 struct ForwardedOverlayConnectContext *focc;
348 struct ForwardedOverlayConnectContext *foccn;
350 for (focc = rhc->focc_dll_head; NULL != focc; focc = foccn)
353 if (focc->client == client)
354 GST_cleanup_focc (focc);
361 * Adds a route to the route list
363 * @param route the route to add
366 route_list_add (struct Route *route)
368 if (route->dest >= route_list_size)
369 GST_array_grow_large_enough (route_list, route_list_size, route->dest);
370 GNUNET_assert (NULL == route_list[route->dest]);
371 route_list[route->dest] = route;
376 * Add a neighbour to the neighbour list. Grows the neighbour list
379 * @param n the neighbour to add
382 neighbour_list_add (struct Neighbour *n)
384 if (n->host_id >= neighbour_list_size)
385 GST_array_grow_large_enough (neighbour_list, neighbour_list_size, n->host_id);
386 GNUNET_assert (NULL == neighbour_list[n->host_id]);
387 neighbour_list[n->host_id] = n;
392 * Cleans up the route list
395 GST_route_list_clear ()
399 for (id = 0; id < route_list_size; id++)
400 if (NULL != route_list[id])
401 GNUNET_free (route_list[id]);
402 GNUNET_free_non_null (route_list);
408 * Iterator for freeing hash map entries in a slave's reghost_map
410 * @param cls handle to the slave
411 * @param key current key code
412 * @param value value in the hash map
413 * @return #GNUNET_YES if we should continue to iterate,
417 reghost_free_iterator (void *cls,
418 const struct GNUNET_HashCode *key,
421 struct Slave *slave = cls;
422 struct RegisteredHostContext *rhc = value;
423 struct ForwardedOverlayConnectContext *focc;
425 GNUNET_assert (GNUNET_YES ==
426 GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
428 while (NULL != (focc = rhc->focc_dll_head))
429 GST_cleanup_focc (focc);
436 * Kill a #Slave object
438 * @param slave the #Slave object
441 kill_slave (struct Slave *slave)
443 struct HostRegistration *hr_entry;
445 while (NULL != (hr_entry = slave->hr_dll_head))
447 GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail,
449 GNUNET_free (hr_entry);
451 if (NULL != slave->rhandle)
452 GNUNET_TESTBED_cancel_registration (slave->rhandle);
453 GNUNET_assert (GNUNET_SYSERR !=
454 GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map,
455 reghost_free_iterator,
457 GNUNET_CONTAINER_multihashmap_destroy (slave->reghost_map);
458 if (NULL != slave->controller)
459 GNUNET_TESTBED_controller_disconnect (slave->controller);
460 if (NULL != slave->controller_proc)
462 LOG_DEBUG ("Stopping a slave\n");
463 GNUNET_TESTBED_controller_kill_ (slave->controller_proc);
469 * Destroy a #Slave object
471 * @param slave the #Slave object
474 destroy_slave (struct Slave *slave)
476 if (NULL != slave->controller_proc)
478 GNUNET_TESTBED_controller_destroy_ (slave->controller_proc);
479 LOG_DEBUG ("Slave stopped\n");
481 GST_slave_list[slave->host_id] = NULL;
487 * Cleans up the slave list
490 GST_slave_list_clear ()
495 for (id = 0; id < GST_slave_list_size; id++)
497 slave = GST_slave_list[id];
502 for (id = 0; id < GST_slave_list_size; id++)
504 slave = GST_slave_list[id];
507 destroy_slave (slave);
509 GNUNET_free_non_null (GST_slave_list);
510 GST_slave_list = NULL;
515 * Finds the route with directly connected host as destination through which
516 * the destination host can be reached
518 * @param host_id the id of the destination host
519 * @return the route with directly connected destination host; NULL if no route
523 GST_find_dest_route (uint32_t host_id)
527 if (route_list_size <= host_id)
529 while (NULL != (route = route_list[host_id]))
531 if (route->thru == GST_context->host_id)
533 host_id = route->thru;
540 * Function to send a failure reponse for controller link operation
542 * @param client the client to send the message to
543 * @param operation_id the operation ID of the controller link request
544 * @param cfg the configuration with which the delegated controller is started.
545 * Can be NULL if the delegated controller is not started but just
547 * @param emsg set to an error message explaining why the controller link
548 * failed. Setting this to NULL signifies success. !This should be
549 * NULL if cfg is set!
552 send_controller_link_response (struct GNUNET_SERVICE_Client *client,
553 uint64_t operation_id,
554 const struct GNUNET_CONFIGURATION_Handle *cfg,
557 struct GNUNET_MQ_Envelope *env;
558 struct GNUNET_TESTBED_ControllerLinkResponse *msg;
564 GNUNET_assert ((NULL == cfg) || (NULL == emsg));
571 xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
574 msize += xconfig_size;
577 msize += strlen (emsg);
578 env = GNUNET_MQ_msg_extra (msg,
580 GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
582 msg->success = htons (GNUNET_YES);
583 msg->operation_id = GNUNET_htonll (operation_id);
584 msg->config_size = htons ((uint16_t) config_size);
587 GNUNET_memcpy (&msg[1],
590 GNUNET_free (xconfig);
593 GNUNET_memcpy (&msg[1],
596 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
602 * The Link Controller forwarding task
604 * @param cls the LCFContext
607 lcf_proc_task (void *cls);
611 * Completion callback for host registrations while forwarding Link Controller messages
613 * @param cls the LCFContext
614 * @param emsg the error message; NULL if host registration is successful
617 lcf_proc_cc (void *cls,
620 struct LCFContext *lcf = cls;
622 GNUNET_assert (NULL == lcf_proc_task_id);
627 goto registration_error;
628 lcf->state = DELEGATED_HOST_REGISTERED;
629 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
631 case DELEGATED_HOST_REGISTERED:
633 goto registration_error;
634 lcf->state = SLAVE_HOST_REGISTERED;
635 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
638 GNUNET_assert (0); /* Shouldn't reach here */
643 LOG (GNUNET_ERROR_TYPE_WARNING,
644 "Host registration failed with message: %s\n",
646 lcf->state = FINISHED;
647 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
653 * The Link Controller forwarding task
655 * @param cls the LCFContext
658 lcf_proc_task (void *cls);
662 * Task to free resources when forwarded link controllers has been timedout
664 * @param cls the LCFContext
667 lcf_forwarded_operation_timeout (void *cls)
669 struct LCFContext *lcf = cls;
671 lcf->timeout_task = NULL;
672 // GST_forwarded_operation_timeout (lcf->fopc, tc);
673 LOG (GNUNET_ERROR_TYPE_WARNING,
674 "A forwarded controller link operation has timed out\n");
675 send_controller_link_response (lcf->client,
678 "A forwarded controller link operation has timed out\n");
679 GNUNET_assert (NULL == lcf_proc_task_id);
680 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
686 * The Link Controller forwarding task
688 * @param cls the LCFContext
691 lcf_proc_task (void *cls)
693 struct LCFContext *lcf = cls;
695 lcf_proc_task_id = NULL;
700 GNUNET_TESTBED_is_host_registered_ (GST_host_list
701 [lcf->delegated_host_id],
702 lcf->gateway->controller))
704 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
705 GST_host_list[lcf->delegated_host_id]);
709 lcf->state = DELEGATED_HOST_REGISTERED;
710 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
713 case DELEGATED_HOST_REGISTERED:
715 GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
716 lcf->gateway->controller))
718 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
719 GST_host_list[lcf->slave_host_id]);
723 lcf->state = SLAVE_HOST_REGISTERED;
724 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
727 case SLAVE_HOST_REGISTERED:
728 lcf->op = GNUNET_TESTBED_controller_link (lcf,
729 lcf->gateway->controller,
730 GST_host_list[lcf->delegated_host_id],
731 GST_host_list[lcf->slave_host_id],
732 lcf->is_subordinate);
734 GNUNET_SCHEDULER_add_delayed (GST_timeout,
735 &lcf_forwarded_operation_timeout,
737 lcf->state = FINISHED;
741 GNUNET_TESTBED_operation_done (lcf->op);
742 GNUNET_CONTAINER_DLL_remove (lcf_head,
746 if (NULL != lcf_head)
747 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
754 * Callback for event from slave controllers
757 * @param event information about the event
760 slave_event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
762 struct LCFContext *lcf;
764 /* We currently only get here when working on LCFContexts */
765 GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
767 GNUNET_assert (lcf->op == event->op);
768 GNUNET_TESTBED_operation_done (lcf->op);
770 GNUNET_assert (FINISHED == lcf->state);
771 GNUNET_assert (NULL != lcf->timeout_task);
772 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
773 if (NULL == event->details.operation_finished.emsg)
774 send_controller_link_response (lcf->client, lcf->operation_id,
775 GNUNET_TESTBED_host_get_cfg_
776 (GST_host_list[lcf->delegated_host_id]),
779 send_controller_link_response (lcf->client, lcf->operation_id,
781 event->details.operation_finished.emsg);
782 GNUNET_assert (NULL == lcf_proc_task_id);
783 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
789 * Callback to signal successfull startup of the controller process
791 * @param cls the handle to the slave whose status is to be found here
792 * @param cfg the configuration with which the controller has been started;
793 * NULL if status is not #GNUNET_OK
794 * @param status #GNUNET_OK if the startup is successfull; #GNUNET_SYSERR if not,
795 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
798 slave_status_cb (void *cls,
799 const struct GNUNET_CONFIGURATION_Handle *cfg,
802 struct Slave *slave = cls;
803 struct LinkControllersContext *lcc;
806 if (GNUNET_SYSERR == status)
808 slave->controller_proc = NULL;
809 /* Stop all link controller forwarding tasks since we shutdown here anyway
810 and as these tasks they depend on the operation queues which are created
811 through GNUNET_TESTBED_controller_connect() and in kill_slave() we call
812 the destructor function GNUNET_TESTBED_controller_disconnect() */
815 destroy_slave (slave);
817 LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
818 GNUNET_SCHEDULER_shutdown (); /* We too shutdown */
822 GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
823 EVENT_MASK, &slave_event_cb,
825 if (NULL != slave->controller)
827 send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
831 send_controller_link_response (lcc->client, lcc->operation_id, NULL,
832 "Could not connect to delegated controller");
834 destroy_slave (slave);
841 if (NULL != lcc->client)
843 GNUNET_SERVICE_client_continue (lcc->client);
854 * Trigger notification task if there are notification requests currently
855 * waiting in the given neighbour. Also activates the neighbour connect operation
856 * if it was previously inactivated so that the connection to the neighbour can
859 * @param n the neighbour
862 trigger_notifications (struct Neighbour *n);
866 * Task to call the notification queued in the notifications list of the given
869 * @param cls the neighbour
872 neighbour_connect_notify_task (void *cls)
874 struct Neighbour *n = cls;
875 struct NeighbourConnectNotification *h;
877 GNUNET_assert (NULL != (h = n->nl_head));
878 GNUNET_assert (NULL != n->notify_task);
879 n->notify_task = NULL;
880 GNUNET_assert (NULL != n->controller);
881 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
882 trigger_notifications (n);
883 h->cb (h->cb_cls, n->controller);
889 * Trigger notification task if there are notification requests currently
890 * waiting in the given neighbour. Also activates the neighbour connect operation
891 * if it was previously inactivated so that the connection to the neighbour can
894 * @param n the neighbour
897 trigger_notifications (struct Neighbour *n)
899 GNUNET_assert (NULL != n->conn_op);
900 if (NULL == n->nl_head)
902 if (NULL == n->controller)
904 if (NULL != n->notify_task)
906 if (1 == n->inactive)
908 GNUNET_assert (0 == n->reference_cnt);
909 GNUNET_TESTBED_operation_activate_ (n->conn_op);
914 GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n);
919 * Callback to be called when the neighbour connect operation is started. The
920 * connection to the neigbour is opened here and any pending notifications are
923 * @param cls the neighbour
926 opstart_neighbour_conn (void *cls)
928 struct Neighbour *n = cls;
930 GNUNET_assert (NULL != n->conn_op);
931 GNUNET_assert (NULL == n->controller);
932 LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
933 n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
937 trigger_notifications (n);
942 * Callback to be called when the neighbour connect operation is released
944 * @param cls the neighbour
947 oprelease_neighbour_conn (void *cls)
949 struct Neighbour *n = cls;
951 GNUNET_assert (0 == n->reference_cnt);
952 GNUNET_assert (NULL == n->notify_task);
953 GNUNET_assert (NULL == n->nl_head);
954 if (NULL != n->controller)
956 LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
957 GNUNET_TESTBED_controller_disconnect (n->controller);
958 n->controller = NULL;
966 * Try to open a connection to the given neigbour. If the connection is open
967 * already, then it is re-used. If not, the request is queued in the operation
968 * queues responsible for bounding the total number of file descriptors. The
969 * actual connection will happen when the operation queue marks the
970 * corresponding operation as active.
972 * @param n the neighbour to open a connection to
973 * @param cb the notification callback to call when the connection is opened
974 * @param cb_cls the closure for the above callback
976 struct NeighbourConnectNotification *
977 GST_neighbour_get_connection (struct Neighbour *n,
978 GST_NeigbourConnectNotifyCallback cb,
981 struct NeighbourConnectNotification *h;
983 GNUNET_assert (NULL != cb);
984 LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
986 h = GNUNET_new (struct NeighbourConnectNotification);
990 GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
991 if (NULL == n->conn_op)
993 GNUNET_assert (NULL == n->controller);
994 n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
995 &oprelease_neighbour_conn);
996 GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
997 GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
1000 trigger_notifications (n);
1006 * Cancel the request for opening a connection to the neighbour
1008 * @param h the notification handle
1011 GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
1013 struct Neighbour *n;
1017 cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
1018 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
1020 if (GNUNET_NO == cleanup_task)
1022 if (NULL == n->notify_task)
1024 GNUNET_assert (0 < n->reference_cnt);
1026 GNUNET_SCHEDULER_cancel (n->notify_task);
1027 n->notify_task = NULL;
1028 if (NULL == n->nl_head)
1030 if ( (0 == n->reference_cnt) && (0 == n->inactive) )
1033 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1037 trigger_notifications (n);
1042 * Release the connection to the neighbour. The actual connection will be
1043 * closed if connections to other neighbour are waiting (to maintain a bound on
1044 * the total number of connections that are open).
1046 * @param n the neighbour whose connection can be closed
1049 GST_neighbour_release_connection (struct Neighbour *n)
1051 GNUNET_assert (0 == n->inactive);
1052 GNUNET_assert (0 < n->reference_cnt);
1054 if (0 == n->reference_cnt)
1057 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1063 * Cleanup neighbour connect contexts
1065 * @param ncc the neighbour connect context to cleanup
1068 cleanup_ncc (struct NeighbourConnectCtxt *ncc)
1070 if (NULL != ncc->nh)
1071 GST_neighbour_get_connection_cancel (ncc->nh);
1072 if (NULL != ncc->timeout_task)
1073 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1074 GNUNET_CONTAINER_DLL_remove (ncc_head,
1082 * Cleans up the neighbour list
1085 GST_neighbour_list_clean ()
1087 struct Neighbour *n;
1090 for (id = 0; id < neighbour_list_size; id++)
1092 if (NULL == (n = neighbour_list[id]))
1094 if (NULL != n->conn_op)
1095 GNUNET_TESTBED_operation_release_ (n->conn_op);
1097 neighbour_list[id] = NULL;
1099 GNUNET_free_non_null (neighbour_list);
1104 * Get a neighbour from the neighbour list
1106 * @param id the index of the neighbour in the neighbour list
1107 * @return the Neighbour; NULL if the given index in invalid (index greater than
1108 * the list size or neighbour at that index is NULL)
1111 GST_get_neighbour (uint32_t id)
1113 if (neighbour_list_size <= id)
1115 return neighbour_list[id];
1120 * Function to cleanup the neighbour connect contexts
1125 while (NULL != ncc_head)
1126 cleanup_ncc (ncc_head);
1131 * Task to be run upon timeout while attempting to connect to the neighbour
1133 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1136 timeout_neighbour_connect (void *cls)
1138 struct NeighbourConnectCtxt *ncc = cls;
1140 ncc->timeout_task = NULL;
1141 send_controller_link_response (ncc->client,
1144 "Could not connect to delegated controller");
1150 * Callback called when a connection to the neighbour is made
1152 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1153 * @param c the handle the neighbour's controller
1156 neighbour_connect_cb (void *cls,
1157 struct GNUNET_TESTBED_Controller *c)
1159 struct NeighbourConnectCtxt *ncc = cls;
1161 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1162 ncc->timeout_task = NULL;
1164 GST_neighbour_release_connection (ncc->n);
1165 send_controller_link_response (ncc->client,
1174 * Function to create a neigbour and add it into the neighbour list
1176 * @param host the host of the neighbour
1179 GST_create_neighbour (struct GNUNET_TESTBED_Host *host)
1181 struct Neighbour *n;
1183 n = GNUNET_new (struct Neighbour);
1184 n->host_id = GNUNET_TESTBED_host_get_id_ (host);
1185 neighbour_list_add (n); /* just add; connect on-demand */
1191 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1193 * @param cls identification of the client
1194 * @param msg the actual message
1197 handle_link_controllers (void *cls,
1198 const struct GNUNET_TESTBED_ControllerLinkRequest *msg)
1200 struct GNUNET_SERVICE_Client *client = cls;
1201 struct LCFContext *lcf;
1202 struct Route *route;
1203 struct Route *new_route;
1205 uint32_t delegated_host_id;
1206 uint32_t slave_host_id;
1208 if (NULL == GST_context)
1211 GNUNET_SERVICE_client_drop (client);
1214 delegated_host_id = ntohl (msg->delegated_host_id);
1215 if (delegated_host_id == GST_context->host_id)
1218 LOG (GNUNET_ERROR_TYPE_WARNING,
1219 "Trying to link ourselves\n");
1220 GNUNET_SERVICE_client_drop (client);
1223 if ((delegated_host_id >= GST_host_list_size) ||
1224 (NULL == GST_host_list[delegated_host_id]))
1226 LOG (GNUNET_ERROR_TYPE_WARNING,
1227 "Delegated host %u not registered with us\n",
1229 GNUNET_SERVICE_client_drop (client);
1232 slave_host_id = ntohl (msg->slave_host_id);
1233 if ((slave_host_id >= GST_host_list_size) ||
1234 (NULL == GST_host_list[slave_host_id]))
1236 LOG (GNUNET_ERROR_TYPE_WARNING,
1237 "Slave host %u not registered with us\n",
1239 GNUNET_SERVICE_client_drop (client);
1242 if (slave_host_id == delegated_host_id)
1244 LOG (GNUNET_ERROR_TYPE_WARNING,
1245 "Slave and delegated host are same\n");
1246 GNUNET_SERVICE_client_drop (client);
1249 op_id = GNUNET_ntohll (msg->operation_id);
1250 if (slave_host_id == GST_context->host_id) /* Link from us */
1252 struct Slave *slave;
1253 struct LinkControllersContext *lcc;
1255 if (1 != msg->is_subordinate)
1257 struct Neighbour *n;
1258 struct NeighbourConnectCtxt *ncc;
1260 if ((delegated_host_id < neighbour_list_size) &&
1261 (NULL != neighbour_list[delegated_host_id]))
1264 GNUNET_SERVICE_client_drop (client);
1267 LOG_DEBUG ("Received request to establish a link to host %u\n",
1269 n = GST_create_neighbour (GST_host_list[delegated_host_id]);
1270 ncc = GNUNET_new (struct NeighbourConnectCtxt);
1273 ncc->client = client;
1274 ncc->nh = GST_neighbour_get_connection (n,
1275 &neighbour_connect_cb,
1278 = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1279 &timeout_neighbour_connect,
1281 GNUNET_CONTAINER_DLL_insert_tail (ncc_head,
1284 GNUNET_SERVICE_client_continue (client);
1287 if ( (delegated_host_id < GST_slave_list_size) &&
1288 (NULL != GST_slave_list[delegated_host_id]) )
1291 GNUNET_SERVICE_client_drop (client);
1294 LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1296 slave = GNUNET_new (struct Slave);
1297 slave->host_id = delegated_host_id;
1298 slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100,
1300 slave_list_add (slave);
1301 lcc = GNUNET_new (struct LinkControllersContext);
1302 lcc->operation_id = op_id;
1303 lcc->client = client;
1305 slave->controller_proc
1306 = GNUNET_TESTBED_controller_start (GST_context->master_ip,
1307 GST_host_list[slave->host_id],
1310 new_route = GNUNET_new (struct Route);
1311 new_route->dest = delegated_host_id;
1312 new_route->thru = GST_context->host_id;
1313 route_list_add (new_route);
1317 /* Route the request */
1318 if (slave_host_id >= route_list_size)
1320 LOG (GNUNET_ERROR_TYPE_WARNING,
1321 "No route towards slave host");
1322 GNUNET_SERVICE_client_drop (client);
1325 lcf = GNUNET_new (struct LCFContext);
1326 lcf->delegated_host_id = delegated_host_id;
1327 lcf->slave_host_id = slave_host_id;
1328 route = GST_find_dest_route (slave_host_id);
1329 GNUNET_assert (NULL != route); /* because we add routes carefully */
1330 GNUNET_assert (route->dest < GST_slave_list_size);
1331 GNUNET_assert (NULL != GST_slave_list[route->dest]);
1332 lcf->is_subordinate = msg->is_subordinate;
1334 lcf->operation_id = op_id;
1335 lcf->gateway = GST_slave_list[route->dest];
1336 lcf->client = client;
1337 if (NULL == lcf_head)
1339 GNUNET_assert (NULL == lcf_proc_task_id);
1340 GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1343 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
1348 GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1352 /* FIXME: Adding a new route should happen after the controllers are linked
1354 if (1 != msg->is_subordinate)
1356 GNUNET_SERVICE_client_continue (client);
1359 if ( (delegated_host_id < route_list_size) &&
1360 (NULL != route_list[delegated_host_id]) )
1362 GNUNET_break_op (0); /* Are you trying to link delegated host twice
1363 * with is subordinate flag set to GNUNET_YES? */
1364 GNUNET_SERVICE_client_drop (client);
1367 new_route = GNUNET_new (struct Route);
1368 new_route->dest = delegated_host_id;
1369 new_route->thru = route->dest;
1370 route_list_add (new_route);
1371 GNUNET_SERVICE_client_continue (client);
1376 * Clean up @a client handle if we stored any via #handle_link_controllers(),
1377 * the given client disconnected.
1379 * @param client the client that is history
1382 GST_link_notify_disconnect (struct GNUNET_SERVICE_Client *client)
1384 struct NeighbourConnectCtxt *ncc;
1385 struct NeighbourConnectCtxt *nccn;
1386 struct LCFContext *lcf;
1387 struct LCFContext *lcfn;
1389 for (ncc = ncc_head; NULL != ncc; ncc = nccn)
1392 if (ncc->client == client)
1395 for (unsigned int i=0;i<GST_slave_list_size;i++)
1397 struct Slave *slave = GST_slave_list[i];
1398 struct LinkControllersContext *lcc;
1402 GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map,
1403 &drop_client_entries,
1408 if (lcc->client == client)
1414 for (lcf = lcf_head; NULL != lcf; lcf = lcfn)
1417 if ( (NULL != lcf) &&
1418 (client == lcf->client) )
1420 if (NULL != lcf->op)
1421 GNUNET_TESTBED_operation_done (lcf->op);
1422 GNUNET_CONTAINER_DLL_remove (lcf_head,
1432 * Cleans up the queue used for forwarding link controllers requests
1437 struct LCFContext *lcf;
1439 if (NULL != lcf_head)
1441 if (NULL != lcf_proc_task_id)
1443 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1444 lcf_proc_task_id = NULL;
1447 GNUNET_assert (NULL == lcf_proc_task_id);
1448 for (lcf = lcf_head; NULL != lcf; lcf = lcf_head)
1450 if (NULL != lcf->op)
1451 GNUNET_TESTBED_operation_done (lcf->op);
1452 if (NULL != lcf->timeout_task)
1453 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
1454 GNUNET_CONTAINER_DLL_remove (lcf_head,