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