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