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 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.
17 * @file testbed/gnunet-service-testbed_links.c
18 * @brief TESTBED service components that deals with starting slave controllers
19 * and establishing lateral links between controllers
20 * @author Sree Harsha Totakura
23 #include "gnunet-service-testbed.h"
26 * Redefine LOG with a changed log component string
31 #define LOG(kind,...) \
32 GNUNET_log_from (kind, "testbed-links", __VA_ARGS__)
35 * The event mask for the events we listen from sub-controllers
37 #define EVENT_MASK (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED)
41 * States of LCFContext
46 * The Context has been initialized; Nothing has been done on it
51 * Delegated host has been registered at the forwarding controller
53 DELEGATED_HOST_REGISTERED,
56 * The slave host has been registred at the forwarding controller
58 SLAVE_HOST_REGISTERED,
61 * The context has been finished (may have error)
68 * Link controllers request forwarding context
75 struct LCFContext *next;
80 struct LCFContext *prev;
83 * The gateway which will pass the link message to delegated host
85 struct Slave *gateway;
88 * The client which has asked to perform this operation
90 struct GNUNET_SERVICE_Client *client;
93 * Handle for operations which are forwarded while linking controllers
95 struct GNUNET_TESTBED_Operation *op;
100 struct GNUNET_SCHEDULER_Task *timeout_task;
103 * The id of the operation which created this context
105 uint64_t operation_id;
108 * should the slave controller start the delegated controller?
113 * The state of this context
115 enum LCFContextState state;
120 uint32_t delegated_host_id;
125 uint32_t slave_host_id;
131 * Notification context to be used to notify when connection to the neighbour's
132 * controller is opened
134 struct NeighbourConnectNotification
137 * DLL next for inclusion in neighbour's list of notification requests
139 struct NeighbourConnectNotification *next;
144 struct NeighbourConnectNotification *prev;
152 * The notification callback to call when we are connect to neighbour
154 GST_NeigbourConnectNotifyCallback cb;
157 * The closure for the above callback
164 * A connected controller which is not our child
169 * The controller handle
171 struct GNUNET_TESTBED_Controller *controller;
174 * Operation handle for opening a lateral connection to another controller.
175 * Will be NULL if the slave controller is started by this controller
177 struct GNUNET_TESTBED_Operation *conn_op;
180 * DLL head for the list of notification requests
182 struct NeighbourConnectNotification *nl_head;
185 * DLL tail for the list of notification requests
187 struct NeighbourConnectNotification *nl_tail;
190 * Task id for the task to call notifications from the notification list
192 struct GNUNET_SCHEDULER_Task * notify_task;
195 * How many references are present currently to this neighbour's connection
197 unsigned int reference_cnt;
200 * Is the conn_op inactivated?
202 unsigned int inactive;
205 * The id of the host this controller is running on
214 static struct Neighbour **neighbour_list;
217 * The size of the neighbour list
219 static unsigned int neighbour_list_size;
223 * Context information for establishing a link to neighbour (Used is
224 * GST_handle_link_controllers()
226 struct NeighbourConnectCtxt
229 * DLL next for inclusion in the corresponding context list
231 struct NeighbourConnectCtxt *next;
236 struct NeighbourConnectCtxt *prev;
239 * The neighbour to whom connection should be made
244 * The client requesting the connection
246 struct GNUNET_SERVICE_Client *client;
249 * Task to be run upon timeout
251 struct GNUNET_SCHEDULER_Task *timeout_task;
254 * The notification handle associated with the neighbour's connection request
256 struct NeighbourConnectNotification *nh;
259 * The id of the link-controllers operation responsible for creating this
266 * DLL head for the list of neighbour connect contexts
268 struct NeighbourConnectCtxt *ncc_head;
271 * DLL tail for the list of neighbour connect contexts
273 struct NeighbourConnectCtxt *ncc_tail;
276 * A list of directly linked neighbours
278 struct Slave **GST_slave_list;
281 * The size of directly linked neighbours list
283 unsigned int GST_slave_list_size;
288 static struct Route **route_list;
293 static struct LCFContext *lcf_head;
296 * The tail for the LCF queue
298 static struct LCFContext *lcf_tail;
301 * The lcf_task handle
303 static struct GNUNET_SCHEDULER_Task * lcf_proc_task_id;
306 * The size of the route list
308 static unsigned int route_list_size;
312 * Adds a slave to the slave array
314 * @param slave the slave controller to add
317 slave_list_add (struct Slave *slave)
319 if (slave->host_id >= GST_slave_list_size)
320 GST_array_grow_large_enough (GST_slave_list,
323 GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
324 GST_slave_list[slave->host_id] = slave;
329 * Clean up all forwarded operation overlay context matching the
330 * client given in @a cls.
332 * @param cls a `struct GNUNET_SERVICE_Client *` to match
334 * @param value the `struct RegisteredHostContext` to search for @a cls
335 * @return #GNUNET_OK (continue iterating)
338 drop_client_entries (void *cls,
339 const struct GNUNET_HashCode *key,
342 struct GNUNET_SERVICE_Client *client = cls;
343 struct RegisteredHostContext *rhc = value;
344 struct ForwardedOverlayConnectContext *focc;
345 struct ForwardedOverlayConnectContext *foccn;
347 for (focc = rhc->focc_dll_head; NULL != focc; focc = foccn)
350 if (focc->client == client)
351 GST_cleanup_focc (focc);
358 * Adds a route to the route list
360 * @param route the route to add
363 route_list_add (struct Route *route)
365 if (route->dest >= route_list_size)
366 GST_array_grow_large_enough (route_list, route_list_size, route->dest);
367 GNUNET_assert (NULL == route_list[route->dest]);
368 route_list[route->dest] = route;
373 * Add a neighbour to the neighbour list. Grows the neighbour list
376 * @param n the neighbour to add
379 neighbour_list_add (struct Neighbour *n)
381 if (n->host_id >= neighbour_list_size)
382 GST_array_grow_large_enough (neighbour_list, neighbour_list_size, n->host_id);
383 GNUNET_assert (NULL == neighbour_list[n->host_id]);
384 neighbour_list[n->host_id] = n;
389 * Cleans up the route list
392 GST_route_list_clear ()
396 for (id = 0; id < route_list_size; id++)
397 if (NULL != route_list[id])
398 GNUNET_free (route_list[id]);
399 GNUNET_free_non_null (route_list);
405 * Iterator for freeing hash map entries in a slave's reghost_map
407 * @param cls handle to the slave
408 * @param key current key code
409 * @param value value in the hash map
410 * @return #GNUNET_YES if we should continue to iterate,
414 reghost_free_iterator (void *cls,
415 const struct GNUNET_HashCode *key,
418 struct Slave *slave = cls;
419 struct RegisteredHostContext *rhc = value;
420 struct ForwardedOverlayConnectContext *focc;
422 GNUNET_assert (GNUNET_YES ==
423 GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
425 while (NULL != (focc = rhc->focc_dll_head))
426 GST_cleanup_focc (focc);
433 * Kill a #Slave object
435 * @param slave the #Slave object
438 kill_slave (struct Slave *slave)
440 struct HostRegistration *hr_entry;
442 while (NULL != (hr_entry = slave->hr_dll_head))
444 GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail,
446 GNUNET_free (hr_entry);
448 if (NULL != slave->rhandle)
449 GNUNET_TESTBED_cancel_registration (slave->rhandle);
450 GNUNET_assert (GNUNET_SYSERR !=
451 GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map,
452 reghost_free_iterator,
454 GNUNET_CONTAINER_multihashmap_destroy (slave->reghost_map);
455 if (NULL != slave->controller)
456 GNUNET_TESTBED_controller_disconnect (slave->controller);
457 if (NULL != slave->controller_proc)
459 LOG_DEBUG ("Stopping a slave\n");
460 GNUNET_TESTBED_controller_kill_ (slave->controller_proc);
466 * Destroy a #Slave object
468 * @param slave the #Slave object
471 destroy_slave (struct Slave *slave)
473 if (NULL != slave->controller_proc)
475 GNUNET_TESTBED_controller_destroy_ (slave->controller_proc);
476 LOG_DEBUG ("Slave stopped\n");
478 GST_slave_list[slave->host_id] = NULL;
484 * Cleans up the slave list
487 GST_slave_list_clear ()
492 for (id = 0; id < GST_slave_list_size; id++)
494 slave = GST_slave_list[id];
499 for (id = 0; id < GST_slave_list_size; id++)
501 slave = GST_slave_list[id];
504 destroy_slave (slave);
506 GNUNET_free_non_null (GST_slave_list);
507 GST_slave_list = NULL;
512 * Finds the route with directly connected host as destination through which
513 * the destination host can be reached
515 * @param host_id the id of the destination host
516 * @return the route with directly connected destination host; NULL if no route
520 GST_find_dest_route (uint32_t host_id)
524 if (route_list_size <= host_id)
526 while (NULL != (route = route_list[host_id]))
528 if (route->thru == GST_context->host_id)
530 host_id = route->thru;
537 * Function to send a failure reponse for controller link operation
539 * @param client the client to send the message to
540 * @param operation_id the operation ID of the controller link request
541 * @param cfg the configuration with which the delegated controller is started.
542 * Can be NULL if the delegated controller is not started but just
544 * @param emsg set to an error message explaining why the controller link
545 * failed. Setting this to NULL signifies success. !This should be
546 * NULL if cfg is set!
549 send_controller_link_response (struct GNUNET_SERVICE_Client *client,
550 uint64_t operation_id,
551 const struct GNUNET_CONFIGURATION_Handle *cfg,
554 struct GNUNET_MQ_Envelope *env;
555 struct GNUNET_TESTBED_ControllerLinkResponse *msg;
561 GNUNET_assert ((NULL == cfg) || (NULL == emsg));
568 xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
571 msize += xconfig_size;
574 msize += strlen (emsg);
575 env = GNUNET_MQ_msg_extra (msg,
577 GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
579 msg->success = htons (GNUNET_YES);
580 msg->operation_id = GNUNET_htonll (operation_id);
581 msg->config_size = htons ((uint16_t) config_size);
584 GNUNET_memcpy (&msg[1],
587 GNUNET_free (xconfig);
590 GNUNET_memcpy (&msg[1],
593 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
599 * The Link Controller forwarding task
601 * @param cls the LCFContext
604 lcf_proc_task (void *cls);
608 * Completion callback for host registrations while forwarding Link Controller messages
610 * @param cls the LCFContext
611 * @param emsg the error message; NULL if host registration is successful
614 lcf_proc_cc (void *cls,
617 struct LCFContext *lcf = cls;
619 GNUNET_assert (NULL == lcf_proc_task_id);
624 goto registration_error;
625 lcf->state = DELEGATED_HOST_REGISTERED;
626 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
628 case DELEGATED_HOST_REGISTERED:
630 goto registration_error;
631 lcf->state = SLAVE_HOST_REGISTERED;
632 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
635 GNUNET_assert (0); /* Shouldn't reach here */
640 LOG (GNUNET_ERROR_TYPE_WARNING,
641 "Host registration failed with message: %s\n",
643 lcf->state = FINISHED;
644 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
650 * The Link Controller forwarding task
652 * @param cls the LCFContext
655 lcf_proc_task (void *cls);
659 * Task to free resources when forwarded link controllers has been timedout
661 * @param cls the LCFContext
664 lcf_forwarded_operation_timeout (void *cls)
666 struct LCFContext *lcf = cls;
668 lcf->timeout_task = NULL;
669 // GST_forwarded_operation_timeout (lcf->fopc, tc);
670 LOG (GNUNET_ERROR_TYPE_WARNING,
671 "A forwarded controller link operation has timed out\n");
672 send_controller_link_response (lcf->client,
675 "A forwarded controller link operation has timed out\n");
676 GNUNET_assert (NULL == lcf_proc_task_id);
677 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
683 * The Link Controller forwarding task
685 * @param cls the LCFContext
688 lcf_proc_task (void *cls)
690 struct LCFContext *lcf = cls;
692 lcf_proc_task_id = NULL;
697 GNUNET_TESTBED_is_host_registered_ (GST_host_list
698 [lcf->delegated_host_id],
699 lcf->gateway->controller))
701 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
702 GST_host_list[lcf->delegated_host_id]);
706 lcf->state = DELEGATED_HOST_REGISTERED;
707 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
710 case DELEGATED_HOST_REGISTERED:
712 GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
713 lcf->gateway->controller))
715 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
716 GST_host_list[lcf->slave_host_id]);
720 lcf->state = SLAVE_HOST_REGISTERED;
721 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
724 case SLAVE_HOST_REGISTERED:
725 lcf->op = GNUNET_TESTBED_controller_link (lcf,
726 lcf->gateway->controller,
727 GST_host_list[lcf->delegated_host_id],
728 GST_host_list[lcf->slave_host_id],
729 lcf->is_subordinate);
731 GNUNET_SCHEDULER_add_delayed (GST_timeout,
732 &lcf_forwarded_operation_timeout,
734 lcf->state = FINISHED;
738 GNUNET_TESTBED_operation_done (lcf->op);
739 GNUNET_CONTAINER_DLL_remove (lcf_head,
743 if (NULL != lcf_head)
744 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
751 * Callback for event from slave controllers
754 * @param event information about the event
757 slave_event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
759 struct LCFContext *lcf;
761 /* We currently only get here when working on LCFContexts */
762 GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
764 GNUNET_assert (lcf->op == event->op);
765 GNUNET_TESTBED_operation_done (lcf->op);
767 GNUNET_assert (FINISHED == lcf->state);
768 GNUNET_assert (NULL != lcf->timeout_task);
769 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
770 if (NULL == event->details.operation_finished.emsg)
771 send_controller_link_response (lcf->client, lcf->operation_id,
772 GNUNET_TESTBED_host_get_cfg_
773 (GST_host_list[lcf->delegated_host_id]),
776 send_controller_link_response (lcf->client, lcf->operation_id,
778 event->details.operation_finished.emsg);
779 GNUNET_assert (NULL == lcf_proc_task_id);
780 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
786 * Callback to signal successfull startup of the controller process
788 * @param cls the handle to the slave whose status is to be found here
789 * @param cfg the configuration with which the controller has been started;
790 * NULL if status is not #GNUNET_OK
791 * @param status #GNUNET_OK if the startup is successfull; #GNUNET_SYSERR if not,
792 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
795 slave_status_cb (void *cls,
796 const struct GNUNET_CONFIGURATION_Handle *cfg,
799 struct Slave *slave = cls;
800 struct LinkControllersContext *lcc;
803 if (GNUNET_SYSERR == status)
805 slave->controller_proc = NULL;
806 /* Stop all link controller forwarding tasks since we shutdown here anyway
807 and as these tasks they depend on the operation queues which are created
808 through GNUNET_TESTBED_controller_connect() and in kill_slave() we call
809 the destructor function GNUNET_TESTBED_controller_disconnect() */
812 destroy_slave (slave);
814 LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
815 GNUNET_SCHEDULER_shutdown (); /* We too shutdown */
819 GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
820 EVENT_MASK, &slave_event_cb,
822 if (NULL != slave->controller)
824 send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
828 send_controller_link_response (lcc->client, lcc->operation_id, NULL,
829 "Could not connect to delegated controller");
831 destroy_slave (slave);
838 if (NULL != lcc->client)
840 GNUNET_SERVICE_client_continue (lcc->client);
851 * Trigger notification task if there are notification requests currently
852 * waiting in the given neighbour. Also activates the neighbour connect operation
853 * if it was previously inactivated so that the connection to the neighbour can
856 * @param n the neighbour
859 trigger_notifications (struct Neighbour *n);
863 * Task to call the notification queued in the notifications list of the given
866 * @param cls the neighbour
869 neighbour_connect_notify_task (void *cls)
871 struct Neighbour *n = cls;
872 struct NeighbourConnectNotification *h;
874 GNUNET_assert (NULL != (h = n->nl_head));
875 GNUNET_assert (NULL != n->notify_task);
876 n->notify_task = NULL;
877 GNUNET_assert (NULL != n->controller);
878 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
879 trigger_notifications (n);
880 h->cb (h->cb_cls, n->controller);
886 * Trigger notification task if there are notification requests currently
887 * waiting in the given neighbour. Also activates the neighbour connect operation
888 * if it was previously inactivated so that the connection to the neighbour can
891 * @param n the neighbour
894 trigger_notifications (struct Neighbour *n)
896 GNUNET_assert (NULL != n->conn_op);
897 if (NULL == n->nl_head)
899 if (NULL == n->controller)
901 if (NULL != n->notify_task)
903 if (1 == n->inactive)
905 GNUNET_assert (0 == n->reference_cnt);
906 GNUNET_TESTBED_operation_activate_ (n->conn_op);
911 GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n);
916 * Callback to be called when the neighbour connect operation is started. The
917 * connection to the neigbour is opened here and any pending notifications are
920 * @param cls the neighbour
923 opstart_neighbour_conn (void *cls)
925 struct Neighbour *n = cls;
927 GNUNET_assert (NULL != n->conn_op);
928 GNUNET_assert (NULL == n->controller);
929 LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
930 n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
934 trigger_notifications (n);
939 * Callback to be called when the neighbour connect operation is released
941 * @param cls the neighbour
944 oprelease_neighbour_conn (void *cls)
946 struct Neighbour *n = cls;
948 GNUNET_assert (0 == n->reference_cnt);
949 GNUNET_assert (NULL == n->notify_task);
950 GNUNET_assert (NULL == n->nl_head);
951 if (NULL != n->controller)
953 LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
954 GNUNET_TESTBED_controller_disconnect (n->controller);
955 n->controller = NULL;
963 * Try to open a connection to the given neigbour. If the connection is open
964 * already, then it is re-used. If not, the request is queued in the operation
965 * queues responsible for bounding the total number of file descriptors. The
966 * actual connection will happen when the operation queue marks the
967 * corresponding operation as active.
969 * @param n the neighbour to open a connection to
970 * @param cb the notification callback to call when the connection is opened
971 * @param cb_cls the closure for the above callback
973 struct NeighbourConnectNotification *
974 GST_neighbour_get_connection (struct Neighbour *n,
975 GST_NeigbourConnectNotifyCallback cb,
978 struct NeighbourConnectNotification *h;
980 GNUNET_assert (NULL != cb);
981 LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
983 h = GNUNET_new (struct NeighbourConnectNotification);
987 GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
988 if (NULL == n->conn_op)
990 GNUNET_assert (NULL == n->controller);
991 n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
992 &oprelease_neighbour_conn);
993 GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
994 GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
997 trigger_notifications (n);
1003 * Cancel the request for opening a connection to the neighbour
1005 * @param h the notification handle
1008 GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
1010 struct Neighbour *n;
1014 cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
1015 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
1017 if (GNUNET_NO == cleanup_task)
1019 if (NULL == n->notify_task)
1021 GNUNET_assert (0 < n->reference_cnt);
1023 GNUNET_SCHEDULER_cancel (n->notify_task);
1024 n->notify_task = NULL;
1025 if (NULL == n->nl_head)
1027 if ( (0 == n->reference_cnt) && (0 == n->inactive) )
1030 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1034 trigger_notifications (n);
1039 * Release the connection to the neighbour. The actual connection will be
1040 * closed if connections to other neighbour are waiting (to maintain a bound on
1041 * the total number of connections that are open).
1043 * @param n the neighbour whose connection can be closed
1046 GST_neighbour_release_connection (struct Neighbour *n)
1048 GNUNET_assert (0 == n->inactive);
1049 GNUNET_assert (0 < n->reference_cnt);
1051 if (0 == n->reference_cnt)
1054 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1060 * Cleanup neighbour connect contexts
1062 * @param ncc the neighbour connect context to cleanup
1065 cleanup_ncc (struct NeighbourConnectCtxt *ncc)
1067 if (NULL != ncc->nh)
1068 GST_neighbour_get_connection_cancel (ncc->nh);
1069 if (NULL != ncc->timeout_task)
1070 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1071 GNUNET_CONTAINER_DLL_remove (ncc_head,
1079 * Cleans up the neighbour list
1082 GST_neighbour_list_clean ()
1084 struct Neighbour *n;
1087 for (id = 0; id < neighbour_list_size; id++)
1089 if (NULL == (n = neighbour_list[id]))
1091 if (NULL != n->conn_op)
1092 GNUNET_TESTBED_operation_release_ (n->conn_op);
1094 neighbour_list[id] = NULL;
1096 GNUNET_free_non_null (neighbour_list);
1101 * Get a neighbour from the neighbour list
1103 * @param id the index of the neighbour in the neighbour list
1104 * @return the Neighbour; NULL if the given index in invalid (index greater than
1105 * the list size or neighbour at that index is NULL)
1108 GST_get_neighbour (uint32_t id)
1110 if (neighbour_list_size <= id)
1112 return neighbour_list[id];
1117 * Function to cleanup the neighbour connect contexts
1122 while (NULL != ncc_head)
1123 cleanup_ncc (ncc_head);
1128 * Task to be run upon timeout while attempting to connect to the neighbour
1130 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1133 timeout_neighbour_connect (void *cls)
1135 struct NeighbourConnectCtxt *ncc = cls;
1137 ncc->timeout_task = NULL;
1138 send_controller_link_response (ncc->client,
1141 "Could not connect to delegated controller");
1147 * Callback called when a connection to the neighbour is made
1149 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1150 * @param c the handle the neighbour's controller
1153 neighbour_connect_cb (void *cls,
1154 struct GNUNET_TESTBED_Controller *c)
1156 struct NeighbourConnectCtxt *ncc = cls;
1158 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1159 ncc->timeout_task = NULL;
1161 GST_neighbour_release_connection (ncc->n);
1162 send_controller_link_response (ncc->client,
1171 * Function to create a neigbour and add it into the neighbour list
1173 * @param host the host of the neighbour
1176 GST_create_neighbour (struct GNUNET_TESTBED_Host *host)
1178 struct Neighbour *n;
1180 n = GNUNET_new (struct Neighbour);
1181 n->host_id = GNUNET_TESTBED_host_get_id_ (host);
1182 neighbour_list_add (n); /* just add; connect on-demand */
1188 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1190 * @param cls identification of the client
1191 * @param msg the actual message
1194 handle_link_controllers (void *cls,
1195 const struct GNUNET_TESTBED_ControllerLinkRequest *msg)
1197 struct GNUNET_SERVICE_Client *client = cls;
1198 struct LCFContext *lcf;
1199 struct Route *route;
1200 struct Route *new_route;
1202 uint32_t delegated_host_id;
1203 uint32_t slave_host_id;
1205 if (NULL == GST_context)
1208 GNUNET_SERVICE_client_drop (client);
1211 delegated_host_id = ntohl (msg->delegated_host_id);
1212 if (delegated_host_id == GST_context->host_id)
1215 LOG (GNUNET_ERROR_TYPE_WARNING,
1216 "Trying to link ourselves\n");
1217 GNUNET_SERVICE_client_drop (client);
1220 if ((delegated_host_id >= GST_host_list_size) ||
1221 (NULL == GST_host_list[delegated_host_id]))
1223 LOG (GNUNET_ERROR_TYPE_WARNING,
1224 "Delegated host %u not registered with us\n",
1226 GNUNET_SERVICE_client_drop (client);
1229 slave_host_id = ntohl (msg->slave_host_id);
1230 if ((slave_host_id >= GST_host_list_size) ||
1231 (NULL == GST_host_list[slave_host_id]))
1233 LOG (GNUNET_ERROR_TYPE_WARNING,
1234 "Slave host %u not registered with us\n",
1236 GNUNET_SERVICE_client_drop (client);
1239 if (slave_host_id == delegated_host_id)
1241 LOG (GNUNET_ERROR_TYPE_WARNING,
1242 "Slave and delegated host are same\n");
1243 GNUNET_SERVICE_client_drop (client);
1246 op_id = GNUNET_ntohll (msg->operation_id);
1247 if (slave_host_id == GST_context->host_id) /* Link from us */
1249 struct Slave *slave;
1250 struct LinkControllersContext *lcc;
1252 if (1 != msg->is_subordinate)
1254 struct Neighbour *n;
1255 struct NeighbourConnectCtxt *ncc;
1257 if ((delegated_host_id < neighbour_list_size) &&
1258 (NULL != neighbour_list[delegated_host_id]))
1261 GNUNET_SERVICE_client_drop (client);
1264 LOG_DEBUG ("Received request to establish a link to host %u\n",
1266 n = GST_create_neighbour (GST_host_list[delegated_host_id]);
1267 ncc = GNUNET_new (struct NeighbourConnectCtxt);
1270 ncc->client = client;
1271 ncc->nh = GST_neighbour_get_connection (n,
1272 &neighbour_connect_cb,
1275 = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1276 &timeout_neighbour_connect,
1278 GNUNET_CONTAINER_DLL_insert_tail (ncc_head,
1281 GNUNET_SERVICE_client_continue (client);
1284 if ( (delegated_host_id < GST_slave_list_size) &&
1285 (NULL != GST_slave_list[delegated_host_id]) )
1288 GNUNET_SERVICE_client_drop (client);
1291 LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1293 slave = GNUNET_new (struct Slave);
1294 slave->host_id = delegated_host_id;
1295 slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100,
1297 slave_list_add (slave);
1298 lcc = GNUNET_new (struct LinkControllersContext);
1299 lcc->operation_id = op_id;
1300 lcc->client = client;
1302 slave->controller_proc
1303 = GNUNET_TESTBED_controller_start (GST_context->master_ip,
1304 GST_host_list[slave->host_id],
1307 new_route = GNUNET_new (struct Route);
1308 new_route->dest = delegated_host_id;
1309 new_route->thru = GST_context->host_id;
1310 route_list_add (new_route);
1314 /* Route the request */
1315 if (slave_host_id >= route_list_size)
1317 LOG (GNUNET_ERROR_TYPE_WARNING,
1318 "No route towards slave host");
1319 GNUNET_SERVICE_client_drop (client);
1322 lcf = GNUNET_new (struct LCFContext);
1323 lcf->delegated_host_id = delegated_host_id;
1324 lcf->slave_host_id = slave_host_id;
1325 route = GST_find_dest_route (slave_host_id);
1326 GNUNET_assert (NULL != route); /* because we add routes carefully */
1327 GNUNET_assert (route->dest < GST_slave_list_size);
1328 GNUNET_assert (NULL != GST_slave_list[route->dest]);
1329 lcf->is_subordinate = msg->is_subordinate;
1331 lcf->operation_id = op_id;
1332 lcf->gateway = GST_slave_list[route->dest];
1333 lcf->client = client;
1334 if (NULL == lcf_head)
1336 GNUNET_assert (NULL == lcf_proc_task_id);
1337 GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1340 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
1345 GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1349 /* FIXME: Adding a new route should happen after the controllers are linked
1351 if (1 != msg->is_subordinate)
1353 GNUNET_SERVICE_client_continue (client);
1356 if ( (delegated_host_id < route_list_size) &&
1357 (NULL != route_list[delegated_host_id]) )
1359 GNUNET_break_op (0); /* Are you trying to link delegated host twice
1360 * with is subordinate flag set to GNUNET_YES? */
1361 GNUNET_SERVICE_client_drop (client);
1364 new_route = GNUNET_new (struct Route);
1365 new_route->dest = delegated_host_id;
1366 new_route->thru = route->dest;
1367 route_list_add (new_route);
1368 GNUNET_SERVICE_client_continue (client);
1373 * Clean up @a client handle if we stored any via #handle_link_controllers(),
1374 * the given client disconnected.
1376 * @param client the client that is history
1379 GST_link_notify_disconnect (struct GNUNET_SERVICE_Client *client)
1381 struct NeighbourConnectCtxt *ncc;
1382 struct NeighbourConnectCtxt *nccn;
1383 struct LCFContext *lcf;
1384 struct LCFContext *lcfn;
1386 for (ncc = ncc_head; NULL != ncc; ncc = nccn)
1389 if (ncc->client == client)
1392 for (unsigned int i=0;i<GST_slave_list_size;i++)
1394 struct Slave *slave = GST_slave_list[i];
1395 struct LinkControllersContext *lcc;
1399 GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map,
1400 &drop_client_entries,
1405 if (lcc->client == client)
1411 for (lcf = lcf_head; NULL != lcf; lcf = lcfn)
1414 if ( (NULL != lcf) &&
1415 (client == lcf->client) )
1417 if (NULL != lcf->op)
1418 GNUNET_TESTBED_operation_done (lcf->op);
1419 GNUNET_CONTAINER_DLL_remove (lcf_head,
1429 * Cleans up the queue used for forwarding link controllers requests
1434 struct LCFContext *lcf;
1436 if (NULL != lcf_head)
1438 if (NULL != lcf_proc_task_id)
1440 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1441 lcf_proc_task_id = NULL;
1444 GNUNET_assert (NULL == lcf_proc_task_id);
1445 for (lcf = lcf_head; NULL != lcf; lcf = lcf_head)
1447 if (NULL != lcf->op)
1448 GNUNET_TESTBED_operation_done (lcf->op);
1449 if (NULL != lcf->timeout_task)
1450 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
1451 GNUNET_CONTAINER_DLL_remove (lcf_head,