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.c1467
1 files changed, 0 insertions, 1467 deletions
diff --git a/src/testbed/gnunet-service-testbed_links.c b/src/testbed/gnunet-service-testbed_links.c
deleted file mode 100644
index fe87d64ea..000000000
--- a/src/testbed/gnunet-service-testbed_links.c
+++ /dev/null
@@ -1,1467 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
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
26 */
27
28#include "gnunet-service-testbed.h"
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/**
40 * The event mask for the events we listen from sub-controllers
41 */
42#define EVENT_MASK (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED)
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 registered 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 LCFContext
79 */
80 struct LCFContext *next;
81
82 /**
83 * The LCFContext
84 */
85 struct LCFContext *prev;
86
87 /**
88 * The gateway which will pass the link message to delegated host
89 */
90 struct Slave *gateway;
91
92 /**
93 * The client which has asked to perform this operation
94 */
95 struct GNUNET_SERVICE_Client *client;
96
97 /**
98 * Handle for operations which are forwarded while linking controllers
99 */
100 struct GNUNET_TESTBED_Operation *op;
101
102 /**
103 * The timeout task
104 */
105 struct GNUNET_SCHEDULER_Task *timeout_task;
106
107 /**
108 * The id of the operation which created this context
109 */
110 uint64_t operation_id;
111
112 /**
113 * should the slave controller start the delegated controller?
114 */
115 int is_subordinate;
116
117 /**
118 * The state of this context
119 */
120 enum LCFContextState state;
121
122 /**
123 * The delegated host
124 */
125 uint32_t delegated_host_id;
126
127 /**
128 * The slave host
129 */
130 uint32_t slave_host_id;
131};
132
133
134/**
135 * Notification context to be used to notify when connection to the neighbour's
136 * controller is opened
137 */
138struct NeighbourConnectNotification
139{
140 /**
141 * DLL next for inclusion in neighbour's list of notification requests
142 */
143 struct NeighbourConnectNotification *next;
144
145 /**
146 * DLL prev
147 */
148 struct NeighbourConnectNotification *prev;
149
150 /**
151 * The neighbour
152 */
153 struct Neighbour *n;
154
155 /**
156 * The notification callback to call when we are connect to neighbour
157 */
158 GST_NeighbourConnectNotifyCallback cb;
159
160 /**
161 * The closure for the above callback
162 */
163 void *cb_cls;
164};
165
166
167/**
168 * A connected controller which is not our child
169 */
170struct Neighbour
171{
172 /**
173 * The controller handle
174 */
175 struct GNUNET_TESTBED_Controller *controller;
176
177 /**
178 * Operation handle for opening a lateral connection to another controller.
179 * Will be NULL if the slave controller is started by this controller
180 */
181 struct GNUNET_TESTBED_Operation *conn_op;
182
183 /**
184 * DLL head for the list of notification requests
185 */
186 struct NeighbourConnectNotification *nl_head;
187
188 /**
189 * DLL tail for the list of notification requests
190 */
191 struct NeighbourConnectNotification *nl_tail;
192
193 /**
194 * Task id for the task to call notifications from the notification list
195 */
196 struct GNUNET_SCHEDULER_Task *notify_task;
197
198 /**
199 * How many references are present currently to this neighbour's connection
200 */
201 unsigned int reference_cnt;
202
203 /**
204 * Is the conn_op inactivated?
205 */
206 unsigned int inactive;
207
208 /**
209 * The id of the host this controller is running on
210 */
211 uint32_t host_id;
212};
213
214
215/**
216 * The neighbour list
217 */
218static struct Neighbour **neighbour_list;
219
220/**
221 * The size of the neighbour list
222 */
223static unsigned int neighbour_list_size;
224
225
226/**
227 * Context information for establishing a link to neighbour (Used is
228 * GST_handle_link_controllers()
229 */
230struct NeighbourConnectCtxt
231{
232 /**
233 * DLL next for inclusion in the corresponding context list
234 */
235 struct NeighbourConnectCtxt *next;
236
237 /**
238 * DLL tail
239 */
240 struct NeighbourConnectCtxt *prev;
241
242 /**
243 * The neighbour to whom connection should be made
244 */
245 struct Neighbour *n;
246
247 /**
248 * The client requesting the connection
249 */
250 struct GNUNET_SERVICE_Client *client;
251
252 /**
253 * Task to be run upon timeout
254 */
255 struct GNUNET_SCHEDULER_Task *timeout_task;
256
257 /**
258 * The notification handle associated with the neighbour's connection request
259 */
260 struct NeighbourConnectNotification *nh;
261
262 /**
263 * The id of the link-controllers operation responsible for creating this
264 * context
265 */
266 uint64_t op_id;
267};
268
269/**
270 * DLL head for the list of neighbour connect contexts
271 */
272struct NeighbourConnectCtxt *ncc_head;
273
274/**
275 * DLL tail for the list of neighbour connect contexts
276 */
277struct NeighbourConnectCtxt *ncc_tail;
278
279/**
280 * A list of directly linked neighbours
281 */
282struct Slave **GST_slave_list;
283
284/**
285 * The size of directly linked neighbours list
286 */
287unsigned int GST_slave_list_size;
288
289/**
290 * A list of routes
291 */
292static struct Route **route_list;
293
294/**
295 * The LCF queue
296 */
297static struct LCFContext *lcf_head;
298
299/**
300 * The tail for the LCF queue
301 */
302static struct LCFContext *lcf_tail;
303
304/**
305 * The lcf_task handle
306 */
307static struct GNUNET_SCHEDULER_Task *lcf_proc_task_id;
308
309/**
310 * The size of the route list
311 */
312static unsigned int route_list_size;
313
314
315/**
316 * Adds a slave to the slave array
317 *
318 * @param slave the slave controller to add
319 */
320static void
321slave_list_add (struct Slave *slave)
322{
323 if (slave->host_id >= GST_slave_list_size)
324 GST_array_grow_large_enough (GST_slave_list,
325 GST_slave_list_size,
326 slave->host_id);
327 GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
328 GST_slave_list[slave->host_id] = slave;
329}
330
331
332/**
333 * Clean up all forwarded operation overlay context matching the
334 * client given in @a cls.
335 *
336 * @param cls a `struct GNUNET_SERVICE_Client *` to match
337 * @param key unused
338 * @param value the `struct RegisteredHostContext` to search for @a cls
339 * @return #GNUNET_OK (continue iterating)
340 */
341static int
342drop_client_entries (void *cls,
343 const struct GNUNET_HashCode *key,
344 void *value)
345{
346 struct GNUNET_SERVICE_Client *client = cls;
347 struct RegisteredHostContext *rhc = value;
348 struct ForwardedOverlayConnectContext *focc;
349 struct ForwardedOverlayConnectContext *foccn;
350
351 for (focc = rhc->focc_dll_head; NULL != focc; focc = foccn)
352 {
353 foccn = focc->next;
354 if (focc->client == client)
355 GST_cleanup_focc (focc);
356 }
357 return GNUNET_OK;
358}
359
360
361/**
362 * Adds a route to the route list
363 *
364 * @param route the route to add
365 */
366static void
367route_list_add (struct Route *route)
368{
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;
373}
374
375
376/**
377 * Add a neighbour to the neighbour list. Grows the neighbour list
378 * automatically.
379 *
380 * @param n the neighbour to add
381 */
382static void
383neighbour_list_add (struct Neighbour *n)
384{
385 if (n->host_id >= neighbour_list_size)
386 GST_array_grow_large_enough (neighbour_list, neighbour_list_size,
387 n->host_id);
388 GNUNET_assert (NULL == neighbour_list[n->host_id]);
389 neighbour_list[n->host_id] = n;
390}
391
392
393/**
394 * Cleans up the route list
395 */
396void
397GST_route_list_clear ()
398{
399 unsigned int id;
400
401 for (id = 0; id < route_list_size; id++)
402 if (NULL != route_list[id])
403 GNUNET_free (route_list[id]);
404 GNUNET_free (route_list);
405 route_list = NULL;
406}
407
408
409/**
410 * Iterator for freeing hash map entries in a slave's reghost_map
411 *
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,
416 * #GNUNET_NO if not.
417 */
418static int
419reghost_free_iterator (void *cls,
420 const struct GNUNET_HashCode *key,
421 void *value)
422{
423 struct Slave *slave = cls;
424 struct RegisteredHostContext *rhc = value;
425 struct ForwardedOverlayConnectContext *focc;
426
427 GNUNET_assert (GNUNET_YES ==
428 GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
429 value));
430 while (NULL != (focc = rhc->focc_dll_head))
431 GST_cleanup_focc (focc);
432 GNUNET_free (value);
433 return GNUNET_YES;
434}
435
436
437/**
438 * Kill a #Slave object
439 *
440 * @param slave the #Slave object
441 */
442static void
443kill_slave (struct Slave *slave)
444{
445 struct HostRegistration *hr_entry;
446
447 while (NULL != (hr_entry = slave->hr_dll_head))
448 {
449 GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail,
450 hr_entry);
451 GNUNET_free (hr_entry);
452 }
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,
458 slave));
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)
463 {
464 LOG_DEBUG ("Stopping a slave\n");
465 GNUNET_TESTBED_controller_kill_ (slave->controller_proc);
466 }
467}
468
469
470/**
471 * Destroy a #Slave object
472 *
473 * @param slave the #Slave object
474 */
475static void
476destroy_slave (struct Slave *slave)
477{
478 if (NULL != slave->controller_proc)
479 {
480 GNUNET_TESTBED_controller_destroy_ (slave->controller_proc);
481 LOG_DEBUG ("Slave stopped\n");
482 }
483 GST_slave_list[slave->host_id] = NULL;
484 GNUNET_free (slave);
485}
486
487
488/**
489 * Cleans up the slave list
490 */
491void
492GST_slave_list_clear ()
493{
494 struct Slave *slave;
495 unsigned int id;
496
497 for (id = 0; id < GST_slave_list_size; id++)
498 {
499 slave = GST_slave_list[id];
500 if (NULL == slave)
501 continue;
502 kill_slave (slave);
503 }
504 for (id = 0; id < GST_slave_list_size; id++)
505 {
506 slave = GST_slave_list[id];
507 if (NULL == slave)
508 continue;
509 destroy_slave (slave);
510 }
511 GNUNET_free (GST_slave_list);
512 GST_slave_list = NULL;
513}
514
515
516/**
517 * Finds the route with directly connected host as destination through which
518 * the destination host can be reached
519 *
520 * @param host_id the id of the destination host
521 * @return the route with directly connected destination host; NULL if no route
522 * is found
523 */
524struct Route *
525GST_find_dest_route (uint32_t host_id)
526{
527 struct Route *route;
528
529 if (route_list_size <= host_id)
530 return NULL;
531 while (NULL != (route = route_list[host_id]))
532 {
533 if (route->thru == GST_context->host_id)
534 break;
535 host_id = route->thru;
536 }
537 return route;
538}
539
540
541/**
542 * Function to send a failure response for controller link operation
543 *
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
548 * linked to.
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!
552 */
553static void
554send_controller_link_response (struct GNUNET_SERVICE_Client *client,
555 uint64_t operation_id,
556 const struct GNUNET_CONFIGURATION_Handle *cfg,
557 const char *emsg)
558{
559 struct GNUNET_MQ_Envelope *env;
560 struct GNUNET_TESTBED_ControllerLinkResponse *msg;
561 char *xconfig;
562 size_t config_size;
563 size_t xconfig_size;
564 uint16_t msize;
565
566 GNUNET_assert ((NULL == cfg) || (NULL == emsg));
567 xconfig = NULL;
568 xconfig_size = 0;
569 config_size = 0;
570 msize = 0;
571 if (NULL != cfg)
572 {
573 xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
574 &config_size,
575 &xconfig_size);
576 msize += xconfig_size;
577 }
578 if (NULL != emsg)
579 msize += strlen (emsg);
580 env = GNUNET_MQ_msg_extra (msg,
581 msize,
582 GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
583 if (NULL == emsg)
584 msg->success = htons (GNUNET_YES);
585 msg->operation_id = GNUNET_htonll (operation_id);
586 msg->config_size = htons ((uint16_t) config_size);
587 if (NULL != xconfig)
588 {
589 GNUNET_memcpy (&msg[1],
590 xconfig,
591 xconfig_size);
592 GNUNET_free (xconfig);
593 }
594 if (NULL != emsg)
595 GNUNET_memcpy (&msg[1],
596 emsg,
597 strlen (emsg));
598 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
599 env);
600}
601
602
603/**
604 * The Link Controller forwarding task
605 *
606 * @param cls the LCFContext
607 */
608static void
609lcf_proc_task (void *cls);
610
611
612/**
613 * Completion callback for host registrations while forwarding Link Controller messages
614 *
615 * @param cls the LCFContext
616 * @param emsg the error message; NULL if host registration is successful
617 */
618static void
619lcf_proc_cc (void *cls,
620 const char *emsg)
621{
622 struct LCFContext *lcf = cls;
623
624 GNUNET_assert (NULL == lcf_proc_task_id);
625 switch (lcf->state)
626 {
627 case INIT:
628 if (NULL != emsg)
629 goto registration_error;
630 lcf->state = DELEGATED_HOST_REGISTERED;
631 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
632 break;
633
634 case DELEGATED_HOST_REGISTERED:
635 if (NULL != emsg)
636 goto registration_error;
637 lcf->state = SLAVE_HOST_REGISTERED;
638 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
639 break;
640
641 default:
642 GNUNET_assert (0); /* Shouldn't reach here */
643 }
644 return;
645
646registration_error:
647 LOG (GNUNET_ERROR_TYPE_WARNING,
648 "Host registration failed with message: %s\n",
649 emsg);
650 lcf->state = FINISHED;
651 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
652 lcf);
653}
654
655
656/**
657 * The Link Controller forwarding task
658 *
659 * @param cls the LCFContext
660 */
661static void
662lcf_proc_task (void *cls);
663
664
665/**
666 * Task to free resources when forwarded link controllers has been timedout
667 *
668 * @param cls the LCFContext
669 */
670static void
671lcf_forwarded_operation_timeout (void *cls)
672{
673 struct LCFContext *lcf = cls;
674
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,
680 lcf->operation_id,
681 NULL,
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,
685 lcf);
686}
687
688
689/**
690 * The Link Controller forwarding task
691 *
692 * @param cls the LCFContext
693 */
694static void
695lcf_proc_task (void *cls)
696{
697 struct LCFContext *lcf = cls;
698
699 lcf_proc_task_id = NULL;
700 switch (lcf->state)
701 {
702 case INIT:
703 if (GNUNET_NO ==
704 GNUNET_TESTBED_is_host_registered_ (GST_host_list
705 [lcf->delegated_host_id],
706 lcf->gateway->controller))
707 {
708 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
709 GST_host_list[lcf->delegated_host_id]);
710 }
711 else
712 {
713 lcf->state = DELEGATED_HOST_REGISTERED;
714 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
715 }
716 break;
717
718 case DELEGATED_HOST_REGISTERED:
719 if (GNUNET_NO ==
720 GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
721 lcf->gateway->controller))
722 {
723 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
724 GST_host_list[lcf->slave_host_id]);
725 }
726 else
727 {
728 lcf->state = SLAVE_HOST_REGISTERED;
729 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
730 }
731 break;
732
733 case SLAVE_HOST_REGISTERED:
734 lcf->op = GNUNET_TESTBED_controller_link (lcf,
735 lcf->gateway->controller,
736 GST_host_list[lcf->
737 delegated_host_id],
738 GST_host_list[lcf->slave_host_id],
739 lcf->is_subordinate);
740 lcf->timeout_task =
741 GNUNET_SCHEDULER_add_delayed (GST_timeout,
742 &lcf_forwarded_operation_timeout,
743 lcf);
744 lcf->state = FINISHED;
745 break;
746
747 case FINISHED:
748 if (NULL != lcf->op)
749 GNUNET_TESTBED_operation_done (lcf->op);
750 GNUNET_CONTAINER_DLL_remove (lcf_head,
751 lcf_tail,
752 lcf);
753 GNUNET_free (lcf);
754 if (NULL != lcf_head)
755 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
756 lcf_head);
757 }
758}
759
760
761/**
762 * Callback for event from slave controllers
763 *
764 * @param cls NULL
765 * @param event information about the event
766 */
767static void
768slave_event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
769{
770 struct LCFContext *lcf;
771
772 /* We currently only get here when working on LCFContexts */
773 GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
774 lcf = event->op_cls;
775 GNUNET_assert (lcf->op == event->op);
776 GNUNET_TESTBED_operation_done (lcf->op);
777 lcf->op = NULL;
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]),
785 NULL);
786 else
787 send_controller_link_response (lcf->client, lcf->operation_id,
788 NULL,
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);
792 return;
793}
794
795
796/**
797 * Callback to signal successful startup of the controller process
798 *
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 successful; #GNUNET_SYSERR if not,
803 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
804 */
805static void
806slave_status_cb (void *cls,
807 const struct GNUNET_CONFIGURATION_Handle *cfg,
808 int status)
809{
810 struct Slave *slave = cls;
811 struct LinkControllersContext *lcc;
812
813 lcc = slave->lcc;
814 if (GNUNET_SYSERR == status)
815 {
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() */
821 GST_free_lcf ();
822 kill_slave (slave);
823 destroy_slave (slave);
824 slave = NULL;
825 LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
826 GNUNET_SCHEDULER_shutdown (); /* We too shutdown */
827 goto clean_lcc;
828 }
829 slave->controller =
830 GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
831 EVENT_MASK, &slave_event_cb,
832 slave);
833 if (NULL != slave->controller)
834 {
835 send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
836 }
837 else
838 {
839 send_controller_link_response (lcc->client, lcc->operation_id, NULL,
840 "Could not connect to delegated controller");
841 kill_slave (slave);
842 destroy_slave (slave);
843 slave = NULL;
844 }
845
846clean_lcc:
847 if (NULL != lcc)
848 {
849 if (NULL != lcc->client)
850 {
851 GNUNET_SERVICE_client_continue (lcc->client);
852 lcc->client = NULL;
853 }
854 GNUNET_free (lcc);
855 }
856 if (NULL != slave)
857 slave->lcc = NULL;
858}
859
860
861/**
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
865 * be re-used
866 *
867 * @param n the neighbour
868 */
869static void
870trigger_notifications (struct Neighbour *n);
871
872
873/**
874 * Task to call the notification queued in the notifications list of the given
875 * neighbour
876 *
877 * @param cls the neighbour
878 */
879static void
880neighbour_connect_notify_task (void *cls)
881{
882 struct Neighbour *n = cls;
883 struct NeighbourConnectNotification *h;
884
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);
892 GNUNET_free (h);
893}
894
895
896/**
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
900 * be re-used
901 *
902 * @param n the neighbour
903 */
904static void
905trigger_notifications (struct Neighbour *n)
906{
907 GNUNET_assert (NULL != n->conn_op);
908 if (NULL == n->nl_head)
909 return;
910 if (NULL == n->controller)
911 return;
912 if (NULL != n->notify_task)
913 return;
914 if (1 == n->inactive)
915 {
916 GNUNET_assert (0 == n->reference_cnt);
917 GNUNET_TESTBED_operation_activate_ (n->conn_op);
918 n->inactive = 0;
919 }
920 n->reference_cnt++;
921 n->notify_task =
922 GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n);
923}
924
925
926/**
927 * Callback to be called when the neighbour connect operation is started. The
928 * connection to the neighbour is opened here and any pending notifications are
929 * trigger.
930 *
931 * @param cls the neighbour
932 */
933static void
934opstart_neighbour_conn (void *cls)
935{
936 struct Neighbour *n = cls;
937
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],
942 EVENT_MASK,
943 &slave_event_cb,
944 NULL);
945 trigger_notifications (n);
946}
947
948
949/**
950 * Callback to be called when the neighbour connect operation is released
951 *
952 * @param cls the neighbour
953 */
954static void
955oprelease_neighbour_conn (void *cls)
956{
957 struct Neighbour *n = cls;
958
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)
963 {
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;
967 }
968 n->conn_op = NULL;
969 n->inactive = 0;
970}
971
972
973/**
974 * Try to open a connection to the given neighbour. 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.
979 *
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
983 */
984struct NeighbourConnectNotification *
985GST_neighbour_get_connection (struct Neighbour *n,
986 GST_NeighbourConnectNotifyCallback cb,
987 void *cb_cls)
988{
989 struct NeighbourConnectNotification *h;
990
991 GNUNET_assert (NULL != cb);
992 LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
993 n->host_id);
994 h = GNUNET_new (struct NeighbourConnectNotification);
995 h->n = n;
996 h->cb = cb;
997 h->cb_cls = cb_cls;
998 GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
999 if (NULL == n->conn_op)
1000 {
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);
1006 return h;
1007 }
1008 trigger_notifications (n);
1009 return h;
1010}
1011
1012
1013/**
1014 * Cancel the request for opening a connection to the neighbour
1015 *
1016 * @param h the notification handle
1017 */
1018void
1019GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
1020{
1021 struct Neighbour *n;
1022 int cleanup_task;
1023
1024 n = h->n;
1025 cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
1026 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
1027 GNUNET_free (h);
1028 if (GNUNET_NO == cleanup_task)
1029 return;
1030 if (NULL == n->notify_task)
1031 return;
1032 GNUNET_assert (0 < n->reference_cnt);
1033 n->reference_cnt--;
1034 GNUNET_SCHEDULER_cancel (n->notify_task);
1035 n->notify_task = NULL;
1036 if (NULL == n->nl_head)
1037 {
1038 if ((0 == n->reference_cnt) && (0 == n->inactive))
1039 {
1040 n->inactive = 1;
1041 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1042 }
1043 return;
1044 }
1045 trigger_notifications (n);
1046}
1047
1048
1049/**
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).
1053 *
1054 * @param n the neighbour whose connection can be closed
1055 */
1056void
1057GST_neighbour_release_connection (struct Neighbour *n)
1058{
1059 GNUNET_assert (0 == n->inactive);
1060 GNUNET_assert (0 < n->reference_cnt);
1061 n->reference_cnt--;
1062 if (0 == n->reference_cnt)
1063 {
1064 n->inactive = 1;
1065 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1066 }
1067}
1068
1069
1070/**
1071 * Cleanup neighbour connect contexts
1072 *
1073 * @param ncc the neighbour connect context to cleanup
1074 */
1075static void
1076cleanup_ncc (struct NeighbourConnectCtxt *ncc)
1077{
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,
1083 ncc_tail,
1084 ncc);
1085 GNUNET_free (ncc);
1086}
1087
1088
1089/**
1090 * Cleans up the neighbour list
1091 */
1092void
1093GST_neighbour_list_clean ()
1094{
1095 struct Neighbour *n;
1096 unsigned int id;
1097
1098 for (id = 0; id < neighbour_list_size; id++)
1099 {
1100 if (NULL == (n = neighbour_list[id]))
1101 continue;
1102 if (NULL != n->conn_op)
1103 GNUNET_TESTBED_operation_release_ (n->conn_op);
1104 GNUNET_free (n);
1105 neighbour_list[id] = NULL;
1106 }
1107 GNUNET_free (neighbour_list);
1108}
1109
1110
1111/**
1112 * Get a neighbour from the neighbour list
1113 *
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)
1117 */
1118struct Neighbour *
1119GST_get_neighbour (uint32_t id)
1120{
1121 if (neighbour_list_size <= id)
1122 return NULL;
1123 return neighbour_list[id];
1124}
1125
1126
1127/**
1128 * Function to cleanup the neighbour connect contexts
1129 */
1130void
1131GST_free_nccq ()
1132{
1133 while (NULL != ncc_head)
1134 cleanup_ncc (ncc_head);
1135}
1136
1137
1138/**
1139 * Task to be run upon timeout while attempting to connect to the neighbour
1140 *
1141 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1142 */
1143static void
1144timeout_neighbour_connect (void *cls)
1145{
1146 struct NeighbourConnectCtxt *ncc = cls;
1147
1148 ncc->timeout_task = NULL;
1149 send_controller_link_response (ncc->client,
1150 ncc->op_id,
1151 NULL,
1152 "Could not connect to delegated controller");
1153 cleanup_ncc (ncc);
1154}
1155
1156
1157/**
1158 * Callback called when a connection to the neighbour is made
1159 *
1160 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1161 * @param c the handle the neighbour's controller
1162 */
1163static void
1164neighbour_connect_cb (void *cls,
1165 struct GNUNET_TESTBED_Controller *c)
1166{
1167 struct NeighbourConnectCtxt *ncc = cls;
1168
1169 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1170 ncc->timeout_task = NULL;
1171 ncc->nh = NULL;
1172 GST_neighbour_release_connection (ncc->n);
1173 send_controller_link_response (ncc->client,
1174 ncc->op_id,
1175 NULL,
1176 NULL);
1177 cleanup_ncc (ncc);
1178}
1179
1180
1181/**
1182 * Function to create a neighbour and add it into the neighbour list
1183 *
1184 * @param host the host of the neighbour
1185 */
1186struct Neighbour *
1187GST_create_neighbour (struct GNUNET_TESTBED_Host *host)
1188{
1189 struct Neighbour *n;
1190
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 */
1194 return n;
1195}
1196
1197
1198/**
1199 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1200 *
1201 * @param cls identification of the client
1202 * @param msg the actual message
1203 */
1204void
1205handle_link_controllers (void *cls,
1206 const struct GNUNET_TESTBED_ControllerLinkRequest *msg)
1207{
1208 struct GNUNET_SERVICE_Client *client = cls;
1209 struct LCFContext *lcf;
1210 struct Route *route;
1211 struct Route *new_route;
1212 uint64_t op_id;
1213 uint32_t delegated_host_id;
1214 uint32_t slave_host_id;
1215
1216 if (NULL == GST_context)
1217 {
1218 GNUNET_break (0);
1219 GNUNET_SERVICE_client_drop (client);
1220 return;
1221 }
1222 delegated_host_id = ntohl (msg->delegated_host_id);
1223 if (delegated_host_id == GST_context->host_id)
1224 {
1225 GNUNET_break (0);
1226 LOG (GNUNET_ERROR_TYPE_WARNING,
1227 "Trying to link ourselves\n");
1228 GNUNET_SERVICE_client_drop (client);
1229 return;
1230 }
1231 if ((delegated_host_id >= GST_host_list_size) ||
1232 (NULL == GST_host_list[delegated_host_id]))
1233 {
1234 LOG (GNUNET_ERROR_TYPE_WARNING,
1235 "Delegated host %u not registered with us\n",
1236 delegated_host_id);
1237 GNUNET_SERVICE_client_drop (client);
1238 return;
1239 }
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]))
1243 {
1244 LOG (GNUNET_ERROR_TYPE_WARNING,
1245 "Slave host %u not registered with us\n",
1246 slave_host_id);
1247 GNUNET_SERVICE_client_drop (client);
1248 return;
1249 }
1250 if (slave_host_id == delegated_host_id)
1251 {
1252 LOG (GNUNET_ERROR_TYPE_WARNING,
1253 "Slave and delegated host are same\n");
1254 GNUNET_SERVICE_client_drop (client);
1255 return;
1256 }
1257 op_id = GNUNET_ntohll (msg->operation_id);
1258 if (slave_host_id == GST_context->host_id) /* Link from us */
1259 {
1260 struct Slave *slave;
1261 struct LinkControllersContext *lcc;
1262
1263 if (1 != msg->is_subordinate)
1264 {
1265 struct Neighbour *n;
1266 struct NeighbourConnectCtxt *ncc;
1267
1268 if ((delegated_host_id < neighbour_list_size) &&
1269 (NULL != neighbour_list[delegated_host_id]))
1270 {
1271 GNUNET_break (0);
1272 GNUNET_SERVICE_client_drop (client);
1273 return;
1274 }
1275 LOG_DEBUG ("Received request to establish a link to host %u\n",
1276 delegated_host_id);
1277 n = GST_create_neighbour (GST_host_list[delegated_host_id]);
1278 ncc = GNUNET_new (struct NeighbourConnectCtxt);
1279 ncc->n = n;
1280 ncc->op_id = op_id;
1281 ncc->client = client;
1282 ncc->nh = GST_neighbour_get_connection (n,
1283 &neighbour_connect_cb,
1284 ncc);
1285 ncc->timeout_task
1286 = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1287 &timeout_neighbour_connect,
1288 ncc);
1289 GNUNET_CONTAINER_DLL_insert_tail (ncc_head,
1290 ncc_tail,
1291 ncc);
1292 GNUNET_SERVICE_client_continue (client);
1293 return;
1294 }
1295 if ((delegated_host_id < GST_slave_list_size) &&
1296 (NULL != GST_slave_list[delegated_host_id]))
1297 {
1298 GNUNET_break (0);
1299 GNUNET_SERVICE_client_drop (client);
1300 return;
1301 }
1302 LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1303 delegated_host_id);
1304 slave = GNUNET_new (struct Slave);
1305 slave->host_id = delegated_host_id;
1306 slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100,
1307 GNUNET_NO);
1308 slave_list_add (slave);
1309 lcc = GNUNET_new (struct LinkControllersContext);
1310 lcc->operation_id = op_id;
1311 lcc->client = client;
1312 slave->lcc = lcc;
1313 slave->controller_proc
1314 = GNUNET_TESTBED_controller_start (GST_context->master_ip,
1315 GST_host_list[slave->host_id],
1316 &slave_status_cb,
1317 slave);
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);
1322 return;
1323 }
1324
1325 /* Route the request */
1326 if (slave_host_id >= route_list_size)
1327 {
1328 LOG (GNUNET_ERROR_TYPE_WARNING,
1329 "No route towards slave host");
1330 GNUNET_SERVICE_client_drop (client);
1331 return;
1332 }
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;
1341 lcf->state = INIT;
1342 lcf->operation_id = op_id;
1343 lcf->gateway = GST_slave_list[route->dest];
1344 lcf->client = client;
1345 if (NULL == lcf_head)
1346 {
1347 GNUNET_assert (NULL == lcf_proc_task_id);
1348 GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1349 lcf_tail,
1350 lcf);
1351 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
1352 lcf);
1353 }
1354 else
1355 {
1356 GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1357 lcf_tail,
1358 lcf);
1359 }
1360 /* FIXME: Adding a new route should happen after the controllers are linked
1361 * successfully */
1362 if (1 != msg->is_subordinate)
1363 {
1364 GNUNET_SERVICE_client_continue (client);
1365 return;
1366 }
1367 if ((delegated_host_id < route_list_size) &&
1368 (NULL != route_list[delegated_host_id]))
1369 {
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);
1373 return;
1374 }
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);
1380}
1381
1382
1383/**
1384 * Clean up @a client handle if we stored any via #handle_link_controllers(),
1385 * the given client disconnected.
1386 *
1387 * @param client the client that is history
1388 */
1389void
1390GST_link_notify_disconnect (struct GNUNET_SERVICE_Client *client)
1391{
1392 struct NeighbourConnectCtxt *ncc;
1393 struct NeighbourConnectCtxt *nccn;
1394 struct LCFContext *lcf;
1395 struct LCFContext *lcfn;
1396
1397 for (ncc = ncc_head; NULL != ncc; ncc = nccn)
1398 {
1399 nccn = ncc->next;
1400 if (ncc->client == client)
1401 cleanup_ncc (ncc);
1402 }
1403 for (unsigned int i = 0; i < GST_slave_list_size; i++)
1404 {
1405 struct Slave *slave = GST_slave_list[i];
1406 struct LinkControllersContext *lcc;
1407
1408 if (NULL == slave)
1409 continue;
1410 GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map,
1411 &drop_client_entries,
1412 client);
1413 lcc = slave->lcc;
1414 if (NULL == lcc)
1415 continue;
1416 if (lcc->client == client)
1417 {
1418 slave->lcc = NULL;
1419 GNUNET_free (lcc);
1420 }
1421 }
1422 for (lcf = lcf_head; NULL != lcf; lcf = lcfn)
1423 {
1424 lcfn = lcf->next;
1425 if ((NULL != lcf) &&
1426 (client == lcf->client))
1427 {
1428 if (NULL != lcf->op)
1429 GNUNET_TESTBED_operation_done (lcf->op);
1430 GNUNET_CONTAINER_DLL_remove (lcf_head,
1431 lcf_tail,
1432 lcf);
1433 GNUNET_free (lcf);
1434 }
1435 }
1436}
1437
1438
1439/**
1440 * Cleans up the queue used for forwarding link controllers requests
1441 */
1442void
1443GST_free_lcf ()
1444{
1445 struct LCFContext *lcf;
1446
1447 if (NULL != lcf_head)
1448 {
1449 if (NULL != lcf_proc_task_id)
1450 {
1451 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1452 lcf_proc_task_id = NULL;
1453 }
1454 }
1455 GNUNET_assert (NULL == lcf_proc_task_id);
1456 for (lcf = lcf_head; NULL != lcf; lcf = lcf_head)
1457 {
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,
1463 lcf_tail,
1464 lcf);
1465 GNUNET_free (lcf);
1466 }
1467}