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