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