6f71d8a611ee7c0a5a3d2daa7f864f9c8d74966b
[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.c
23  * @brief implementation of the TESTBED service
24  * @author Sree Harsha Totakura
25  */
26
27 #include "gnunet-service-testbed.h"
28
29 /**
30  * The event mask for the events we listen from sub-controllers
31  */
32 #define EVENT_MASK (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED)
33
34 /**
35  * A list of directly linked neighbours
36  */
37 struct Slave **GST_slave_list;
38
39 /**
40  * The size of directly linked neighbours list
41  */
42 unsigned int GST_slave_list_size;
43
44 /**
45  * A list of routes
46  */
47 static struct Route **route_list;
48
49 /**
50  * The head for the LCF queue
51  */
52 static struct LCFContextQueue *lcfq_head;
53
54 /**
55  * The tail for the LCF queue
56  */
57 static struct LCFContextQueue *lcfq_tail;
58
59 /**
60  * The lcf_task handle
61  */
62 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
63
64 /**
65  * The size of the route list
66  */
67 static unsigned int route_list_size;
68
69
70 /**
71  * Adds a slave to the slave array
72  *
73  * @param slave the slave controller to add
74  */
75 static void
76 slave_list_add (struct Slave *slave)
77 {
78   if (slave->host_id >= GST_slave_list_size)
79     GST_array_grow_large_enough (GST_slave_list, GST_slave_list_size,
80                                  slave->host_id);
81   GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
82   GST_slave_list[slave->host_id] = slave;
83 }
84
85
86 /**
87  * Adds a route to the route list
88  *
89  * @param route the route to add
90  */
91 static void
92 route_list_add (struct Route *route)
93 {
94   if (route->dest >= route_list_size)
95     GST_array_grow_large_enough (route_list, route_list_size, route->dest);
96   GNUNET_assert (NULL == route_list[route->dest]);
97   route_list[route->dest] = route;
98 }
99
100
101 /**
102  * Cleans up the route list
103  */
104 void
105 GST_route_list_clear ()
106 {
107   unsigned int id;
108   
109   for (id = 0; id < route_list_size; id++)
110     if (NULL != route_list[id])
111       GNUNET_free (route_list[id]);
112   GNUNET_free_non_null (route_list);
113   route_list = NULL;
114 }
115
116
117 /**
118  * Iterator for freeing hash map entries in a slave's reghost_map
119  *
120  * @param cls handle to the slave
121  * @param key current key code
122  * @param value value in the hash map
123  * @return GNUNET_YES if we should continue to
124  *         iterate,
125  *         GNUNET_NO if not.
126  */
127 static int
128 reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key,
129                        void *value)
130 {
131   struct Slave *slave = cls;
132   struct RegisteredHostContext *rhc = value;
133   struct ForwardedOverlayConnectContext *focc;
134
135   GNUNET_assert (GNUNET_YES ==
136                  GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
137                                                        value));
138   while (NULL != (focc = rhc->focc_dll_head))
139   {
140     GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
141     GST_cleanup_focc (focc);
142   }
143   if (NULL != rhc->sub_op)
144     GNUNET_TESTBED_operation_done (rhc->sub_op);
145   if (NULL != rhc->client)
146     GNUNET_SERVER_client_drop (rhc->client);
147   GNUNET_free (value);
148   return GNUNET_YES;
149 }
150
151
152 /**
153  * Cleans up the slave list
154  */
155 void
156 GST_slave_list_clear ()
157 {
158   unsigned int id;
159   struct HostRegistration *hr_entry;
160
161   for (id = 0; id < GST_slave_list_size; id++)
162     if (NULL != GST_slave_list[id])
163     {
164       while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head))
165       {
166         GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head,
167                                      GST_slave_list[id]->hr_dll_tail, hr_entry);
168         GNUNET_free (hr_entry);
169       }
170       if (NULL != GST_slave_list[id]->rhandle)
171         GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle);
172       (void)
173           GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list
174                                                  [id]->reghost_map,
175                                                  reghost_free_iterator,
176                                                  GST_slave_list[id]);
177       GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map);
178       if (NULL != GST_slave_list[id]->controller)
179         GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller);
180       if (NULL != GST_slave_list[id]->controller_proc)
181         GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc);
182       GNUNET_free (GST_slave_list[id]);
183     }
184   GNUNET_free_non_null (GST_slave_list);
185   GST_slave_list = NULL;
186 }
187
188
189 /**
190  * Finds the route with directly connected host as destination through which
191  * the destination host can be reached
192  *
193  * @param host_id the id of the destination host
194  * @return the route with directly connected destination host; NULL if no route
195  *           is found
196  */
197 struct Route *
198 GST_find_dest_route (uint32_t host_id)
199 {
200   struct Route *route;
201
202   if (route_list_size <= host_id)
203     return NULL;
204   while (NULL != (route = route_list[host_id]))
205   {
206     if (route->thru == GST_context->host_id)
207       break;
208     host_id = route->thru;
209   }
210   return route;
211 }
212
213
214 /**
215  * Function to send a failure reponse for controller link operation
216  *
217  * @param client the client to send the message to
218  * @param operation_id the operation ID of the controller link request
219  * @param cfg the configuration with which the delegated controller is started.
220  *          Can be NULL if the delegated controller is not started but just
221  *          linked to.
222  * @param emsg set to an error message explaining why the controller link
223  *          failed.  Setting this to NULL signifies success.  !This should be
224  *          NULL if cfg is set!
225  */
226 static void
227 send_controller_link_response (struct GNUNET_SERVER_Client *client,
228                                uint64_t operation_id,
229                                const struct GNUNET_CONFIGURATION_Handle
230                                *cfg,
231                                const char *emsg)
232 {
233   struct GNUNET_TESTBED_ControllerLinkResponse *msg;
234   char *xconfig;
235   size_t config_size;
236   size_t xconfig_size;  
237   uint16_t msize;
238
239   GNUNET_assert ((NULL == cfg) || (NULL == emsg));
240   xconfig = NULL;
241   xconfig_size = 0;
242   config_size = 0;
243   msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse);
244   if (NULL != cfg)
245   {
246     xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
247                                             &config_size,
248                                             &xconfig_size);
249     msize += xconfig_size;
250   }
251   if (NULL != emsg)
252     msize += strlen (emsg);
253   msg = GNUNET_malloc (msize);
254   msg->header.type = htons
255       (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
256   msg->header.size = htons (msize);
257   if (NULL == emsg)
258     msg->success = htons (GNUNET_YES);
259   msg->operation_id = GNUNET_htonll (operation_id);
260   msg->config_size = htons ((uint16_t) config_size);
261   if (NULL != xconfig)
262     memcpy (&msg[1], xconfig, xconfig_size);
263   if (NULL != emsg)
264     memcpy (&msg[1], emsg, strlen (emsg));
265   GST_queue_message (client, &msg->header);
266 }
267
268
269 /**
270  * The  Link Controller forwarding task
271  *
272  * @param cls the LCFContext
273  * @param tc the Task context from scheduler
274  */
275 static void
276 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
277
278
279 /**
280  * Completion callback for host registrations while forwarding Link Controller messages
281  *
282  * @param cls the LCFContext
283  * @param emsg the error message; NULL if host registration is successful
284  */
285 static void
286 lcf_proc_cc (void *cls, const char *emsg)
287 {
288   struct LCFContext *lcf = cls;
289
290   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
291   switch (lcf->state)
292   {
293   case INIT:
294     if (NULL != emsg)
295       goto registration_error;
296     lcf->state = DELEGATED_HOST_REGISTERED;
297     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
298     break;
299   case DELEGATED_HOST_REGISTERED:
300     if (NULL != emsg)
301       goto registration_error;
302     lcf->state = SLAVE_HOST_REGISTERED;
303     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
304     break;
305   default:
306     GNUNET_assert (0);          /* Shouldn't reach here */
307   }
308   return;
309
310 registration_error:
311   LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
312        emsg);
313   lcf->state = FINISHED;
314   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
315 }
316
317
318 /**
319  * The  Link Controller forwarding task
320  *
321  * @param cls the LCFContext
322  * @param tc the Task context from scheduler
323  */
324 static void
325 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
326
327
328 /**
329  * Task to free resources when forwarded link controllers has been timedout
330  *
331  * @param cls the LCFContext
332  * @param tc the task context from scheduler
333  */
334 static void
335 lcf_forwarded_operation_timeout (void *cls,
336                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
337 {
338   struct LCFContext *lcf = cls;
339
340   lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK;
341   //  GST_forwarded_operation_timeout (lcf->fopc, tc);
342   LOG (GNUNET_ERROR_TYPE_WARNING,
343        "A forwarded controller link operation has timed out\n");
344   send_controller_link_response (lcf->client, lcf->operation_id, NULL,
345                                  "A forwarded controller link operation has "
346                                  "timed out\n");
347   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
348   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
349 }
350
351
352 /**
353  * The  Link Controller forwarding task
354  *
355  * @param cls the LCFContext
356  * @param tc the Task context from scheduler
357  */
358 static void
359 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
360 {
361   struct LCFContext *lcf = cls;
362   struct LCFContextQueue *lcfq;
363
364   lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
365   switch (lcf->state)
366   {
367   case INIT:
368     if (GNUNET_NO ==
369         GNUNET_TESTBED_is_host_registered_ (GST_host_list
370                                             [lcf->delegated_host_id],
371                                             lcf->gateway->controller))
372     {
373       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
374                                    GST_host_list[lcf->delegated_host_id]);
375     }
376     else
377     {
378       lcf->state = DELEGATED_HOST_REGISTERED;
379       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
380     }
381     break;
382   case DELEGATED_HOST_REGISTERED:
383     if (GNUNET_NO ==
384         GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
385                                             lcf->gateway->controller))
386     {
387       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
388                                    GST_host_list[lcf->slave_host_id]);
389     }
390     else
391     {
392       lcf->state = SLAVE_HOST_REGISTERED;
393       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
394     }
395     break;
396   case SLAVE_HOST_REGISTERED:
397     lcf->op = GNUNET_TESTBED_controller_link (lcf,
398                                               lcf->gateway->controller,
399                                               GST_host_list[lcf->delegated_host_id],
400                                               GST_host_list[lcf->slave_host_id],
401                                               NULL,
402                                               lcf->is_subordinate);
403     lcf->timeout_task =
404         GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout,
405                                       lcf);
406     lcf->state = FINISHED;
407     break;
408   case FINISHED:
409     lcfq = lcfq_head;
410     GNUNET_assert (lcfq->lcf == lcf);
411     GNUNET_assert (NULL != lcf->cfg);
412     GNUNET_CONFIGURATION_destroy (lcf->cfg);
413     GNUNET_SERVER_client_drop (lcf->client);
414     GNUNET_TESTBED_operation_done (lcf->op);
415     GNUNET_free (lcf);
416     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
417     GNUNET_free (lcfq);
418     if (NULL != lcfq_head)
419       lcf_proc_task_id =
420           GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
421   }
422 }
423
424
425 /**
426  * Callback for event from slave controllers
427  *
428  * @param cls struct Slave *
429  * @param event information about the event
430  */
431 static void
432 slave_event_callback (void *cls,
433                       const struct GNUNET_TESTBED_EventInformation *event)
434 {
435   struct RegisteredHostContext *rhc;
436   struct LCFContext *lcf;
437   struct GNUNET_CONFIGURATION_Handle *cfg;
438   struct GNUNET_TESTBED_Operation *old_op;
439
440   /* We currently only get here when working on RegisteredHostContexts and
441      LCFContexts */
442   GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
443   rhc = event->op_cls;
444   if (CLOSURE_TYPE_RHC == rhc->type)
445   {
446     GNUNET_assert (rhc->sub_op == event->op);
447     switch (rhc->state)
448     {
449     case RHC_GET_CFG:
450       cfg = event->details.operation_finished.generic;
451       old_op = rhc->sub_op;
452       rhc->state = RHC_LINK;
453       rhc->sub_op =
454           GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller,
455                                           rhc->reg_host, rhc->host, cfg,
456                                           GNUNET_NO);
457       GNUNET_TESTBED_operation_done (old_op);
458       break;
459     case RHC_LINK:
460       LOG_DEBUG ("OL: Linking controllers successfull\n");
461       GNUNET_TESTBED_operation_done (rhc->sub_op);
462       rhc->sub_op = NULL;
463       rhc->state = RHC_OL_CONNECT;
464       GST_process_next_focc (rhc);
465       break;
466     default:
467       GNUNET_assert (0);
468     }
469     return;
470   }
471   lcf = event->op_cls;
472   if (CLOSURE_TYPE_LCF == lcf->type)
473   {    
474     GNUNET_assert (lcf->op == event->op);
475     GNUNET_assert (FINISHED == lcf->state);
476     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task);
477     GNUNET_SCHEDULER_cancel (lcf->timeout_task);
478     if (NULL == event->details.operation_finished.emsg)
479       send_controller_link_response (lcf->client, lcf->operation_id,
480                                      GNUNET_TESTBED_host_get_cfg_ 
481                                      (GST_host_list[lcf->delegated_host_id]),
482                                      NULL);
483     else
484       send_controller_link_response (lcf->client, lcf->operation_id,
485                                      NULL,
486                                      event->details.operation_finished.emsg);
487     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
488     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
489     return;
490   }
491   GNUNET_assert (0);
492 }
493
494
495 /**
496  * Callback to signal successfull startup of the controller process
497  *
498  * @param cls the handle to the slave whose status is to be found here
499  * @param cfg the configuration with which the controller has been started;
500  *          NULL if status is not GNUNET_OK
501  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
502  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
503  */
504 static void
505 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
506                        int status)
507 {
508   struct Slave *slave = cls;
509   struct LinkControllersContext *lcc;
510
511   lcc = slave->lcc;
512   if (GNUNET_SYSERR == status)
513   {
514     slave->controller_proc = NULL;
515     GST_slave_list[slave->host_id] = NULL;
516     GNUNET_free (slave);
517     slave = NULL;
518     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
519     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
520     goto clean_lcc;
521   }
522   slave->controller =
523       GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
524                                          EVENT_MASK, &slave_event_callback,
525                                          slave);
526   if (NULL != slave->controller)
527   {
528     send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
529   }
530   else
531   {
532     send_controller_link_response (lcc->client, lcc->operation_id, NULL,
533                                    "Could not connect to delegated controller");
534     GNUNET_TESTBED_controller_stop (slave->controller_proc);
535     GST_slave_list[slave->host_id] = NULL;
536     GNUNET_free (slave);
537     slave = NULL;
538   }
539
540 clean_lcc:
541   if (NULL != lcc)
542   {
543     if (NULL != lcc->client)
544     {
545       GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
546       GNUNET_SERVER_client_drop (lcc->client);
547       lcc->client = NULL;
548     }
549     GNUNET_free (lcc);
550   }
551   if (NULL != slave)
552     slave->lcc = NULL;
553 }
554
555
556 /**
557  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
558  *
559  * @param cls NULL
560  * @param client identification of the client
561  * @param message the actual message
562  */
563 void
564 GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
565                          const struct GNUNET_MessageHeader *message)
566 {
567   const struct GNUNET_TESTBED_ControllerLinkRequest *msg;
568   struct GNUNET_CONFIGURATION_Handle *cfg;
569   struct LCFContextQueue *lcfq;
570   struct Route *route;
571   struct Route *new_route;
572   uint32_t delegated_host_id;
573   uint32_t slave_host_id;
574   uint16_t msize;
575
576   if (NULL == GST_context)
577   {
578     GNUNET_break (0);
579     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
580     return;
581   }
582   msize = ntohs (message->size);
583   if (sizeof (struct GNUNET_TESTBED_ControllerLinkRequest) >= msize)
584   {
585     GNUNET_break (0);
586     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
587     return;
588   }
589   msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message;
590   delegated_host_id = ntohl (msg->delegated_host_id);
591   if (delegated_host_id == GST_context->host_id)
592   {
593     GNUNET_break (0);
594     LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
595     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
596     return;
597   }
598   if ((delegated_host_id >= GST_host_list_size) ||
599       (NULL == GST_host_list[delegated_host_id]))
600   {
601     LOG (GNUNET_ERROR_TYPE_WARNING,
602          "Delegated host %u not registered with us\n", delegated_host_id);
603     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
604     return;
605   }
606   slave_host_id = ntohl (msg->slave_host_id);
607   if ((slave_host_id >= GST_host_list_size) ||
608       (NULL == GST_host_list[slave_host_id]))
609   {
610     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
611          slave_host_id);
612     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
613     return;
614   }
615   if (slave_host_id == delegated_host_id)
616   {
617     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
618     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
619     return;
620   }
621   cfg = GNUNET_TESTBED_extract_config_ (message); /* destroy cfg here or in lcfcontext */
622   if (NULL == cfg)
623   {
624     GNUNET_break (0);         /* Configuration parsing error */
625     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
626     return;
627   }
628   if (slave_host_id == GST_context->host_id)    /* Link from us */
629   {
630     struct Slave *slave;
631     struct LinkControllersContext *lcc;
632
633     if ((delegated_host_id < GST_slave_list_size) &&
634         (NULL != GST_slave_list[delegated_host_id]))
635     {
636       GNUNET_break (0);
637       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
638       return;
639     }
640     slave = GNUNET_malloc (sizeof (struct Slave));
641     slave->host_id = delegated_host_id;
642     slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
643     slave_list_add (slave);
644     if (1 != msg->is_subordinate)
645     {
646       slave->controller =
647           GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
648                                              EVENT_MASK, &slave_event_callback,
649                                              slave);
650       if (NULL != slave->controller)
651         send_controller_link_response (client,
652                                        GNUNET_ntohll (msg->operation_id),
653                                        NULL,
654                                        NULL);
655       else
656         send_controller_link_response (client,
657                                        GNUNET_ntohll (msg->operation_id),
658                                        NULL,
659                                        "Could not connect to delegated controller");
660       GNUNET_SERVER_receive_done (client, GNUNET_OK);
661       return;
662     }
663     lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
664     lcc->operation_id = GNUNET_ntohll (msg->operation_id);
665     GNUNET_SERVER_client_keep (client);
666     lcc->client = client;
667     slave->lcc = lcc;
668     slave->controller_proc =
669         GNUNET_TESTBED_controller_start (GST_context->master_ip,
670                                          GST_host_list[slave->host_id], cfg,
671                                          &slave_status_callback, slave);
672     GNUNET_CONFIGURATION_destroy (cfg);
673     new_route = GNUNET_malloc (sizeof (struct Route));
674     new_route->dest = delegated_host_id;
675     new_route->thru = GST_context->host_id;
676     route_list_add (new_route);
677     return;
678   }
679
680   /* Route the request */
681   if (slave_host_id >= route_list_size)
682   {
683     LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
684     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
685     return;
686   }
687   lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
688   lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
689   lcfq->lcf->type = CLOSURE_TYPE_LCF;
690   lcfq->lcf->delegated_host_id = delegated_host_id;
691   lcfq->lcf->slave_host_id = slave_host_id;
692   route = GST_find_dest_route (slave_host_id);
693   GNUNET_assert (NULL != route);        /* because we add routes carefully */
694   GNUNET_assert (route->dest < GST_slave_list_size);
695   GNUNET_assert (NULL != GST_slave_list[route->dest]);
696   lcfq->lcf->cfg = cfg;
697   lcfq->lcf->is_subordinate = msg->is_subordinate;
698   lcfq->lcf->state = INIT;
699   lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id);
700   lcfq->lcf->gateway = GST_slave_list[route->dest];
701   GNUNET_SERVER_client_keep (client);
702   lcfq->lcf->client = client;
703   if (NULL == lcfq_head)
704   {
705     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
706     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
707     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
708   }
709   else
710     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
711   /* FIXME: Adding a new route should happen after the controllers are linked
712    * successfully */
713   if (1 != msg->is_subordinate)
714   {
715     GNUNET_SERVER_receive_done (client, GNUNET_OK);
716     return;
717   }
718   if ((delegated_host_id < route_list_size) &&
719       (NULL != route_list[delegated_host_id]))
720   {
721     GNUNET_break_op (0);        /* Are you trying to link delegated host twice
722                                  * with is subordinate flag set to GNUNET_YES? */
723     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
724     return;
725   }
726   new_route = GNUNET_malloc (sizeof (struct Route));
727   new_route->dest = delegated_host_id;
728   new_route->thru = route->dest;
729   route_list_add (new_route);
730   GNUNET_SERVER_receive_done (client, GNUNET_OK);
731 }
732
733
734 /**
735  * Cleans up the queue used for forwarding link controllers requests
736  */
737 void
738 GST_free_lcfq ()
739 {
740   struct LCFContextQueue *lcfq;
741   
742   if (NULL != lcfq_head)
743   {
744     if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
745     {
746       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
747       lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
748     }
749   }
750   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
751   for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
752   {
753     GNUNET_SERVER_client_drop (lcfq->lcf->client);
754     GNUNET_assert (NULL != lcfq->lcf->cfg);
755     GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg);
756     GNUNET_free (lcfq->lcf);
757     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
758     GNUNET_free (lcfq);
759   }
760 }