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