80e96762bf7a54751345558ade88ec694f76b0d6
[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                                               NULL,
591                                               lcf->is_subordinate);
592     lcf->timeout_task =
593         GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout,
594                                       lcf);
595     lcf->state = FINISHED;
596     break;
597   case FINISHED:
598     lcfq = lcfq_head;
599     GNUNET_assert (lcfq->lcf == lcf);
600     GNUNET_SERVER_client_drop (lcf->client);
601     GNUNET_TESTBED_operation_done (lcf->op);
602     GNUNET_free (lcf);
603     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
604     GNUNET_free (lcfq);
605     if (NULL != lcfq_head)
606       lcf_proc_task_id =
607           GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
608   }
609 }
610
611
612 /**
613  * Callback for event from slave controllers
614  *
615  * @param cls NULL
616  * @param event information about the event
617  */
618 static void
619 slave_event_callback (void *cls,
620                       const struct GNUNET_TESTBED_EventInformation *event)
621 {
622   struct RegisteredHostContext *rhc;
623   struct LCFContext *lcf;
624   struct GNUNET_CONFIGURATION_Handle *cfg;
625   struct GNUNET_TESTBED_Operation *old_op;
626
627   /* We currently only get here when working on RegisteredHostContexts and
628      LCFContexts */
629   GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
630   rhc = event->op_cls;
631   if (CLOSURE_TYPE_RHC == rhc->type)
632   {
633     GNUNET_assert (rhc->sub_op == event->op);
634     switch (rhc->state)
635     {
636     case RHC_GET_CFG:
637       cfg = event->details.operation_finished.generic;
638       old_op = rhc->sub_op;
639       rhc->state = RHC_LINK;
640       rhc->sub_op =
641           GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller,
642                                           rhc->reg_host, rhc->host, cfg,
643                                           GNUNET_NO);
644       GNUNET_TESTBED_operation_done (old_op);
645       break;
646     case RHC_LINK:
647       LOG_DEBUG ("OL: Linking controllers successfull\n");
648       GNUNET_TESTBED_operation_done (rhc->sub_op);
649       rhc->sub_op = NULL;
650       rhc->state = RHC_OL_CONNECT;
651       GST_process_next_focc (rhc);
652       break;
653     default:
654       GNUNET_assert (0);
655     }
656     return;
657   }
658   lcf = event->op_cls;
659   if (CLOSURE_TYPE_LCF == lcf->type)
660   {    
661     GNUNET_assert (lcf->op == event->op);
662     GNUNET_assert (FINISHED == lcf->state);
663     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task);
664     GNUNET_SCHEDULER_cancel (lcf->timeout_task);
665     if (NULL == event->details.operation_finished.emsg)
666       send_controller_link_response (lcf->client, lcf->operation_id,
667                                      GNUNET_TESTBED_host_get_cfg_ 
668                                      (GST_host_list[lcf->delegated_host_id]),
669                                      NULL);
670     else
671       send_controller_link_response (lcf->client, lcf->operation_id,
672                                      NULL,
673                                      event->details.operation_finished.emsg);
674     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
675     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
676     return;
677   }
678   GNUNET_assert (0);
679 }
680
681 static void
682 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
683                        int status);
684
685 /**
686  * Callback to signal successfull startup of the controller process
687  *
688  * @param cls the handle to the slave whose status is to be found here
689  * @param cfg the configuration with which the controller has been started;
690  *          NULL if status is not GNUNET_OK
691  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
692  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
693  */
694 static void
695 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
696                        int status)
697 {
698   struct Slave *slave = cls;
699   struct LinkControllersContext *lcc;
700
701   lcc = slave->lcc;
702   if (GNUNET_SYSERR == status)
703   {
704     slave->controller_proc = NULL;
705     GST_slave_list[slave->host_id] = NULL;
706     GNUNET_free (slave);
707     slave = NULL;
708     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
709     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
710     goto clean_lcc;
711   }
712   slave->controller =
713       GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
714                                          EVENT_MASK, &slave_event_callback,
715                                          slave);
716   if (NULL != slave->controller)
717   {
718     send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
719   }
720   else
721   {
722     send_controller_link_response (lcc->client, lcc->operation_id, NULL,
723                                    "Could not connect to delegated controller");
724     GNUNET_TESTBED_controller_stop (slave->controller_proc);
725     GST_slave_list[slave->host_id] = NULL;
726     GNUNET_free (slave);
727     slave = NULL;
728   }
729
730 clean_lcc:
731   if (NULL != lcc)
732   {
733     if (NULL != lcc->client)
734     {
735       GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
736       GNUNET_SERVER_client_drop (lcc->client);
737       lcc->client = NULL;
738     }
739     GNUNET_free (lcc);
740   }
741   if (NULL != slave)
742     slave->lcc = NULL;
743 }
744
745 static void
746 neighbour_connect_notify_task (void *cls, 
747                                const struct GNUNET_SCHEDULER_TaskContext *tc);
748
749 static void
750 trigger_notifications (struct Neighbour *n)
751 {
752   GNUNET_assert (NULL != n->conn_op);
753   if (NULL == n->nl_head)
754     return;
755   if (NULL == n->controller)
756     return;
757   if (GNUNET_SCHEDULER_NO_TASK != n->notify_task)
758     return;  
759   if (1 == n->inactive)
760   {
761     GNUNET_assert (0 == n->reference_cnt);
762     GNUNET_TESTBED_operation_activate_ (n->conn_op);
763     n->inactive = 0;
764   }
765   n->notify_task = 
766       GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n->nl_head);
767 }
768
769 static void
770 neighbour_connect_notify_task (void *cls, 
771                                const struct GNUNET_SCHEDULER_TaskContext *tc)
772 {
773   struct NeighbourConnectNotification *h = cls;
774   struct Neighbour *n;
775
776   n = h->n;  
777   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->notify_task);  
778   n->notify_task = GNUNET_SCHEDULER_NO_TASK;
779   GNUNET_assert (NULL != n->controller);
780   GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);  
781   trigger_notifications (n);
782   n->reference_cnt++;
783   h->cb (h->cb_cls, n->controller);
784   GNUNET_free (h);
785 }
786
787 static void
788 opstart_neighbour_conn (void *cls)
789 {
790   struct Neighbour *n = cls;
791   
792   GNUNET_assert (NULL != n->conn_op);
793   GNUNET_assert (NULL == n->controller);
794   LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
795   n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
796                                                      EVENT_MASK,
797                                                      &slave_event_callback,
798                                                      NULL);
799   trigger_notifications (n);
800 }
801
802 static void
803 oprelease_neighbour_conn (void *cls)
804 {
805    struct Neighbour *n = cls;
806
807    GNUNET_assert (0 == n->reference_cnt);
808    GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->notify_task);
809    GNUNET_assert (NULL == n->nl_head);
810    if (NULL != n->controller)
811    {
812      LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
813      GNUNET_TESTBED_controller_disconnect (n->controller);
814      n->controller = NULL;
815    }
816    n->conn_op = NULL;
817    n->inactive = 0;
818 }
819
820 struct NeighbourConnectNotification *
821 GST_neighbour_get_connection (struct Neighbour *n,
822                               GST_NeigbourConnectNotifyCallback cb,
823                               void *cb_cls)
824 {
825   struct NeighbourConnectNotification *h;
826
827   GNUNET_assert (NULL != cb);
828   LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
829              n->host_id);
830   h = GNUNET_malloc (sizeof (struct NeighbourConnectNotification));
831   h->n = n;
832   h->cb  = cb;
833   h->cb_cls = cb_cls;
834   GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
835   if (NULL == n->conn_op)
836   {
837     GNUNET_assert (NULL == n->controller);
838     n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
839                                                    &oprelease_neighbour_conn);
840     GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
841     GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
842     return h;
843   }
844   trigger_notifications (n);
845   return h;
846 }
847
848 void
849 GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
850 {
851   struct Neighbour *n;
852   int cleanup_task;
853   
854   n = h->n;
855   cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
856   GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
857   GNUNET_free (h);
858   if (GNUNET_NO == cleanup_task)
859     return;
860   if (GNUNET_SCHEDULER_NO_TASK == n->notify_task)
861     return;
862   GNUNET_SCHEDULER_cancel (n->notify_task);
863   n->notify_task = GNUNET_SCHEDULER_NO_TASK;
864   if (NULL == n->nl_head)
865   {
866     if ( (0 == n->reference_cnt) && (0 == n->inactive) )
867     {
868       n->inactive = 1;
869       GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
870     }
871     return;
872   }
873   trigger_notifications (n);
874 }
875
876 void
877 GST_neighbour_release_connection (struct Neighbour *n)
878 {
879   GNUNET_assert (0 == n->inactive);
880   GNUNET_assert (0 < n->reference_cnt);
881   n->reference_cnt--;
882   if (0 == n->reference_cnt)
883   {
884     n->inactive = 1;
885     GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
886   }
887 }
888
889 static void
890 cleanup_ncc (struct NeighbourConnectCtxt *ncc)
891 {
892   if (NULL != ncc->nh)
893     GST_neighbour_get_connection_cancel (ncc->nh);
894   if (GNUNET_SCHEDULER_NO_TASK != ncc->timeout_task)
895     GNUNET_SCHEDULER_cancel (ncc->timeout_task);
896   GNUNET_SERVER_client_drop (ncc->client);
897   GNUNET_CONTAINER_DLL_remove (ncc_head, ncc_tail, ncc);
898   GNUNET_free (ncc);
899 }
900
901 void
902 GST_neighbour_list_clean()
903 {
904   struct Neighbour *n;
905   unsigned int id;
906
907   for (id = 0; id < neighbour_list_size; id++)
908   {
909     if (NULL == (n = neighbour_list[id]))
910       continue;
911     if (NULL != n->conn_op)
912       GNUNET_TESTBED_operation_release_ (n->conn_op);
913     GNUNET_free (n);
914     neighbour_list[id] = NULL;
915   }
916   GNUNET_free_non_null (neighbour_list);
917 }
918
919 struct Neighbour *
920 GST_get_neighbour (uint32_t id)
921 {
922   if (neighbour_list_size <= id)
923     return NULL;
924   else
925     return neighbour_list[id];
926 }
927
928 void
929 GST_free_nccq ()
930 {
931   while (NULL != ncc_head)
932     cleanup_ncc (ncc_head);
933 }
934
935 static void
936 timeout_neighbour_connect (void *cls, 
937                            const struct GNUNET_SCHEDULER_TaskContext *tc)
938 {
939  struct NeighbourConnectCtxt *ncc = cls;
940
941  ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
942  send_controller_link_response (ncc->client, ncc->op_id, NULL,
943                                 "Could not connect to delegated controller");
944  cleanup_ncc (ncc);
945 }
946
947 static void
948 neighbour_connect_cb (void *cls, struct GNUNET_TESTBED_Controller *c)
949 {
950   struct NeighbourConnectCtxt *ncc = cls;
951
952   GNUNET_SCHEDULER_cancel (ncc->timeout_task);
953   ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
954   ncc->nh = NULL;
955   GST_neighbour_release_connection (ncc->n);
956   send_controller_link_response (ncc->client, ncc->op_id, NULL, NULL);
957   cleanup_ncc (ncc);
958 }
959
960 /**
961  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
962  *
963  * @param cls NULL
964  * @param client identification of the client
965  * @param message the actual message
966  */
967 void
968 GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
969                              const struct GNUNET_MessageHeader *message)
970 {
971   const struct GNUNET_TESTBED_ControllerLinkRequest *msg;
972   struct LCFContextQueue *lcfq;
973   struct Route *route;
974   struct Route *new_route;
975   uint64_t op_id;
976   uint32_t delegated_host_id;
977   uint32_t slave_host_id;
978
979   if (NULL == GST_context)
980   {
981     GNUNET_break (0);
982     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
983     return;
984   }
985   msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message;
986   delegated_host_id = ntohl (msg->delegated_host_id);
987   if (delegated_host_id == GST_context->host_id)
988   {
989     GNUNET_break (0);
990     LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
991     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
992     return;
993   }
994   if ((delegated_host_id >= GST_host_list_size) ||
995       (NULL == GST_host_list[delegated_host_id]))
996   {
997     LOG (GNUNET_ERROR_TYPE_WARNING,
998          "Delegated host %u not registered with us\n", delegated_host_id);
999     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1000     return;
1001   }
1002   slave_host_id = ntohl (msg->slave_host_id);
1003   if ((slave_host_id >= GST_host_list_size) ||
1004       (NULL == GST_host_list[slave_host_id]))
1005   {
1006     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
1007          slave_host_id);
1008     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1009     return;
1010   }
1011   if (slave_host_id == delegated_host_id)
1012   {
1013     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
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     new_route = GNUNET_malloc (sizeof (struct Route));
1077     new_route->dest = delegated_host_id;
1078     new_route->thru = GST_context->host_id;
1079     route_list_add (new_route);
1080     return;
1081   }
1082
1083   /* Route the request */
1084   if (slave_host_id >= route_list_size)
1085   {
1086     LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1087     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1088     return;
1089   }
1090   lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
1091   lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
1092   lcfq->lcf->type = CLOSURE_TYPE_LCF;
1093   lcfq->lcf->delegated_host_id = delegated_host_id;
1094   lcfq->lcf->slave_host_id = slave_host_id;
1095   route = GST_find_dest_route (slave_host_id);
1096   GNUNET_assert (NULL != route);        /* because we add routes carefully */
1097   GNUNET_assert (route->dest < GST_slave_list_size);
1098   GNUNET_assert (NULL != GST_slave_list[route->dest]);
1099   lcfq->lcf->is_subordinate = msg->is_subordinate;
1100   lcfq->lcf->state = INIT;
1101   lcfq->lcf->operation_id = op_id;
1102   lcfq->lcf->gateway = GST_slave_list[route->dest];
1103   GNUNET_SERVER_client_keep (client);
1104   lcfq->lcf->client = client;
1105   if (NULL == lcfq_head)
1106   {
1107     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1108     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1109     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
1110   }
1111   else
1112     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1113   /* FIXME: Adding a new route should happen after the controllers are linked
1114    * successfully */
1115   if (1 != msg->is_subordinate)
1116   {
1117     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1118     return;
1119   }
1120   if ((delegated_host_id < route_list_size) &&
1121       (NULL != route_list[delegated_host_id]))
1122   {
1123     GNUNET_break_op (0);        /* Are you trying to link delegated host twice
1124                                  * with is subordinate flag set to GNUNET_YES? */
1125     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1126     return;
1127   }
1128   new_route = GNUNET_malloc (sizeof (struct Route));
1129   new_route->dest = delegated_host_id;
1130   new_route->thru = route->dest;
1131   route_list_add (new_route);
1132   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1133 }
1134
1135
1136 /**
1137  * Cleans up the queue used for forwarding link controllers requests
1138  */
1139 void
1140 GST_free_lcfq ()
1141 {
1142   struct LCFContextQueue *lcfq;
1143   
1144   if (NULL != lcfq_head)
1145   {
1146     if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
1147     {
1148       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1149       lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1150     }
1151   }
1152   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1153   for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
1154   {
1155     GNUNET_SERVER_client_drop (lcfq->lcf->client);
1156     GNUNET_free (lcfq->lcf);
1157     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
1158     GNUNET_free (lcfq);
1159   }
1160 }