- give out run handle through which master controller's handle can be retrieved
[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 3, 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   struct HostRegistration *hr_entry;
429   struct GNUNET_TESTBED_ControllerProc *cproc;
430   unsigned int id;
431
432   for (id = 0; id < GST_slave_list_size; id++)
433   {
434     if (NULL == GST_slave_list[id])
435       continue;
436     while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head))
437     {
438       GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head,
439                                    GST_slave_list[id]->hr_dll_tail, hr_entry);
440       GNUNET_free (hr_entry);
441     }
442     if (NULL != GST_slave_list[id]->rhandle)
443       GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle);
444     (void)
445         GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list
446                                                [id]->reghost_map,
447                                                reghost_free_iterator,
448                                                GST_slave_list[id]);
449     GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map);
450     if (NULL != GST_slave_list[id]->controller)
451       GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller);
452     if (NULL != (cproc = GST_slave_list[id]->controller_proc))
453     {
454       LOG_DEBUG ("Stopping a slave\n");
455       GNUNET_TESTBED_controller_kill_ (cproc);
456     }
457   }
458   for (id = 0; id < GST_slave_list_size; id++)
459   {
460     if (NULL == GST_slave_list[id])
461       continue;
462     if (NULL != (cproc = GST_slave_list[id]->controller_proc))
463     {
464       GNUNET_TESTBED_controller_destroy_ (cproc);
465       LOG_DEBUG ("Slave stopped\n");
466     }
467     GNUNET_free (GST_slave_list[id]);
468   }
469   GNUNET_free_non_null (GST_slave_list);
470   GST_slave_list = NULL;
471 }
472
473
474 /**
475  * Finds the route with directly connected host as destination through which
476  * the destination host can be reached
477  *
478  * @param host_id the id of the destination host
479  * @return the route with directly connected destination host; NULL if no route
480  *           is found
481  */
482 struct Route *
483 GST_find_dest_route (uint32_t host_id)
484 {
485   struct Route *route;
486
487   if (route_list_size <= host_id)
488     return NULL;
489   while (NULL != (route = route_list[host_id]))
490   {
491     if (route->thru == GST_context->host_id)
492       break;
493     host_id = route->thru;
494   }
495   return route;
496 }
497
498
499 /**
500  * Function to send a failure reponse for controller link operation
501  *
502  * @param client the client to send the message to
503  * @param operation_id the operation ID of the controller link request
504  * @param cfg the configuration with which the delegated controller is started.
505  *          Can be NULL if the delegated controller is not started but just
506  *          linked to.
507  * @param emsg set to an error message explaining why the controller link
508  *          failed.  Setting this to NULL signifies success.  !This should be
509  *          NULL if cfg is set!
510  */
511 static void
512 send_controller_link_response (struct GNUNET_SERVER_Client *client,
513                                uint64_t operation_id,
514                                const struct GNUNET_CONFIGURATION_Handle
515                                *cfg,
516                                const char *emsg)
517 {
518   struct GNUNET_TESTBED_ControllerLinkResponse *msg;
519   char *xconfig;
520   size_t config_size;
521   size_t xconfig_size;  
522   uint16_t msize;
523
524   GNUNET_assert ((NULL == cfg) || (NULL == emsg));
525   xconfig = NULL;
526   xconfig_size = 0;
527   config_size = 0;
528   msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse);
529   if (NULL != cfg)
530   {
531     xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
532                                             &config_size,
533                                             &xconfig_size);
534     msize += xconfig_size;
535   }
536   if (NULL != emsg)
537     msize += strlen (emsg);
538   msg = GNUNET_malloc (msize);
539   msg->header.type = htons
540       (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
541   msg->header.size = htons (msize);
542   if (NULL == emsg)
543     msg->success = htons (GNUNET_YES);
544   msg->operation_id = GNUNET_htonll (operation_id);
545   msg->config_size = htons ((uint16_t) config_size);
546   if (NULL != xconfig)
547   {
548     memcpy (&msg[1], xconfig, xconfig_size);
549     GNUNET_free (xconfig);
550   }
551   if (NULL != emsg)
552     memcpy (&msg[1], emsg, strlen (emsg));
553   GST_queue_message (client, &msg->header);
554 }
555
556
557 /**
558  * The  Link Controller forwarding task
559  *
560  * @param cls the LCFContext
561  * @param tc the Task context from scheduler
562  */
563 static void
564 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
565
566
567 /**
568  * Completion callback for host registrations while forwarding Link Controller messages
569  *
570  * @param cls the LCFContext
571  * @param emsg the error message; NULL if host registration is successful
572  */
573 static void
574 lcf_proc_cc (void *cls, const char *emsg)
575 {
576   struct LCFContext *lcf = cls;
577
578   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
579   switch (lcf->state)
580   {
581   case INIT:
582     if (NULL != emsg)
583       goto registration_error;
584     lcf->state = DELEGATED_HOST_REGISTERED;
585     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
586     break;
587   case DELEGATED_HOST_REGISTERED:
588     if (NULL != emsg)
589       goto registration_error;
590     lcf->state = SLAVE_HOST_REGISTERED;
591     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
592     break;
593   default:
594     GNUNET_assert (0);          /* Shouldn't reach here */
595   }
596   return;
597
598 registration_error:
599   LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
600        emsg);
601   lcf->state = FINISHED;
602   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
603 }
604
605
606 /**
607  * The  Link Controller forwarding task
608  *
609  * @param cls the LCFContext
610  * @param tc the Task context from scheduler
611  */
612 static void
613 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
614
615
616 /**
617  * Task to free resources when forwarded link controllers has been timedout
618  *
619  * @param cls the LCFContext
620  * @param tc the task context from scheduler
621  */
622 static void
623 lcf_forwarded_operation_timeout (void *cls,
624                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
625 {
626   struct LCFContext *lcf = cls;
627
628   lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK;
629   //  GST_forwarded_operation_timeout (lcf->fopc, tc);
630   LOG (GNUNET_ERROR_TYPE_WARNING,
631        "A forwarded controller link operation has timed out\n");
632   send_controller_link_response (lcf->client, lcf->operation_id, NULL,
633                                  "A forwarded controller link operation has "
634                                  "timed out\n");
635   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
636   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
637 }
638
639
640 /**
641  * The  Link Controller forwarding task
642  *
643  * @param cls the LCFContext
644  * @param tc the Task context from scheduler
645  */
646 static void
647 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
648 {
649   struct LCFContext *lcf = cls;
650   struct LCFContextQueue *lcfq;
651
652   lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
653   switch (lcf->state)
654   {
655   case INIT:
656     if (GNUNET_NO ==
657         GNUNET_TESTBED_is_host_registered_ (GST_host_list
658                                             [lcf->delegated_host_id],
659                                             lcf->gateway->controller))
660     {
661       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
662                                    GST_host_list[lcf->delegated_host_id]);
663     }
664     else
665     {
666       lcf->state = DELEGATED_HOST_REGISTERED;
667       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
668     }
669     break;
670   case DELEGATED_HOST_REGISTERED:
671     if (GNUNET_NO ==
672         GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
673                                             lcf->gateway->controller))
674     {
675       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
676                                    GST_host_list[lcf->slave_host_id]);
677     }
678     else
679     {
680       lcf->state = SLAVE_HOST_REGISTERED;
681       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
682     }
683     break;
684   case SLAVE_HOST_REGISTERED:
685     lcf->op = GNUNET_TESTBED_controller_link (lcf,
686                                               lcf->gateway->controller,
687                                               GST_host_list[lcf->delegated_host_id],
688                                               GST_host_list[lcf->slave_host_id],
689                                               lcf->is_subordinate);
690     lcf->timeout_task =
691         GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout,
692                                       lcf);
693     lcf->state = FINISHED;
694     break;
695   case FINISHED:
696     lcfq = lcfq_head;
697     GNUNET_assert (lcfq->lcf == lcf);
698     GNUNET_SERVER_client_drop (lcf->client);
699     GNUNET_TESTBED_operation_done (lcf->op);
700     GNUNET_free (lcf);
701     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
702     GNUNET_free (lcfq);
703     if (NULL != lcfq_head)
704       lcf_proc_task_id =
705           GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
706   }
707 }
708
709
710 /**
711  * Callback for event from slave controllers
712  *
713  * @param cls NULL
714  * @param event information about the event
715  */
716 static void
717 slave_event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
718 {
719   struct LCFContext *lcf;
720
721   /* We currently only get here when working on RegisteredHostContexts and
722      LCFContexts */
723   GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
724   lcf = event->op_cls;
725   GNUNET_assert (lcf->op == event->op);
726   GNUNET_assert (FINISHED == lcf->state);
727   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task);
728   GNUNET_SCHEDULER_cancel (lcf->timeout_task);
729   if (NULL == event->details.operation_finished.emsg)
730     send_controller_link_response (lcf->client, lcf->operation_id,
731                                    GNUNET_TESTBED_host_get_cfg_ 
732                                    (GST_host_list[lcf->delegated_host_id]),
733                                    NULL);
734   else
735     send_controller_link_response (lcf->client, lcf->operation_id,
736                                    NULL,
737                                    event->details.operation_finished.emsg);
738   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
739   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
740   return;
741 }
742
743
744 /**
745  * Callback to signal successfull startup of the controller process
746  *
747  * @param cls the handle to the slave whose status is to be found here
748  * @param cfg the configuration with which the controller has been started;
749  *          NULL if status is not GNUNET_OK
750  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
751  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
752  */
753 static void
754 slave_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
755                  int status)
756 {
757   struct Slave *slave = cls;
758   struct LinkControllersContext *lcc;
759
760   lcc = slave->lcc;
761   if (GNUNET_SYSERR == status)
762   {
763     slave->controller_proc = NULL;
764     GST_slave_list[slave->host_id] = NULL;
765     GNUNET_free (slave);
766     slave = NULL;
767     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
768     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
769     goto clean_lcc;
770   }
771   slave->controller =
772       GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
773                                          EVENT_MASK, &slave_event_cb,
774                                          slave);
775   if (NULL != slave->controller)
776   {
777     send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
778   }
779   else
780   {
781     send_controller_link_response (lcc->client, lcc->operation_id, NULL,
782                                    "Could not connect to delegated controller");
783     GNUNET_TESTBED_controller_stop (slave->controller_proc);
784     GST_slave_list[slave->host_id] = NULL;
785     GNUNET_free (slave);
786     slave = NULL;
787   }
788
789 clean_lcc:
790   if (NULL != lcc)
791   {
792     if (NULL != lcc->client)
793     {
794       GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
795       GNUNET_SERVER_client_drop (lcc->client);
796       lcc->client = NULL;
797     }
798     GNUNET_free (lcc);
799   }
800   if (NULL != slave)
801     slave->lcc = NULL;
802 }
803
804
805 /**
806  * Trigger notification task if there are notification requests currently
807  * waiting in the given neighbour.  Also activates the neighbour connect operation
808  * if it was previously inactivated so that the connection to the neighbour can
809  * be re-used
810  *
811  * @param n the neighbour
812  */
813 static void
814 trigger_notifications (struct Neighbour *n);
815
816
817 /**
818  * Task to call the notification queued in the notifications list of the given
819  * neighbour
820  *
821  * @param cls the neighbour
822  * @param tc scheduler task context
823  */
824 static void
825 neighbour_connect_notify_task (void *cls, 
826                                const struct GNUNET_SCHEDULER_TaskContext *tc)
827 {
828   struct Neighbour *n = cls;
829   struct NeighbourConnectNotification *h;
830
831   GNUNET_assert (NULL != (h = n->nl_head));
832   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->notify_task);  
833   n->notify_task = GNUNET_SCHEDULER_NO_TASK;
834   GNUNET_assert (NULL != n->controller);
835   GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);  
836   trigger_notifications (n);
837   h->cb (h->cb_cls, n->controller);
838   GNUNET_free (h);
839 }
840
841
842 /**
843  * Trigger notification task if there are notification requests currently
844  * waiting in the given neighbour.  Also activates the neighbour connect operation
845  * if it was previously inactivated so that the connection to the neighbour can
846  * be re-used
847  *
848  * @param n the neighbour
849  */
850 static void
851 trigger_notifications (struct Neighbour *n)
852 {
853   GNUNET_assert (NULL != n->conn_op);
854   if (NULL == n->nl_head)
855     return;
856   if (NULL == n->controller)
857     return;
858   if (GNUNET_SCHEDULER_NO_TASK != n->notify_task)
859     return;  
860   if (1 == n->inactive)
861   {
862     GNUNET_assert (0 == n->reference_cnt);
863     GNUNET_TESTBED_operation_activate_ (n->conn_op);
864     n->inactive = 0;
865   }
866   n->reference_cnt++;
867   n->notify_task = 
868       GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n);
869 }
870
871
872 /**
873  * Callback to be called when the neighbour connect operation is started.  The
874  * connection to the neigbour is opened here and any pending notifications are
875  * trigger.
876  *
877  * @param cls the neighbour
878  */
879 static void
880 opstart_neighbour_conn (void *cls)
881 {
882   struct Neighbour *n = cls;
883   
884   GNUNET_assert (NULL != n->conn_op);
885   GNUNET_assert (NULL == n->controller);
886   LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
887   n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
888                                                      EVENT_MASK,
889                                                      &slave_event_cb,
890                                                      NULL);
891   trigger_notifications (n);
892 }
893
894
895 /**
896  * Callback to be called when the neighbour connect operation is released
897  *
898  * @param cls the neighbour
899  */
900 static void
901 oprelease_neighbour_conn (void *cls)
902 {
903    struct Neighbour *n = cls;
904
905    GNUNET_assert (0 == n->reference_cnt);
906    GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->notify_task);
907    GNUNET_assert (NULL == n->nl_head);
908    if (NULL != n->controller)
909    {
910      LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
911      GNUNET_TESTBED_controller_disconnect (n->controller);
912      n->controller = NULL;
913    }
914    n->conn_op = NULL;
915    n->inactive = 0;
916 }
917
918
919 /**
920  * Try to open a connection to the given neigbour.  If the connection is open
921  * already, then it is re-used.  If not, the request is queued in the operation
922  * queues responsible for bounding the total number of file descriptors.  The
923  * actual connection will happen when the operation queue marks the
924  * corresponding operation as active.
925  *
926  * @param n the neighbour to open a connection to
927  * @param cb the notification callback to call when the connection is opened
928  * @param cb_cls the closure for the above callback
929  */
930 struct NeighbourConnectNotification *
931 GST_neighbour_get_connection (struct Neighbour *n,
932                               GST_NeigbourConnectNotifyCallback cb,
933                               void *cb_cls)
934 {
935   struct NeighbourConnectNotification *h;
936
937   GNUNET_assert (NULL != cb);
938   LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
939              n->host_id);
940   h = GNUNET_malloc (sizeof (struct NeighbourConnectNotification));
941   h->n = n;
942   h->cb  = cb;
943   h->cb_cls = cb_cls;
944   GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
945   if (NULL == n->conn_op)
946   {
947     GNUNET_assert (NULL == n->controller);
948     n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
949                                                    &oprelease_neighbour_conn);
950     GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
951     GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
952     return h;
953   }
954   trigger_notifications (n);
955   return h;
956 }
957
958
959 /**
960  * Cancel the request for opening a connection to the neighbour
961  *
962  * @param h the notification handle
963  */
964 void
965 GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
966 {
967   struct Neighbour *n;
968   int cleanup_task;
969   
970   n = h->n;
971   cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
972   GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
973   GNUNET_free (h);
974   if (GNUNET_NO == cleanup_task)
975     return;
976   if (GNUNET_SCHEDULER_NO_TASK == n->notify_task)
977     return;
978   GNUNET_assert (0 < n->reference_cnt);
979   n->reference_cnt--;
980   GNUNET_SCHEDULER_cancel (n->notify_task);
981   n->notify_task = GNUNET_SCHEDULER_NO_TASK;
982   if (NULL == n->nl_head)
983   {
984     if ( (0 == n->reference_cnt) && (0 == n->inactive) )
985     {
986       n->inactive = 1;
987       GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
988     }
989     return;
990   }
991   trigger_notifications (n);
992 }
993
994
995 /**
996  * Release the connection to the neighbour.  The actual connection will be
997  * closed if connections to other neighbour are waiting (to maintain a bound on
998  * the total number of connections that are open).
999  *
1000  * @param n the neighbour whose connection can be closed
1001  */
1002 void
1003 GST_neighbour_release_connection (struct Neighbour *n)
1004 {
1005   GNUNET_assert (0 == n->inactive);
1006   GNUNET_assert (0 < n->reference_cnt);
1007   n->reference_cnt--;
1008   if (0 == n->reference_cnt)
1009   {
1010     n->inactive = 1;
1011     GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1012   }
1013 }
1014
1015
1016 /**
1017  * Cleanup neighbour connect contexts
1018  *
1019  * @param ncc the neighbour connect context to cleanup
1020  */
1021 static void
1022 cleanup_ncc (struct NeighbourConnectCtxt *ncc)
1023 {
1024   if (NULL != ncc->nh)
1025     GST_neighbour_get_connection_cancel (ncc->nh);
1026   if (GNUNET_SCHEDULER_NO_TASK != ncc->timeout_task)
1027     GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1028   GNUNET_SERVER_client_drop (ncc->client);
1029   GNUNET_CONTAINER_DLL_remove (ncc_head, ncc_tail, ncc);
1030   GNUNET_free (ncc);
1031 }
1032
1033
1034 /**
1035  * Cleans up the neighbour list
1036  */
1037 void
1038 GST_neighbour_list_clean()
1039 {
1040   struct Neighbour *n;
1041   unsigned int id;
1042
1043   for (id = 0; id < neighbour_list_size; id++)
1044   {
1045     if (NULL == (n = neighbour_list[id]))
1046       continue;
1047     if (NULL != n->conn_op)
1048       GNUNET_TESTBED_operation_release_ (n->conn_op);
1049     GNUNET_free (n);
1050     neighbour_list[id] = NULL;
1051   }
1052   GNUNET_free_non_null (neighbour_list);
1053 }
1054
1055
1056 /**
1057  * Get a neighbour from the neighbour list
1058  *
1059  * @param id the index of the neighbour in the neighbour list
1060  * @return the Neighbour; NULL if the given index in invalid (index greater than
1061  *           the list size or neighbour at that index is NULL)
1062  */
1063 struct Neighbour *
1064 GST_get_neighbour (uint32_t id)
1065 {
1066   if (neighbour_list_size <= id)
1067     return NULL;
1068   else
1069     return neighbour_list[id];
1070 }
1071
1072
1073 /**
1074  * Function to cleanup the neighbour connect contexts
1075  */
1076 void
1077 GST_free_nccq ()
1078 {
1079   while (NULL != ncc_head)
1080     cleanup_ncc (ncc_head);
1081 }
1082
1083
1084 /**
1085  * Task to be run upon timeout while attempting to connect to the neighbour
1086  *
1087  * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1088  * @param tc the scheduler task context
1089  */
1090 static void
1091 timeout_neighbour_connect (void *cls, 
1092                            const struct GNUNET_SCHEDULER_TaskContext *tc)
1093 {
1094  struct NeighbourConnectCtxt *ncc = cls;
1095
1096  ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1097  send_controller_link_response (ncc->client, ncc->op_id, NULL,
1098                                 "Could not connect to delegated controller");
1099  cleanup_ncc (ncc);
1100 }
1101
1102
1103 /**
1104  * Callback called when a connection to the neighbour is made
1105  *
1106  * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1107  * @param c the handle the neighbour's controller
1108  */
1109 static void
1110 neighbour_connect_cb (void *cls, struct GNUNET_TESTBED_Controller *c)
1111 {
1112   struct NeighbourConnectCtxt *ncc = cls;
1113
1114   GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1115   ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1116   ncc->nh = NULL;
1117   GST_neighbour_release_connection (ncc->n);
1118   send_controller_link_response (ncc->client, ncc->op_id, NULL, NULL);
1119   cleanup_ncc (ncc);
1120 }
1121
1122
1123 /**
1124  * Function to create a neigbour and add it into the neighbour list
1125  *
1126  * @param host the host of the neighbour
1127  */
1128 struct Neighbour *
1129 GST_create_neighbour (struct GNUNET_TESTBED_Host *host)
1130 {
1131   struct Neighbour *n;
1132
1133   n = GNUNET_malloc (sizeof (struct Neighbour));
1134   n->host_id = GNUNET_TESTBED_host_get_id_ (host);
1135   neighbour_list_add (n);   /* just add; connect on-demand */
1136   return n;
1137 }
1138
1139
1140 /**
1141  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1142  *
1143  * @param cls NULL
1144  * @param client identification of the client
1145  * @param message the actual message
1146  */
1147 void
1148 GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
1149                              const struct GNUNET_MessageHeader *message)
1150 {
1151   const struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1152   struct LCFContextQueue *lcfq;
1153   struct Route *route;
1154   struct Route *new_route;
1155   uint64_t op_id;
1156   uint32_t delegated_host_id;
1157   uint32_t slave_host_id;
1158
1159   if (NULL == GST_context)
1160   {
1161     GNUNET_break (0);
1162     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1163     return;
1164   }
1165   msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message;
1166   delegated_host_id = ntohl (msg->delegated_host_id);
1167   if (delegated_host_id == GST_context->host_id)
1168   {
1169     GNUNET_break (0);
1170     LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
1171     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1172     return;
1173   }
1174   if ((delegated_host_id >= GST_host_list_size) ||
1175       (NULL == GST_host_list[delegated_host_id]))
1176   {
1177     LOG (GNUNET_ERROR_TYPE_WARNING,
1178          "Delegated host %u not registered with us\n", delegated_host_id);
1179     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1180     return;
1181   }
1182   slave_host_id = ntohl (msg->slave_host_id);
1183   if ((slave_host_id >= GST_host_list_size) ||
1184       (NULL == GST_host_list[slave_host_id]))
1185   {
1186     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
1187          slave_host_id);
1188     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1189     return;
1190   }
1191   if (slave_host_id == delegated_host_id)
1192   {
1193     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
1194     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1195     return;
1196   }
1197   op_id = GNUNET_ntohll (msg->operation_id);
1198   if (slave_host_id == GST_context->host_id)    /* Link from us */
1199   {
1200     struct Slave *slave;
1201     struct LinkControllersContext *lcc;
1202
1203     
1204     if (1 != msg->is_subordinate)
1205     {
1206       struct Neighbour *n;
1207       struct NeighbourConnectCtxt *ncc;
1208
1209       if ((delegated_host_id < neighbour_list_size) &&
1210         (NULL != neighbour_list[delegated_host_id]))
1211       {
1212         GNUNET_break (0);
1213         GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1214         return;
1215       }
1216       LOG_DEBUG ("Received request to establish a link to host %u\n",
1217                  delegated_host_id);
1218       n = GST_create_neighbour (GST_host_list[delegated_host_id]);
1219       ncc = GNUNET_malloc (sizeof (struct NeighbourConnectCtxt));
1220       ncc->n = n;
1221       ncc->op_id = op_id;
1222       ncc->client = client;
1223       GNUNET_SERVER_client_keep (client);      
1224       ncc->nh = GST_neighbour_get_connection (n, neighbour_connect_cb, ncc);
1225       ncc->timeout_task = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1226                                                         &timeout_neighbour_connect,
1227                                                         ncc);
1228       GNUNET_CONTAINER_DLL_insert_tail (ncc_head, ncc_tail, ncc);      
1229       GNUNET_SERVER_receive_done (client, GNUNET_OK);
1230       return;
1231     }
1232     if ((delegated_host_id < GST_slave_list_size) &&
1233         (NULL != GST_slave_list[delegated_host_id]))
1234     {
1235       GNUNET_break (0);
1236       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1237       return;
1238     }
1239     LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1240                delegated_host_id);
1241     slave = GNUNET_malloc (sizeof (struct Slave));
1242     slave->host_id = delegated_host_id;
1243     slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
1244     slave_list_add (slave);
1245     lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
1246     lcc->operation_id = op_id;
1247     GNUNET_SERVER_client_keep (client);
1248     lcc->client = client;
1249     slave->lcc = lcc;
1250     slave->controller_proc =
1251         GNUNET_TESTBED_controller_start (GST_context->master_ip,
1252                                          GST_host_list[slave->host_id],
1253                                          &slave_status_cb, slave);
1254     new_route = GNUNET_malloc (sizeof (struct Route));
1255     new_route->dest = delegated_host_id;
1256     new_route->thru = GST_context->host_id;
1257     route_list_add (new_route);
1258     return;
1259   }
1260
1261   /* Route the request */
1262   if (slave_host_id >= route_list_size)
1263   {
1264     LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1265     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1266     return;
1267   }
1268   lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
1269   lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
1270   lcfq->lcf->delegated_host_id = delegated_host_id;
1271   lcfq->lcf->slave_host_id = slave_host_id;
1272   route = GST_find_dest_route (slave_host_id);
1273   GNUNET_assert (NULL != route);        /* because we add routes carefully */
1274   GNUNET_assert (route->dest < GST_slave_list_size);
1275   GNUNET_assert (NULL != GST_slave_list[route->dest]);
1276   lcfq->lcf->is_subordinate = msg->is_subordinate;
1277   lcfq->lcf->state = INIT;
1278   lcfq->lcf->operation_id = op_id;
1279   lcfq->lcf->gateway = GST_slave_list[route->dest];
1280   GNUNET_SERVER_client_keep (client);
1281   lcfq->lcf->client = client;
1282   if (NULL == lcfq_head)
1283   {
1284     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1285     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1286     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
1287   }
1288   else
1289     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1290   /* FIXME: Adding a new route should happen after the controllers are linked
1291    * successfully */
1292   if (1 != msg->is_subordinate)
1293   {
1294     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1295     return;
1296   }
1297   if ((delegated_host_id < route_list_size) &&
1298       (NULL != route_list[delegated_host_id]))
1299   {
1300     GNUNET_break_op (0);        /* Are you trying to link delegated host twice
1301                                  * with is subordinate flag set to GNUNET_YES? */
1302     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1303     return;
1304   }
1305   new_route = GNUNET_malloc (sizeof (struct Route));
1306   new_route->dest = delegated_host_id;
1307   new_route->thru = route->dest;
1308   route_list_add (new_route);
1309   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1310 }
1311
1312
1313 /**
1314  * Cleans up the queue used for forwarding link controllers requests
1315  */
1316 void
1317 GST_free_lcfq ()
1318 {
1319   struct LCFContextQueue *lcfq;
1320   
1321   if (NULL != lcfq_head)
1322   {
1323     if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
1324     {
1325       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1326       lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1327     }
1328   }
1329   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1330   for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
1331   {
1332     GNUNET_SERVER_client_drop (lcfq->lcf->client);
1333     GNUNET_free (lcfq->lcf);
1334     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
1335     GNUNET_free (lcfq);
1336   }
1337 }