aboutsummaryrefslogtreecommitdiff
path: root/src/testbed/gnunet-service-testbed_links.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testbed/gnunet-service-testbed_links.c')
-rw-r--r--src/testbed/gnunet-service-testbed_links.c452
1 files changed, 428 insertions, 24 deletions
diff --git a/src/testbed/gnunet-service-testbed_links.c b/src/testbed/gnunet-service-testbed_links.c
index d09e4aff6..ae984e331 100644
--- a/src/testbed/gnunet-service-testbed_links.c
+++ b/src/testbed/gnunet-service-testbed_links.c
@@ -19,18 +19,199 @@
19*/ 19*/
20 20
21/** 21/**
22 * @file testbed/gnunet-service-testbed.c 22 * @file testbed/gnunet-service-testbed_links.c
23 * @brief implementation of the TESTBED service 23 * @brief TESTBED service components that deals with starting slave controllers
24 * and establishing lateral links between controllers
24 * @author Sree Harsha Totakura 25 * @author Sree Harsha Totakura
25 */ 26 */
26 27
27#include "gnunet-service-testbed.h" 28#include "gnunet-service-testbed.h"
28 29
29/** 30/**
31 * Redefine LOG with a changed log component string
32 */
33#ifdef LOG
34#undef LOG
35#endif
36#define LOG(kind,...) \
37 GNUNET_log_from (kind, "testbed-links", __VA_ARGS__)
38
39/**
30 * The event mask for the events we listen from sub-controllers 40 * The event mask for the events we listen from sub-controllers
31 */ 41 */
32#define EVENT_MASK (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED) 42#define EVENT_MASK (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED)
33 43
44
45/**
46 * States of LCFContext
47 */
48enum LCFContextState
49{
50 /**
51 * The Context has been initialized; Nothing has been done on it
52 */
53 INIT,
54
55 /**
56 * Delegated host has been registered at the forwarding controller
57 */
58 DELEGATED_HOST_REGISTERED,
59
60 /**
61 * The slave host has been registred at the forwarding controller
62 */
63 SLAVE_HOST_REGISTERED,
64
65 /**
66 * The context has been finished (may have error)
67 */
68 FINISHED
69};
70
71
72/**
73 * Link controllers request forwarding context
74 */
75struct LCFContext
76{
77 /**
78 * The type of this data structure. Set this to CLOSURE_TYPE_LCF
79 */
80 enum ClosureType type;
81
82 /**
83 * The gateway which will pass the link message to delegated host
84 */
85 struct Slave *gateway;
86
87 /**
88 * The client which has asked to perform this operation
89 */
90 struct GNUNET_SERVER_Client *client;
91
92 /**
93 * Handle for operations which are forwarded while linking controllers
94 */
95 struct GNUNET_TESTBED_Operation *op;
96
97 /**
98 * The configuration which has to be either used as a template while starting
99 * the delegated controller or for connecting to the delegated controller
100 */
101 struct GNUNET_CONFIGURATION_Handle *cfg;
102
103 /**
104 * The timeout task
105 */
106 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
107
108 /**
109 * The id of the operation which created this context
110 */
111 uint64_t operation_id;
112
113 /**
114 * should the slave controller start the delegated controller?
115 */
116 int is_subordinate;
117
118 /**
119 * The state of this context
120 */
121 enum LCFContextState state;
122
123 /**
124 * The delegated host
125 */
126 uint32_t delegated_host_id;
127
128 /**
129 * The slave host
130 */
131 uint32_t slave_host_id;
132
133};
134
135
136/**
137 * Structure of a queue entry in LCFContext request queue
138 */
139struct LCFContextQueue
140{
141 /**
142 * The LCFContext
143 */
144 struct LCFContext *lcf;
145
146 /**
147 * Head prt for DLL
148 */
149 struct LCFContextQueue *next;
150
151 /**
152 * Tail ptr for DLL
153 */
154 struct LCFContextQueue *prev;
155};
156
157struct NeighbourConnectNotification
158{
159 struct NeighbourConnectNotification *next;
160 struct NeighbourConnectNotification *prev;
161 struct Neighbour *n;
162 GST_NeigbourConnectNotifyCallback cb;
163 void *cb_cls;
164};
165
166/**
167 * A connected controller which is not our child
168 */
169struct Neighbour
170{
171 /**
172 * The controller handle
173 */
174 struct GNUNET_TESTBED_Controller *controller;
175
176 /**
177 * Operation handle for opening a lateral connection to another controller.
178 * Will be NULL if the slave controller is started by this controller
179 */
180 struct GNUNET_TESTBED_Operation *conn_op;
181
182 struct NeighbourConnectNotification *nl_head;
183
184 struct NeighbourConnectNotification *nl_tail;
185
186 GNUNET_SCHEDULER_TaskIdentifier notify_task;
187
188 unsigned int reference_cnt;
189
190 /**
191 * The id of the host this controller is running on
192 */
193 uint32_t host_id;
194
195 int8_t inactive;
196};
197
198static struct Neighbour **neighbour_list;
199static unsigned int neighbour_list_size;
200
201struct NeighbourConnectCtxt
202{
203 struct NeighbourConnectCtxt *next;
204 struct NeighbourConnectCtxt *prev;
205 struct Neighbour *n;
206 struct GNUNET_SERVER_Client *client;
207 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
208 struct NeighbourConnectNotification *nh;
209 uint64_t op_id;
210};
211
212struct NeighbourConnectCtxt *ncc_head;
213struct NeighbourConnectCtxt *ncc_tail;
214
34/** 215/**
35 * A list of directly linked neighbours 216 * A list of directly linked neighbours
36 */ 217 */
@@ -97,6 +278,15 @@ route_list_add (struct Route *route)
97 route_list[route->dest] = route; 278 route_list[route->dest] = route;
98} 279}
99 280
281static void
282neighbour_list_add (struct Neighbour *n)
283{
284 if (n->host_id >= neighbour_list_size)
285 GST_array_grow_large_enough (neighbour_list, neighbour_list_size, n->host_id);
286 GNUNET_assert (NULL == neighbour_list[n->host_id]);
287 neighbour_list[n->host_id] = n;
288}
289
100 290
101/** 291/**
102 * Cleans up the route list 292 * Cleans up the route list
@@ -425,7 +615,7 @@ lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
425/** 615/**
426 * Callback for event from slave controllers 616 * Callback for event from slave controllers
427 * 617 *
428 * @param cls struct Slave * 618 * @param cls NULL
429 * @param event information about the event 619 * @param event information about the event
430 */ 620 */
431static void 621static void
@@ -491,6 +681,9 @@ slave_event_callback (void *cls,
491 GNUNET_assert (0); 681 GNUNET_assert (0);
492} 682}
493 683
684static void
685slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
686 int status);
494 687
495/** 688/**
496 * Callback to signal successfull startup of the controller process 689 * Callback to signal successfull startup of the controller process
@@ -552,6 +745,201 @@ clean_lcc:
552 slave->lcc = NULL; 745 slave->lcc = NULL;
553} 746}
554 747
748static void
749neighbour_connect_notify_task (void *cls,
750 const struct GNUNET_SCHEDULER_TaskContext *tc);
751
752static void
753trigger_notifications (struct Neighbour *n)
754{
755 GNUNET_assert (NULL != n->conn_op);
756 if (NULL == n->nl_head)
757 return;
758 if (NULL == n->controller)
759 return;
760 if (GNUNET_SCHEDULER_NO_TASK != n->notify_task)
761 return;
762 n->notify_task =
763 GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n->nl_head);
764}
765
766static void
767neighbour_connect_notify_task (void *cls,
768 const struct GNUNET_SCHEDULER_TaskContext *tc)
769{
770 struct NeighbourConnectNotification *h = cls;
771 struct Neighbour *n;
772
773 n = h->n;
774 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->notify_task);
775 n->notify_task = GNUNET_SCHEDULER_NO_TASK;
776 GNUNET_assert (NULL != n->controller);
777 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
778 trigger_notifications (n);
779 if ((0 == n->reference_cnt) && (1 == n->inactive))
780 {
781 GNUNET_TESTBED_operation_activate_ (n->conn_op);
782 n->inactive = 0;
783 }
784 n->reference_cnt++;
785 h->cb (h->cb_cls, n->controller);
786}
787
788static void
789opstart_neighbour_conn (void *cls)
790{
791 struct Neighbour *n = cls;
792
793 GNUNET_assert (NULL != n->conn_op);
794 GNUNET_assert (NULL == n->controller);
795 LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
796 n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
797 EVENT_MASK,
798 &slave_event_callback,
799 NULL);
800 trigger_notifications (n);
801}
802
803static void
804oprelease_neighbour_conn (void *cls)
805{
806 struct Neighbour *n = cls;
807
808 GNUNET_assert (0 == n->reference_cnt);
809 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->notify_task);
810 GNUNET_assert (NULL == n->nl_head);
811 LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
812 GNUNET_TESTBED_controller_disconnect (n->controller);
813 n->controller = NULL;
814 n->conn_op = NULL;
815}
816
817struct NeighbourConnectNotification *
818GST_neighbour_get_connection (struct Neighbour *n,
819 GST_NeigbourConnectNotifyCallback cb,
820 void *cb_cls)
821{
822 struct NeighbourConnectNotification *h;
823
824 GNUNET_assert (NULL != cb);
825 LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
826 n->host_id);
827 h = GNUNET_malloc (sizeof (struct NeighbourConnectNotification));
828 h->n = n;
829 h->cb = cb;
830 h->cb_cls = cb_cls;
831 GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
832 if (NULL == n->conn_op)
833 {
834 GNUNET_assert (NULL == n->controller);
835 n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
836 &oprelease_neighbour_conn);
837 GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
838 GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
839 return h;
840 }
841 trigger_notifications (n);
842 return h;
843}
844
845void
846GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
847{
848 struct Neighbour *n;
849
850 n = h->n;
851 if ((h == n->nl_head) && (GNUNET_SCHEDULER_NO_TASK != n->notify_task))
852 {
853 GNUNET_SCHEDULER_cancel (n->notify_task);
854 n->notify_task = GNUNET_SCHEDULER_NO_TASK;
855 }
856 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
857 GNUNET_free (h);
858}
859
860void
861GST_neighbour_release_connection (struct Neighbour *n)
862{
863 GNUNET_assert (0 == n->inactive);
864 GNUNET_assert (0 < n->reference_cnt);
865 n->reference_cnt--;
866 if (0 == n->reference_cnt)
867 {
868 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
869 n->inactive = 1;
870 }
871}
872
873static void
874cleanup_ncc (struct NeighbourConnectCtxt *ncc)
875{
876 if (NULL != ncc->nh)
877 GST_neighbour_get_connection_cancel (ncc->nh);
878 if (GNUNET_SCHEDULER_NO_TASK != ncc->timeout_task)
879 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
880 GNUNET_SERVER_client_drop (ncc->client);
881 GNUNET_CONTAINER_DLL_remove (ncc_head, ncc_tail, ncc);
882 GNUNET_free (ncc);
883}
884
885void
886GST_neighbour_list_clean()
887{
888 struct Neighbour *n;
889 unsigned int id;
890
891 for (id = 0; id < neighbour_list_size; id++)
892 {
893 if (NULL == (n = neighbour_list[id]))
894 continue;
895 if (NULL != n->conn_op)
896 GNUNET_TESTBED_operation_release_ (n->conn_op);
897 GNUNET_free (n);
898 neighbour_list[id] = NULL;
899 }
900 GNUNET_free_non_null (neighbour_list);
901}
902
903struct Neighbour *
904GST_get_neighbour (uint32_t id)
905{
906 if (neighbour_list_size <= id)
907 return NULL;
908 else
909 return neighbour_list[id];
910}
911
912void
913GST_free_nccq ()
914{
915 while (NULL != ncc_head)
916 cleanup_ncc (ncc_head);
917}
918
919static void
920timeout_neighbour_connect (void *cls,
921 const struct GNUNET_SCHEDULER_TaskContext *tc)
922{
923 struct NeighbourConnectCtxt *ncc = cls;
924
925 ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
926 send_controller_link_response (ncc->client, ncc->op_id, NULL,
927 "Could not connect to delegated controller");
928 cleanup_ncc (ncc);
929}
930
931static void
932neighbour_connect_cb (void *cls, struct GNUNET_TESTBED_Controller *c)
933{
934 struct NeighbourConnectCtxt *ncc = cls;
935
936 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
937 ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
938 ncc->nh = NULL;
939 GST_neighbour_release_connection (ncc->n);
940 send_controller_link_response (ncc->client, ncc->op_id, NULL, NULL);
941 cleanup_ncc (ncc);
942}
555 943
556/** 944/**
557 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message 945 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
@@ -569,6 +957,7 @@ GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
569 struct LCFContextQueue *lcfq; 957 struct LCFContextQueue *lcfq;
570 struct Route *route; 958 struct Route *route;
571 struct Route *new_route; 959 struct Route *new_route;
960 uint64_t op_id;
572 uint32_t delegated_host_id; 961 uint32_t delegated_host_id;
573 uint32_t slave_host_id; 962 uint32_t slave_host_id;
574 uint16_t msize; 963 uint16_t msize;
@@ -625,11 +1014,43 @@ GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
625 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 1014 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
626 return; 1015 return;
627 } 1016 }
1017 op_id = GNUNET_ntohll (msg->operation_id);
628 if (slave_host_id == GST_context->host_id) /* Link from us */ 1018 if (slave_host_id == GST_context->host_id) /* Link from us */
629 { 1019 {
630 struct Slave *slave; 1020 struct Slave *slave;
631 struct LinkControllersContext *lcc; 1021 struct LinkControllersContext *lcc;
632 1022
1023
1024 if (1 != msg->is_subordinate)
1025 {
1026 struct Neighbour *n;
1027 struct NeighbourConnectCtxt *ncc;
1028
1029 if ((delegated_host_id < neighbour_list_size) &&
1030 (NULL != neighbour_list[delegated_host_id]))
1031 {
1032 GNUNET_break (0);
1033 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1034 return;
1035 }
1036 LOG_DEBUG ("Received request to establish a link to host %u\n",
1037 delegated_host_id);
1038 n = GNUNET_malloc (sizeof (struct Neighbour));
1039 n->host_id = delegated_host_id;
1040 neighbour_list_add (n); /* just add; connect on-demand */
1041 ncc = GNUNET_malloc (sizeof (struct NeighbourConnectCtxt));
1042 ncc->n = n;
1043 ncc->op_id = op_id;
1044 ncc->client = client;
1045 GNUNET_SERVER_client_keep (client);
1046 ncc->nh = GST_neighbour_get_connection (n, neighbour_connect_cb, ncc);
1047 ncc->timeout_task = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1048 &timeout_neighbour_connect,
1049 ncc);
1050 GNUNET_CONTAINER_DLL_insert_tail (ncc_head, ncc_tail, ncc);
1051 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1052 return;
1053 }
633 if ((delegated_host_id < GST_slave_list_size) && 1054 if ((delegated_host_id < GST_slave_list_size) &&
634 (NULL != GST_slave_list[delegated_host_id])) 1055 (NULL != GST_slave_list[delegated_host_id]))
635 { 1056 {
@@ -637,31 +1058,14 @@ GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
637 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 1058 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
638 return; 1059 return;
639 } 1060 }
1061 LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1062 delegated_host_id);
640 slave = GNUNET_malloc (sizeof (struct Slave)); 1063 slave = GNUNET_malloc (sizeof (struct Slave));
641 slave->host_id = delegated_host_id; 1064 slave->host_id = delegated_host_id;
642 slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO); 1065 slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
643 slave_list_add (slave); 1066 slave_list_add (slave);
644 if (1 != msg->is_subordinate)
645 {
646 slave->controller =
647 GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
648 EVENT_MASK, &slave_event_callback,
649 slave);
650 if (NULL != slave->controller)
651 send_controller_link_response (client,
652 GNUNET_ntohll (msg->operation_id),
653 NULL,
654 NULL);
655 else
656 send_controller_link_response (client,
657 GNUNET_ntohll (msg->operation_id),
658 NULL,
659 "Could not connect to delegated controller");
660 GNUNET_SERVER_receive_done (client, GNUNET_OK);
661 return;
662 }
663 lcc = GNUNET_malloc (sizeof (struct LinkControllersContext)); 1067 lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
664 lcc->operation_id = GNUNET_ntohll (msg->operation_id); 1068 lcc->operation_id = op_id;
665 GNUNET_SERVER_client_keep (client); 1069 GNUNET_SERVER_client_keep (client);
666 lcc->client = client; 1070 lcc->client = client;
667 slave->lcc = lcc; 1071 slave->lcc = lcc;
@@ -696,7 +1100,7 @@ GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
696 lcfq->lcf->cfg = cfg; 1100 lcfq->lcf->cfg = cfg;
697 lcfq->lcf->is_subordinate = msg->is_subordinate; 1101 lcfq->lcf->is_subordinate = msg->is_subordinate;
698 lcfq->lcf->state = INIT; 1102 lcfq->lcf->state = INIT;
699 lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id); 1103 lcfq->lcf->operation_id = op_id;
700 lcfq->lcf->gateway = GST_slave_list[route->dest]; 1104 lcfq->lcf->gateway = GST_slave_list[route->dest];
701 GNUNET_SERVER_client_keep (client); 1105 GNUNET_SERVER_client_keep (client);
702 lcfq->lcf->client = client; 1106 lcfq->lcf->client = client;