1da0716605566b13847631ddc66e44d01dcfaf7f
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed_links.c
1 /*
2   This file is part of GNUnet.
3   (C) 2008--2013 Christian Grothoff (and other contributing authors)
4
5   GNUnet is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published
7   by the Free Software Foundation; either version 2, or (at your
8   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   General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with GNUnet; see the file COPYING.  If not, write to the
17   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18   Boston, MA 02111-1307, USA.
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   /**
51    * The Context has been initialized; Nothing has been done on it
52    */
53   INIT,
54
55   /**
56    * Delegated host has been registered at the forwarding controller
57    */
58   DELEGATED_HOST_REGISTERED,
59
60   /**
61    * The slave host has been registred at the forwarding controller
62    */
63   SLAVE_HOST_REGISTERED,
64
65   /**
66    * The context has been finished (may have error)
67    */
68   FINISHED
69 };
70
71
72 /**
73  * Link controllers request forwarding context
74  */
75 struct LCFContext
76 {
77   /**
78    * The type of this data structure. Set this to CLOSURE_TYPE_LCF
79    */
80   enum ClosureType type;
81   
82   /**
83    * The gateway which will pass the link message to delegated host
84    */
85   struct Slave *gateway;
86
87   /**
88    * The client which has asked to perform this operation
89    */
90   struct GNUNET_SERVER_Client *client;
91
92   /**
93    * Handle for operations which are forwarded while linking controllers
94    */
95   struct GNUNET_TESTBED_Operation *op;
96
97   /**
98    * The timeout task
99    */
100   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
101
102   /**
103    * The id of the operation which created this context
104    */
105   uint64_t operation_id;
106   
107   /**
108    * should the slave controller start the delegated controller?
109    */
110   int is_subordinate;
111
112   /**
113    * The state of this context
114    */
115   enum LCFContextState state;
116
117   /**
118    * The delegated host
119    */
120   uint32_t delegated_host_id;
121
122   /**
123    * The slave host
124    */
125   uint32_t slave_host_id;
126
127 };
128
129
130 /**
131  * Structure of a queue entry in LCFContext request queue
132  */
133 struct LCFContextQueue
134 {
135   /**
136    * The LCFContext
137    */
138   struct LCFContext *lcf;
139
140   /**
141    * Head prt for DLL
142    */
143   struct LCFContextQueue *next;
144
145   /**
146    * Tail ptr for DLL
147    */
148   struct LCFContextQueue *prev;
149 };
150
151 struct NeighbourConnectNotification
152 {
153   struct NeighbourConnectNotification *next;
154   struct NeighbourConnectNotification *prev;
155   struct Neighbour *n;
156   GST_NeigbourConnectNotifyCallback cb;
157   void *cb_cls;
158 };
159   
160 /**
161  * A connected controller which is not our child
162  */
163 struct Neighbour
164 {
165   /**
166    * The controller handle
167    */
168   struct GNUNET_TESTBED_Controller *controller;
169   
170   /**
171    * Operation handle for opening a lateral connection to another controller.
172    * Will be NULL if the slave controller is started by this controller
173    */
174   struct GNUNET_TESTBED_Operation *conn_op;
175
176   struct NeighbourConnectNotification *nl_head;
177
178   struct NeighbourConnectNotification *nl_tail;
179
180   GNUNET_SCHEDULER_TaskIdentifier notify_task;
181
182   unsigned int reference_cnt;
183
184   unsigned int inactive;
185
186   
187   /**
188    * The id of the host this controller is running on
189    */
190   uint32_t host_id;
191   
192 };
193
194 static struct Neighbour **neighbour_list;
195 static unsigned int neighbour_list_size;
196
197 struct NeighbourConnectCtxt
198 {
199   struct NeighbourConnectCtxt *next;
200   struct NeighbourConnectCtxt *prev;
201   struct Neighbour *n;
202   struct GNUNET_SERVER_Client *client;
203   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
204   struct NeighbourConnectNotification *nh;
205   uint64_t op_id;
206 };
207
208 struct NeighbourConnectCtxt *ncc_head;
209 struct NeighbourConnectCtxt *ncc_tail;
210
211 /**
212  * A list of directly linked neighbours
213  */
214 struct Slave **GST_slave_list;
215
216 /**
217  * The size of directly linked neighbours list
218  */
219 unsigned int GST_slave_list_size;
220
221 /**
222  * A list of routes
223  */
224 static struct Route **route_list;
225
226 /**
227  * The head for the LCF queue
228  */
229 static struct LCFContextQueue *lcfq_head;
230
231 /**
232  * The tail for the LCF queue
233  */
234 static struct LCFContextQueue *lcfq_tail;
235
236 /**
237  * The lcf_task handle
238  */
239 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
240
241 /**
242  * The size of the route list
243  */
244 static unsigned int route_list_size;
245
246
247 /**
248  * Adds a slave to the slave array
249  *
250  * @param slave the slave controller to add
251  */
252 static void
253 slave_list_add (struct Slave *slave)
254 {
255   if (slave->host_id >= GST_slave_list_size)
256     GST_array_grow_large_enough (GST_slave_list, GST_slave_list_size,
257                                  slave->host_id);
258   GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
259   GST_slave_list[slave->host_id] = slave;
260 }
261
262
263 /**
264  * Adds a route to the route list
265  *
266  * @param route the route to add
267  */
268 static void
269 route_list_add (struct Route *route)
270 {
271   if (route->dest >= route_list_size)
272     GST_array_grow_large_enough (route_list, route_list_size, route->dest);
273   GNUNET_assert (NULL == route_list[route->dest]);
274   route_list[route->dest] = route;
275 }
276
277 static void
278 neighbour_list_add (struct Neighbour *n)
279 {
280   if (n->host_id >= neighbour_list_size)
281     GST_array_grow_large_enough (neighbour_list, neighbour_list_size, n->host_id);
282   GNUNET_assert (NULL == neighbour_list[n->host_id]);
283   neighbour_list[n->host_id] = n;
284 }
285
286
287 /**
288  * Cleans up the route list
289  */
290 void
291 GST_route_list_clear ()
292 {
293   unsigned int id;
294   
295   for (id = 0; id < route_list_size; id++)
296     if (NULL != route_list[id])
297       GNUNET_free (route_list[id]);
298   GNUNET_free_non_null (route_list);
299   route_list = NULL;
300 }
301
302
303 /**
304  * Iterator for freeing hash map entries in a slave's reghost_map
305  *
306  * @param cls handle to the slave
307  * @param key current key code
308  * @param value value in the hash map
309  * @return GNUNET_YES if we should continue to
310  *         iterate,
311  *         GNUNET_NO if not.
312  */
313 static int
314 reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key,
315                        void *value)
316 {
317   struct Slave *slave = cls;
318   struct RegisteredHostContext *rhc = value;
319   struct ForwardedOverlayConnectContext *focc;
320
321   GNUNET_assert (GNUNET_YES ==
322                  GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
323                                                        value));
324   while (NULL != (focc = rhc->focc_dll_head))
325   {
326     GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
327     GST_cleanup_focc (focc);
328   }
329   GNUNET_free (value);
330   return GNUNET_YES;
331 }
332
333
334 /**
335  * Cleans up the slave list
336  */
337 void
338 GST_slave_list_clear ()
339 {
340   unsigned int id;
341   struct HostRegistration *hr_entry;
342
343   for (id = 0; id < GST_slave_list_size; id++)
344     if (NULL != GST_slave_list[id])
345     {
346       while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head))
347       {
348         GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head,
349                                      GST_slave_list[id]->hr_dll_tail, hr_entry);
350         GNUNET_free (hr_entry);
351       }
352       if (NULL != GST_slave_list[id]->rhandle)
353         GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle);
354       (void)
355           GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list
356                                                  [id]->reghost_map,
357                                                  reghost_free_iterator,
358                                                  GST_slave_list[id]);
359       GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map);
360       if (NULL != GST_slave_list[id]->controller)
361         GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller);
362       if (NULL != GST_slave_list[id]->controller_proc)
363         GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc);
364       GNUNET_free (GST_slave_list[id]);
365     }
366   GNUNET_free_non_null (GST_slave_list);
367   GST_slave_list = NULL;
368 }
369
370
371 /**
372  * Finds the route with directly connected host as destination through which
373  * the destination host can be reached
374  *
375  * @param host_id the id of the destination host
376  * @return the route with directly connected destination host; NULL if no route
377  *           is found
378  */
379 struct Route *
380 GST_find_dest_route (uint32_t host_id)
381 {
382   struct Route *route;
383
384   if (route_list_size <= host_id)
385     return NULL;
386   while (NULL != (route = route_list[host_id]))
387   {
388     if (route->thru == GST_context->host_id)
389       break;
390     host_id = route->thru;
391   }
392   return route;
393 }
394
395
396 /**
397  * Function to send a failure reponse for controller link operation
398  *
399  * @param client the client to send the message to
400  * @param operation_id the operation ID of the controller link request
401  * @param cfg the configuration with which the delegated controller is started.
402  *          Can be NULL if the delegated controller is not started but just
403  *          linked to.
404  * @param emsg set to an error message explaining why the controller link
405  *          failed.  Setting this to NULL signifies success.  !This should be
406  *          NULL if cfg is set!
407  */
408 static void
409 send_controller_link_response (struct GNUNET_SERVER_Client *client,
410                                uint64_t operation_id,
411                                const struct GNUNET_CONFIGURATION_Handle
412                                *cfg,
413                                const char *emsg)
414 {
415   struct GNUNET_TESTBED_ControllerLinkResponse *msg;
416   char *xconfig;
417   size_t config_size;
418   size_t xconfig_size;  
419   uint16_t msize;
420
421   GNUNET_assert ((NULL == cfg) || (NULL == emsg));
422   xconfig = NULL;
423   xconfig_size = 0;
424   config_size = 0;
425   msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse);
426   if (NULL != cfg)
427   {
428     xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
429                                             &config_size,
430                                             &xconfig_size);
431     msize += xconfig_size;
432   }
433   if (NULL != emsg)
434     msize += strlen (emsg);
435   msg = GNUNET_malloc (msize);
436   msg->header.type = htons
437       (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
438   msg->header.size = htons (msize);
439   if (NULL == emsg)
440     msg->success = htons (GNUNET_YES);
441   msg->operation_id = GNUNET_htonll (operation_id);
442   msg->config_size = htons ((uint16_t) config_size);
443   if (NULL != xconfig)
444   {
445     memcpy (&msg[1], xconfig, xconfig_size);
446     GNUNET_free (xconfig);
447   }
448   if (NULL != emsg)
449     memcpy (&msg[1], emsg, strlen (emsg));
450   GST_queue_message (client, &msg->header);
451 }
452
453
454 /**
455  * The  Link Controller forwarding task
456  *
457  * @param cls the LCFContext
458  * @param tc the Task context from scheduler
459  */
460 static void
461 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
462
463
464 /**
465  * Completion callback for host registrations while forwarding Link Controller messages
466  *
467  * @param cls the LCFContext
468  * @param emsg the error message; NULL if host registration is successful
469  */
470 static void
471 lcf_proc_cc (void *cls, const char *emsg)
472 {
473   struct LCFContext *lcf = cls;
474
475   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
476   switch (lcf->state)
477   {
478   case INIT:
479     if (NULL != emsg)
480       goto registration_error;
481     lcf->state = DELEGATED_HOST_REGISTERED;
482     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
483     break;
484   case DELEGATED_HOST_REGISTERED:
485     if (NULL != emsg)
486       goto registration_error;
487     lcf->state = SLAVE_HOST_REGISTERED;
488     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
489     break;
490   default:
491     GNUNET_assert (0);          /* Shouldn't reach here */
492   }
493   return;
494
495 registration_error:
496   LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
497        emsg);
498   lcf->state = FINISHED;
499   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
500 }
501
502
503 /**
504  * The  Link Controller forwarding task
505  *
506  * @param cls the LCFContext
507  * @param tc the Task context from scheduler
508  */
509 static void
510 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
511
512
513 /**
514  * Task to free resources when forwarded link controllers has been timedout
515  *
516  * @param cls the LCFContext
517  * @param tc the task context from scheduler
518  */
519 static void
520 lcf_forwarded_operation_timeout (void *cls,
521                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
522 {
523   struct LCFContext *lcf = cls;
524
525   lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK;
526   //  GST_forwarded_operation_timeout (lcf->fopc, tc);
527   LOG (GNUNET_ERROR_TYPE_WARNING,
528        "A forwarded controller link operation has timed out\n");
529   send_controller_link_response (lcf->client, lcf->operation_id, NULL,
530                                  "A forwarded controller link operation has "
531                                  "timed out\n");
532   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
533   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
534 }
535
536
537 /**
538  * The  Link Controller forwarding task
539  *
540  * @param cls the LCFContext
541  * @param tc the Task context from scheduler
542  */
543 static void
544 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
545 {
546   struct LCFContext *lcf = cls;
547   struct LCFContextQueue *lcfq;
548
549   lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
550   switch (lcf->state)
551   {
552   case INIT:
553     if (GNUNET_NO ==
554         GNUNET_TESTBED_is_host_registered_ (GST_host_list
555                                             [lcf->delegated_host_id],
556                                             lcf->gateway->controller))
557     {
558       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
559                                    GST_host_list[lcf->delegated_host_id]);
560     }
561     else
562     {
563       lcf->state = DELEGATED_HOST_REGISTERED;
564       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
565     }
566     break;
567   case DELEGATED_HOST_REGISTERED:
568     if (GNUNET_NO ==
569         GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
570                                             lcf->gateway->controller))
571     {
572       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
573                                    GST_host_list[lcf->slave_host_id]);
574     }
575     else
576     {
577       lcf->state = SLAVE_HOST_REGISTERED;
578       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
579     }
580     break;
581   case SLAVE_HOST_REGISTERED:
582     lcf->op = GNUNET_TESTBED_controller_link (lcf,
583                                               lcf->gateway->controller,
584                                               GST_host_list[lcf->delegated_host_id],
585                                               GST_host_list[lcf->slave_host_id],
586                                               lcf->is_subordinate);
587     lcf->timeout_task =
588         GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout,
589                                       lcf);
590     lcf->state = FINISHED;
591     break;
592   case FINISHED:
593     lcfq = lcfq_head;
594     GNUNET_assert (lcfq->lcf == lcf);
595     GNUNET_SERVER_client_drop (lcf->client);
596     GNUNET_TESTBED_operation_done (lcf->op);
597     GNUNET_free (lcf);
598     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
599     GNUNET_free (lcfq);
600     if (NULL != lcfq_head)
601       lcf_proc_task_id =
602           GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
603   }
604 }
605
606
607 /**
608  * Callback for event from slave controllers
609  *
610  * @param cls NULL
611  * @param event information about the event
612  */
613 static void
614 slave_event_callback (void *cls,
615                       const struct GNUNET_TESTBED_EventInformation *event)
616 {
617   struct LCFContext *lcf;
618
619   /* We currently only get here when working on RegisteredHostContexts and
620      LCFContexts */
621   GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
622   lcf = event->op_cls;
623   if (CLOSURE_TYPE_LCF == lcf->type)
624   {    
625     GNUNET_assert (lcf->op == event->op);
626     GNUNET_assert (FINISHED == lcf->state);
627     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task);
628     GNUNET_SCHEDULER_cancel (lcf->timeout_task);
629     if (NULL == event->details.operation_finished.emsg)
630       send_controller_link_response (lcf->client, lcf->operation_id,
631                                      GNUNET_TESTBED_host_get_cfg_ 
632                                      (GST_host_list[lcf->delegated_host_id]),
633                                      NULL);
634     else
635       send_controller_link_response (lcf->client, lcf->operation_id,
636                                      NULL,
637                                      event->details.operation_finished.emsg);
638     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
639     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
640     return;
641   }
642   GNUNET_assert (0);
643 }
644
645 static void
646 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
647                        int status);
648
649 /**
650  * Callback to signal successfull startup of the controller process
651  *
652  * @param cls the handle to the slave whose status is to be found here
653  * @param cfg the configuration with which the controller has been started;
654  *          NULL if status is not GNUNET_OK
655  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
656  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
657  */
658 static void
659 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
660                        int status)
661 {
662   struct Slave *slave = cls;
663   struct LinkControllersContext *lcc;
664
665   lcc = slave->lcc;
666   if (GNUNET_SYSERR == status)
667   {
668     slave->controller_proc = NULL;
669     GST_slave_list[slave->host_id] = NULL;
670     GNUNET_free (slave);
671     slave = NULL;
672     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
673     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
674     goto clean_lcc;
675   }
676   slave->controller =
677       GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
678                                          EVENT_MASK, &slave_event_callback,
679                                          slave);
680   if (NULL != slave->controller)
681   {
682     send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
683   }
684   else
685   {
686     send_controller_link_response (lcc->client, lcc->operation_id, NULL,
687                                    "Could not connect to delegated controller");
688     GNUNET_TESTBED_controller_stop (slave->controller_proc);
689     GST_slave_list[slave->host_id] = NULL;
690     GNUNET_free (slave);
691     slave = NULL;
692   }
693
694 clean_lcc:
695   if (NULL != lcc)
696   {
697     if (NULL != lcc->client)
698     {
699       GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
700       GNUNET_SERVER_client_drop (lcc->client);
701       lcc->client = NULL;
702     }
703     GNUNET_free (lcc);
704   }
705   if (NULL != slave)
706     slave->lcc = NULL;
707 }
708
709 static void
710 neighbour_connect_notify_task (void *cls, 
711                                const struct GNUNET_SCHEDULER_TaskContext *tc);
712
713 static void
714 trigger_notifications (struct Neighbour *n)
715 {
716   GNUNET_assert (NULL != n->conn_op);
717   if (NULL == n->nl_head)
718     return;
719   if (NULL == n->controller)
720     return;
721   if (GNUNET_SCHEDULER_NO_TASK != n->notify_task)
722     return;  
723   if (1 == n->inactive)
724   {
725     GNUNET_assert (0 == n->reference_cnt);
726     GNUNET_TESTBED_operation_activate_ (n->conn_op);
727     n->inactive = 0;
728   }
729   n->reference_cnt++;
730   n->notify_task = 
731       GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n);
732 }
733
734 static void
735 neighbour_connect_notify_task (void *cls, 
736                                const struct GNUNET_SCHEDULER_TaskContext *tc)
737 {
738   struct Neighbour *n = cls;
739   struct NeighbourConnectNotification *h;
740
741   GNUNET_assert (NULL != (h = n->nl_head));
742   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->notify_task);  
743   n->notify_task = GNUNET_SCHEDULER_NO_TASK;
744   GNUNET_assert (NULL != n->controller);
745   GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);  
746   trigger_notifications (n);
747   h->cb (h->cb_cls, n->controller);
748   GNUNET_free (h);
749 }
750
751 static void
752 opstart_neighbour_conn (void *cls)
753 {
754   struct Neighbour *n = cls;
755   
756   GNUNET_assert (NULL != n->conn_op);
757   GNUNET_assert (NULL == n->controller);
758   LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
759   n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
760                                                      EVENT_MASK,
761                                                      &slave_event_callback,
762                                                      NULL);
763   trigger_notifications (n);
764 }
765
766 static void
767 oprelease_neighbour_conn (void *cls)
768 {
769    struct Neighbour *n = cls;
770
771    GNUNET_assert (0 == n->reference_cnt);
772    GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->notify_task);
773    GNUNET_assert (NULL == n->nl_head);
774    if (NULL != n->controller)
775    {
776      LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
777      GNUNET_TESTBED_controller_disconnect (n->controller);
778      n->controller = NULL;
779    }
780    n->conn_op = NULL;
781    n->inactive = 0;
782 }
783
784 struct NeighbourConnectNotification *
785 GST_neighbour_get_connection (struct Neighbour *n,
786                               GST_NeigbourConnectNotifyCallback cb,
787                               void *cb_cls)
788 {
789   struct NeighbourConnectNotification *h;
790
791   GNUNET_assert (NULL != cb);
792   LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
793              n->host_id);
794   h = GNUNET_malloc (sizeof (struct NeighbourConnectNotification));
795   h->n = n;
796   h->cb  = cb;
797   h->cb_cls = cb_cls;
798   GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
799   if (NULL == n->conn_op)
800   {
801     GNUNET_assert (NULL == n->controller);
802     n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
803                                                    &oprelease_neighbour_conn);
804     GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
805     GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
806     return h;
807   }
808   trigger_notifications (n);
809   return h;
810 }
811
812 void
813 GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
814 {
815   struct Neighbour *n;
816   int cleanup_task;
817   
818   n = h->n;
819   cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
820   GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
821   GNUNET_free (h);
822   if (GNUNET_NO == cleanup_task)
823     return;
824   if (GNUNET_SCHEDULER_NO_TASK == n->notify_task)
825     return;
826   GNUNET_assert (0 < n->reference_cnt);
827   n->reference_cnt--;
828   GNUNET_SCHEDULER_cancel (n->notify_task);
829   n->notify_task = GNUNET_SCHEDULER_NO_TASK;
830   if (NULL == n->nl_head)
831   {
832     if ( (0 == n->reference_cnt) && (0 == n->inactive) )
833     {
834       n->inactive = 1;
835       GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
836     }
837     return;
838   }
839   trigger_notifications (n);
840 }
841
842 void
843 GST_neighbour_release_connection (struct Neighbour *n)
844 {
845   GNUNET_assert (0 == n->inactive);
846   GNUNET_assert (0 < n->reference_cnt);
847   n->reference_cnt--;
848   if (0 == n->reference_cnt)
849   {
850     n->inactive = 1;
851     GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
852   }
853 }
854
855 static void
856 cleanup_ncc (struct NeighbourConnectCtxt *ncc)
857 {
858   if (NULL != ncc->nh)
859     GST_neighbour_get_connection_cancel (ncc->nh);
860   if (GNUNET_SCHEDULER_NO_TASK != ncc->timeout_task)
861     GNUNET_SCHEDULER_cancel (ncc->timeout_task);
862   GNUNET_SERVER_client_drop (ncc->client);
863   GNUNET_CONTAINER_DLL_remove (ncc_head, ncc_tail, ncc);
864   GNUNET_free (ncc);
865 }
866
867 void
868 GST_neighbour_list_clean()
869 {
870   struct Neighbour *n;
871   unsigned int id;
872
873   for (id = 0; id < neighbour_list_size; id++)
874   {
875     if (NULL == (n = neighbour_list[id]))
876       continue;
877     if (NULL != n->conn_op)
878       GNUNET_TESTBED_operation_release_ (n->conn_op);
879     GNUNET_free (n);
880     neighbour_list[id] = NULL;
881   }
882   GNUNET_free_non_null (neighbour_list);
883 }
884
885 struct Neighbour *
886 GST_get_neighbour (uint32_t id)
887 {
888   if (neighbour_list_size <= id)
889     return NULL;
890   else
891     return neighbour_list[id];
892 }
893
894 void
895 GST_free_nccq ()
896 {
897   while (NULL != ncc_head)
898     cleanup_ncc (ncc_head);
899 }
900
901 static void
902 timeout_neighbour_connect (void *cls, 
903                            const struct GNUNET_SCHEDULER_TaskContext *tc)
904 {
905  struct NeighbourConnectCtxt *ncc = cls;
906
907  ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
908  send_controller_link_response (ncc->client, ncc->op_id, NULL,
909                                 "Could not connect to delegated controller");
910  cleanup_ncc (ncc);
911 }
912
913 static void
914 neighbour_connect_cb (void *cls, struct GNUNET_TESTBED_Controller *c)
915 {
916   struct NeighbourConnectCtxt *ncc = cls;
917
918   GNUNET_SCHEDULER_cancel (ncc->timeout_task);
919   ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
920   ncc->nh = NULL;
921   GST_neighbour_release_connection (ncc->n);
922   send_controller_link_response (ncc->client, ncc->op_id, NULL, NULL);
923   cleanup_ncc (ncc);
924 }
925
926 struct Neighbour *
927 GST_create_neighbour (struct GNUNET_TESTBED_Host *host)
928 {
929   struct Neighbour *n;
930
931   n = GNUNET_malloc (sizeof (struct Neighbour));
932   n->host_id = GNUNET_TESTBED_host_get_id_ (host);
933   neighbour_list_add (n);   /* just add; connect on-demand */
934   return n;
935 }
936
937
938 /**
939  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
940  *
941  * @param cls NULL
942  * @param client identification of the client
943  * @param message the actual message
944  */
945 void
946 GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
947                              const struct GNUNET_MessageHeader *message)
948 {
949   const struct GNUNET_TESTBED_ControllerLinkRequest *msg;
950   struct LCFContextQueue *lcfq;
951   struct Route *route;
952   struct Route *new_route;
953   uint64_t op_id;
954   uint32_t delegated_host_id;
955   uint32_t slave_host_id;
956
957   if (NULL == GST_context)
958   {
959     GNUNET_break (0);
960     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
961     return;
962   }
963   msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message;
964   delegated_host_id = ntohl (msg->delegated_host_id);
965   if (delegated_host_id == GST_context->host_id)
966   {
967     GNUNET_break (0);
968     LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
969     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
970     return;
971   }
972   if ((delegated_host_id >= GST_host_list_size) ||
973       (NULL == GST_host_list[delegated_host_id]))
974   {
975     LOG (GNUNET_ERROR_TYPE_WARNING,
976          "Delegated host %u not registered with us\n", delegated_host_id);
977     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
978     return;
979   }
980   slave_host_id = ntohl (msg->slave_host_id);
981   if ((slave_host_id >= GST_host_list_size) ||
982       (NULL == GST_host_list[slave_host_id]))
983   {
984     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
985          slave_host_id);
986     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
987     return;
988   }
989   if (slave_host_id == delegated_host_id)
990   {
991     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
992     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
993     return;
994   }
995   op_id = GNUNET_ntohll (msg->operation_id);
996   if (slave_host_id == GST_context->host_id)    /* Link from us */
997   {
998     struct Slave *slave;
999     struct LinkControllersContext *lcc;
1000
1001     
1002     if (1 != msg->is_subordinate)
1003     {
1004       struct Neighbour *n;
1005       struct NeighbourConnectCtxt *ncc;
1006
1007       if ((delegated_host_id < neighbour_list_size) &&
1008         (NULL != neighbour_list[delegated_host_id]))
1009       {
1010         GNUNET_break (0);
1011         GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1012         return;
1013       }
1014       LOG_DEBUG ("Received request to establish a link to host %u\n",
1015                  delegated_host_id);
1016       n = GST_create_neighbour (GST_host_list[delegated_host_id]);
1017       ncc = GNUNET_malloc (sizeof (struct NeighbourConnectCtxt));
1018       ncc->n = n;
1019       ncc->op_id = op_id;
1020       ncc->client = client;
1021       GNUNET_SERVER_client_keep (client);      
1022       ncc->nh = GST_neighbour_get_connection (n, neighbour_connect_cb, ncc);
1023       ncc->timeout_task = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1024                                                         &timeout_neighbour_connect,
1025                                                         ncc);
1026       GNUNET_CONTAINER_DLL_insert_tail (ncc_head, ncc_tail, ncc);      
1027       GNUNET_SERVER_receive_done (client, GNUNET_OK);
1028       return;
1029     }
1030     if ((delegated_host_id < GST_slave_list_size) &&
1031         (NULL != GST_slave_list[delegated_host_id]))
1032     {
1033       GNUNET_break (0);
1034       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1035       return;
1036     }
1037     LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1038                delegated_host_id);
1039     slave = GNUNET_malloc (sizeof (struct Slave));
1040     slave->host_id = delegated_host_id;
1041     slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
1042     slave_list_add (slave);
1043     lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
1044     lcc->operation_id = op_id;
1045     GNUNET_SERVER_client_keep (client);
1046     lcc->client = client;
1047     slave->lcc = lcc;
1048     slave->controller_proc =
1049         GNUNET_TESTBED_controller_start (GST_context->master_ip,
1050                                          GST_host_list[slave->host_id],
1051                                          &slave_status_callback, slave);
1052     new_route = GNUNET_malloc (sizeof (struct Route));
1053     new_route->dest = delegated_host_id;
1054     new_route->thru = GST_context->host_id;
1055     route_list_add (new_route);
1056     return;
1057   }
1058
1059   /* Route the request */
1060   if (slave_host_id >= route_list_size)
1061   {
1062     LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1063     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1064     return;
1065   }
1066   lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
1067   lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
1068   lcfq->lcf->type = CLOSURE_TYPE_LCF;
1069   lcfq->lcf->delegated_host_id = delegated_host_id;
1070   lcfq->lcf->slave_host_id = slave_host_id;
1071   route = GST_find_dest_route (slave_host_id);
1072   GNUNET_assert (NULL != route);        /* because we add routes carefully */
1073   GNUNET_assert (route->dest < GST_slave_list_size);
1074   GNUNET_assert (NULL != GST_slave_list[route->dest]);
1075   lcfq->lcf->is_subordinate = msg->is_subordinate;
1076   lcfq->lcf->state = INIT;
1077   lcfq->lcf->operation_id = op_id;
1078   lcfq->lcf->gateway = GST_slave_list[route->dest];
1079   GNUNET_SERVER_client_keep (client);
1080   lcfq->lcf->client = client;
1081   if (NULL == lcfq_head)
1082   {
1083     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1084     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1085     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
1086   }
1087   else
1088     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1089   /* FIXME: Adding a new route should happen after the controllers are linked
1090    * successfully */
1091   if (1 != msg->is_subordinate)
1092   {
1093     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1094     return;
1095   }
1096   if ((delegated_host_id < route_list_size) &&
1097       (NULL != route_list[delegated_host_id]))
1098   {
1099     GNUNET_break_op (0);        /* Are you trying to link delegated host twice
1100                                  * with is subordinate flag set to GNUNET_YES? */
1101     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1102     return;
1103   }
1104   new_route = GNUNET_malloc (sizeof (struct Route));
1105   new_route->dest = delegated_host_id;
1106   new_route->thru = route->dest;
1107   route_list_add (new_route);
1108   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1109 }
1110
1111
1112 /**
1113  * Cleans up the queue used for forwarding link controllers requests
1114  */
1115 void
1116 GST_free_lcfq ()
1117 {
1118   struct LCFContextQueue *lcfq;
1119   
1120   if (NULL != lcfq_head)
1121   {
1122     if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
1123     {
1124       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1125       lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1126     }
1127   }
1128   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1129   for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
1130   {
1131     GNUNET_SERVER_client_drop (lcfq->lcf->client);
1132     GNUNET_free (lcfq->lcf);
1133     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
1134     GNUNET_free (lcfq);
1135   }
1136 }