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