6209bf248270f46158dc2caac4399d8820ca3db5
[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   if (NULL != rhc->sub_op)
330     GNUNET_TESTBED_operation_done (rhc->sub_op);
331   if (NULL != rhc->client)
332     GNUNET_SERVER_client_drop (rhc->client);
333   GNUNET_free (value);
334   return GNUNET_YES;
335 }
336
337
338 /**
339  * Cleans up the slave list
340  */
341 void
342 GST_slave_list_clear ()
343 {
344   unsigned int id;
345   struct HostRegistration *hr_entry;
346
347   for (id = 0; id < GST_slave_list_size; id++)
348     if (NULL != GST_slave_list[id])
349     {
350       while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head))
351       {
352         GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head,
353                                      GST_slave_list[id]->hr_dll_tail, hr_entry);
354         GNUNET_free (hr_entry);
355       }
356       if (NULL != GST_slave_list[id]->rhandle)
357         GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle);
358       (void)
359           GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list
360                                                  [id]->reghost_map,
361                                                  reghost_free_iterator,
362                                                  GST_slave_list[id]);
363       GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map);
364       if (NULL != GST_slave_list[id]->controller)
365         GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller);
366       if (NULL != GST_slave_list[id]->controller_proc)
367         GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc);
368       GNUNET_free (GST_slave_list[id]);
369     }
370   GNUNET_free_non_null (GST_slave_list);
371   GST_slave_list = NULL;
372 }
373
374
375 /**
376  * Finds the route with directly connected host as destination through which
377  * the destination host can be reached
378  *
379  * @param host_id the id of the destination host
380  * @return the route with directly connected destination host; NULL if no route
381  *           is found
382  */
383 struct Route *
384 GST_find_dest_route (uint32_t host_id)
385 {
386   struct Route *route;
387
388   if (route_list_size <= host_id)
389     return NULL;
390   while (NULL != (route = route_list[host_id]))
391   {
392     if (route->thru == GST_context->host_id)
393       break;
394     host_id = route->thru;
395   }
396   return route;
397 }
398
399
400 /**
401  * Function to send a failure reponse for controller link operation
402  *
403  * @param client the client to send the message to
404  * @param operation_id the operation ID of the controller link request
405  * @param cfg the configuration with which the delegated controller is started.
406  *          Can be NULL if the delegated controller is not started but just
407  *          linked to.
408  * @param emsg set to an error message explaining why the controller link
409  *          failed.  Setting this to NULL signifies success.  !This should be
410  *          NULL if cfg is set!
411  */
412 static void
413 send_controller_link_response (struct GNUNET_SERVER_Client *client,
414                                uint64_t operation_id,
415                                const struct GNUNET_CONFIGURATION_Handle
416                                *cfg,
417                                const char *emsg)
418 {
419   struct GNUNET_TESTBED_ControllerLinkResponse *msg;
420   char *xconfig;
421   size_t config_size;
422   size_t xconfig_size;  
423   uint16_t msize;
424
425   GNUNET_assert ((NULL == cfg) || (NULL == emsg));
426   xconfig = NULL;
427   xconfig_size = 0;
428   config_size = 0;
429   msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse);
430   if (NULL != cfg)
431   {
432     xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
433                                             &config_size,
434                                             &xconfig_size);
435     msize += xconfig_size;
436   }
437   if (NULL != emsg)
438     msize += strlen (emsg);
439   msg = GNUNET_malloc (msize);
440   msg->header.type = htons
441       (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
442   msg->header.size = htons (msize);
443   if (NULL == emsg)
444     msg->success = htons (GNUNET_YES);
445   msg->operation_id = GNUNET_htonll (operation_id);
446   msg->config_size = htons ((uint16_t) config_size);
447   if (NULL != xconfig)
448   {
449     memcpy (&msg[1], xconfig, xconfig_size);
450     GNUNET_free (xconfig);
451   }
452   if (NULL != emsg)
453     memcpy (&msg[1], emsg, strlen (emsg));
454   GST_queue_message (client, &msg->header);
455 }
456
457
458 /**
459  * The  Link Controller forwarding task
460  *
461  * @param cls the LCFContext
462  * @param tc the Task context from scheduler
463  */
464 static void
465 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
466
467
468 /**
469  * Completion callback for host registrations while forwarding Link Controller messages
470  *
471  * @param cls the LCFContext
472  * @param emsg the error message; NULL if host registration is successful
473  */
474 static void
475 lcf_proc_cc (void *cls, const char *emsg)
476 {
477   struct LCFContext *lcf = cls;
478
479   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
480   switch (lcf->state)
481   {
482   case INIT:
483     if (NULL != emsg)
484       goto registration_error;
485     lcf->state = DELEGATED_HOST_REGISTERED;
486     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
487     break;
488   case DELEGATED_HOST_REGISTERED:
489     if (NULL != emsg)
490       goto registration_error;
491     lcf->state = SLAVE_HOST_REGISTERED;
492     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
493     break;
494   default:
495     GNUNET_assert (0);          /* Shouldn't reach here */
496   }
497   return;
498
499 registration_error:
500   LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
501        emsg);
502   lcf->state = FINISHED;
503   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
504 }
505
506
507 /**
508  * The  Link Controller forwarding task
509  *
510  * @param cls the LCFContext
511  * @param tc the Task context from scheduler
512  */
513 static void
514 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
515
516
517 /**
518  * Task to free resources when forwarded link controllers has been timedout
519  *
520  * @param cls the LCFContext
521  * @param tc the task context from scheduler
522  */
523 static void
524 lcf_forwarded_operation_timeout (void *cls,
525                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
526 {
527   struct LCFContext *lcf = cls;
528
529   lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK;
530   //  GST_forwarded_operation_timeout (lcf->fopc, tc);
531   LOG (GNUNET_ERROR_TYPE_WARNING,
532        "A forwarded controller link operation has timed out\n");
533   send_controller_link_response (lcf->client, lcf->operation_id, NULL,
534                                  "A forwarded controller link operation has "
535                                  "timed out\n");
536   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
537   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
538 }
539
540
541 /**
542  * The  Link Controller forwarding task
543  *
544  * @param cls the LCFContext
545  * @param tc the Task context from scheduler
546  */
547 static void
548 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
549 {
550   struct LCFContext *lcf = cls;
551   struct LCFContextQueue *lcfq;
552
553   lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
554   switch (lcf->state)
555   {
556   case INIT:
557     if (GNUNET_NO ==
558         GNUNET_TESTBED_is_host_registered_ (GST_host_list
559                                             [lcf->delegated_host_id],
560                                             lcf->gateway->controller))
561     {
562       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
563                                    GST_host_list[lcf->delegated_host_id]);
564     }
565     else
566     {
567       lcf->state = DELEGATED_HOST_REGISTERED;
568       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
569     }
570     break;
571   case DELEGATED_HOST_REGISTERED:
572     if (GNUNET_NO ==
573         GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
574                                             lcf->gateway->controller))
575     {
576       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
577                                    GST_host_list[lcf->slave_host_id]);
578     }
579     else
580     {
581       lcf->state = SLAVE_HOST_REGISTERED;
582       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
583     }
584     break;
585   case SLAVE_HOST_REGISTERED:
586     lcf->op = GNUNET_TESTBED_controller_link (lcf,
587                                               lcf->gateway->controller,
588                                               GST_host_list[lcf->delegated_host_id],
589                                               GST_host_list[lcf->slave_host_id],
590                                               lcf->is_subordinate);
591     lcf->timeout_task =
592         GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout,
593                                       lcf);
594     lcf->state = FINISHED;
595     break;
596   case FINISHED:
597     lcfq = lcfq_head;
598     GNUNET_assert (lcfq->lcf == lcf);
599     GNUNET_SERVER_client_drop (lcf->client);
600     GNUNET_TESTBED_operation_done (lcf->op);
601     GNUNET_free (lcf);
602     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
603     GNUNET_free (lcfq);
604     if (NULL != lcfq_head)
605       lcf_proc_task_id =
606           GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
607   }
608 }
609
610
611 /**
612  * Callback for event from slave controllers
613  *
614  * @param cls NULL
615  * @param event information about the event
616  */
617 static void
618 slave_event_callback (void *cls,
619                       const struct GNUNET_TESTBED_EventInformation *event)
620 {
621   struct RegisteredHostContext *rhc;
622   struct LCFContext *lcf;
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       old_op = rhc->sub_op;
636       rhc->state = RHC_LINK;
637       rhc->sub_op =
638           GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller,
639                                           rhc->reg_host, rhc->host, GNUNET_NO);
640       GNUNET_TESTBED_operation_done (old_op);
641       break;
642     case RHC_LINK:
643       LOG_DEBUG ("OL: Linking controllers successfull\n");
644       GNUNET_TESTBED_operation_done (rhc->sub_op);
645       rhc->sub_op = NULL;
646       rhc->state = RHC_OL_CONNECT;
647       GST_process_next_focc (rhc);
648       break;
649     default:
650       GNUNET_assert (0);
651     }
652     return;
653   }
654   lcf = event->op_cls;
655   if (CLOSURE_TYPE_LCF == lcf->type)
656   {    
657     GNUNET_assert (lcf->op == event->op);
658     GNUNET_assert (FINISHED == lcf->state);
659     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task);
660     GNUNET_SCHEDULER_cancel (lcf->timeout_task);
661     if (NULL == event->details.operation_finished.emsg)
662       send_controller_link_response (lcf->client, lcf->operation_id,
663                                      GNUNET_TESTBED_host_get_cfg_ 
664                                      (GST_host_list[lcf->delegated_host_id]),
665                                      NULL);
666     else
667       send_controller_link_response (lcf->client, lcf->operation_id,
668                                      NULL,
669                                      event->details.operation_finished.emsg);
670     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
671     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
672     return;
673   }
674   GNUNET_assert (0);
675 }
676
677 static void
678 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
679                        int status);
680
681 /**
682  * Callback to signal successfull startup of the controller process
683  *
684  * @param cls the handle to the slave whose status is to be found here
685  * @param cfg the configuration with which the controller has been started;
686  *          NULL if status is not GNUNET_OK
687  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
688  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
689  */
690 static void
691 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
692                        int status)
693 {
694   struct Slave *slave = cls;
695   struct LinkControllersContext *lcc;
696
697   lcc = slave->lcc;
698   if (GNUNET_SYSERR == status)
699   {
700     slave->controller_proc = NULL;
701     GST_slave_list[slave->host_id] = NULL;
702     GNUNET_free (slave);
703     slave = NULL;
704     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
705     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
706     goto clean_lcc;
707   }
708   slave->controller =
709       GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
710                                          EVENT_MASK, &slave_event_callback,
711                                          slave);
712   if (NULL != slave->controller)
713   {
714     send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
715   }
716   else
717   {
718     send_controller_link_response (lcc->client, lcc->operation_id, NULL,
719                                    "Could not connect to delegated controller");
720     GNUNET_TESTBED_controller_stop (slave->controller_proc);
721     GST_slave_list[slave->host_id] = NULL;
722     GNUNET_free (slave);
723     slave = NULL;
724   }
725
726 clean_lcc:
727   if (NULL != lcc)
728   {
729     if (NULL != lcc->client)
730     {
731       GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
732       GNUNET_SERVER_client_drop (lcc->client);
733       lcc->client = NULL;
734     }
735     GNUNET_free (lcc);
736   }
737   if (NULL != slave)
738     slave->lcc = NULL;
739 }
740
741 static void
742 neighbour_connect_notify_task (void *cls, 
743                                const struct GNUNET_SCHEDULER_TaskContext *tc);
744
745 static void
746 trigger_notifications (struct Neighbour *n)
747 {
748   GNUNET_assert (NULL != n->conn_op);
749   if (NULL == n->nl_head)
750     return;
751   if (NULL == n->controller)
752     return;
753   if (GNUNET_SCHEDULER_NO_TASK != n->notify_task)
754     return;  
755   if (1 == n->inactive)
756   {
757     GNUNET_assert (0 == n->reference_cnt);
758     GNUNET_TESTBED_operation_activate_ (n->conn_op);
759     n->inactive = 0;
760   }
761   n->reference_cnt++;
762   n->notify_task = 
763       GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n);
764 }
765
766 static void
767 neighbour_connect_notify_task (void *cls, 
768                                const struct GNUNET_SCHEDULER_TaskContext *tc)
769 {
770   struct Neighbour *n = cls;
771   struct NeighbourConnectNotification *h;
772
773   GNUNET_assert (NULL != (h = n->nl_head));
774   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->notify_task);  
775   n->notify_task = GNUNET_SCHEDULER_NO_TASK;
776   GNUNET_assert (NULL != n->controller);
777   GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);  
778   trigger_notifications (n);
779   h->cb (h->cb_cls, n->controller);
780   GNUNET_free (h);
781 }
782
783 static void
784 opstart_neighbour_conn (void *cls)
785 {
786   struct Neighbour *n = cls;
787   
788   GNUNET_assert (NULL != n->conn_op);
789   GNUNET_assert (NULL == n->controller);
790   LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
791   n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
792                                                      EVENT_MASK,
793                                                      &slave_event_callback,
794                                                      NULL);
795   trigger_notifications (n);
796 }
797
798 static void
799 oprelease_neighbour_conn (void *cls)
800 {
801    struct Neighbour *n = cls;
802
803    GNUNET_assert (0 == n->reference_cnt);
804    GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->notify_task);
805    GNUNET_assert (NULL == n->nl_head);
806    if (NULL != n->controller)
807    {
808      LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
809      GNUNET_TESTBED_controller_disconnect (n->controller);
810      n->controller = NULL;
811    }
812    n->conn_op = NULL;
813    n->inactive = 0;
814 }
815
816 struct NeighbourConnectNotification *
817 GST_neighbour_get_connection (struct Neighbour *n,
818                               GST_NeigbourConnectNotifyCallback cb,
819                               void *cb_cls)
820 {
821   struct NeighbourConnectNotification *h;
822
823   GNUNET_assert (NULL != cb);
824   LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
825              n->host_id);
826   h = GNUNET_malloc (sizeof (struct NeighbourConnectNotification));
827   h->n = n;
828   h->cb  = cb;
829   h->cb_cls = cb_cls;
830   GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
831   if (NULL == n->conn_op)
832   {
833     GNUNET_assert (NULL == n->controller);
834     n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
835                                                    &oprelease_neighbour_conn);
836     GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
837     GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
838     return h;
839   }
840   trigger_notifications (n);
841   return h;
842 }
843
844 void
845 GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
846 {
847   struct Neighbour *n;
848   int cleanup_task;
849   
850   n = h->n;
851   cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
852   GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
853   GNUNET_free (h);
854   if (GNUNET_NO == cleanup_task)
855     return;
856   if (GNUNET_SCHEDULER_NO_TASK == n->notify_task)
857     return;
858   GNUNET_assert (0 < n->reference_cnt);
859   n->reference_cnt--;
860   GNUNET_SCHEDULER_cancel (n->notify_task);
861   n->notify_task = GNUNET_SCHEDULER_NO_TASK;
862   if (NULL == n->nl_head)
863   {
864     if ( (0 == n->reference_cnt) && (0 == n->inactive) )
865     {
866       n->inactive = 1;
867       GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
868     }
869     return;
870   }
871   trigger_notifications (n);
872 }
873
874 void
875 GST_neighbour_release_connection (struct Neighbour *n)
876 {
877   GNUNET_assert (0 == n->inactive);
878   GNUNET_assert (0 < n->reference_cnt);
879   n->reference_cnt--;
880   if (0 == n->reference_cnt)
881   {
882     n->inactive = 1;
883     GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
884   }
885 }
886
887 static void
888 cleanup_ncc (struct NeighbourConnectCtxt *ncc)
889 {
890   if (NULL != ncc->nh)
891     GST_neighbour_get_connection_cancel (ncc->nh);
892   if (GNUNET_SCHEDULER_NO_TASK != ncc->timeout_task)
893     GNUNET_SCHEDULER_cancel (ncc->timeout_task);
894   GNUNET_SERVER_client_drop (ncc->client);
895   GNUNET_CONTAINER_DLL_remove (ncc_head, ncc_tail, ncc);
896   GNUNET_free (ncc);
897 }
898
899 void
900 GST_neighbour_list_clean()
901 {
902   struct Neighbour *n;
903   unsigned int id;
904
905   for (id = 0; id < neighbour_list_size; id++)
906   {
907     if (NULL == (n = neighbour_list[id]))
908       continue;
909     if (NULL != n->conn_op)
910       GNUNET_TESTBED_operation_release_ (n->conn_op);
911     GNUNET_free (n);
912     neighbour_list[id] = NULL;
913   }
914   GNUNET_free_non_null (neighbour_list);
915 }
916
917 struct Neighbour *
918 GST_get_neighbour (uint32_t id)
919 {
920   if (neighbour_list_size <= id)
921     return NULL;
922   else
923     return neighbour_list[id];
924 }
925
926 void
927 GST_free_nccq ()
928 {
929   while (NULL != ncc_head)
930     cleanup_ncc (ncc_head);
931 }
932
933 static void
934 timeout_neighbour_connect (void *cls, 
935                            const struct GNUNET_SCHEDULER_TaskContext *tc)
936 {
937  struct NeighbourConnectCtxt *ncc = cls;
938
939  ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
940  send_controller_link_response (ncc->client, ncc->op_id, NULL,
941                                 "Could not connect to delegated controller");
942  cleanup_ncc (ncc);
943 }
944
945 static void
946 neighbour_connect_cb (void *cls, struct GNUNET_TESTBED_Controller *c)
947 {
948   struct NeighbourConnectCtxt *ncc = cls;
949
950   GNUNET_SCHEDULER_cancel (ncc->timeout_task);
951   ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
952   ncc->nh = NULL;
953   GST_neighbour_release_connection (ncc->n);
954   send_controller_link_response (ncc->client, ncc->op_id, NULL, NULL);
955   cleanup_ncc (ncc);
956 }
957
958 /**
959  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
960  *
961  * @param cls NULL
962  * @param client identification of the client
963  * @param message the actual message
964  */
965 void
966 GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
967                              const struct GNUNET_MessageHeader *message)
968 {
969   const struct GNUNET_TESTBED_ControllerLinkRequest *msg;
970   struct LCFContextQueue *lcfq;
971   struct Route *route;
972   struct Route *new_route;
973   uint64_t op_id;
974   uint32_t delegated_host_id;
975   uint32_t slave_host_id;
976
977   if (NULL == GST_context)
978   {
979     GNUNET_break (0);
980     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
981     return;
982   }
983   msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message;
984   delegated_host_id = ntohl (msg->delegated_host_id);
985   if (delegated_host_id == GST_context->host_id)
986   {
987     GNUNET_break (0);
988     LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
989     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
990     return;
991   }
992   if ((delegated_host_id >= GST_host_list_size) ||
993       (NULL == GST_host_list[delegated_host_id]))
994   {
995     LOG (GNUNET_ERROR_TYPE_WARNING,
996          "Delegated host %u not registered with us\n", delegated_host_id);
997     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
998     return;
999   }
1000   slave_host_id = ntohl (msg->slave_host_id);
1001   if ((slave_host_id >= GST_host_list_size) ||
1002       (NULL == GST_host_list[slave_host_id]))
1003   {
1004     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
1005          slave_host_id);
1006     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1007     return;
1008   }
1009   if (slave_host_id == delegated_host_id)
1010   {
1011     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
1012     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1013     return;
1014   }
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 }