glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed_links.c
1 /*
2   This file is part of GNUnet.
3   Copyright (C) 2008--2013 GNUnet e.V.
4
5   GNUnet is free software: you can redistribute it and/or modify it
6   under the terms of the GNU Affero General Public License as published
7   by the Free Software Foundation, either version 3 of the License,
8   or (at your 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   Affero General Public License for more details.
14 */
15
16 /**
17  * @file testbed/gnunet-service-testbed_links.c
18  * @brief TESTBED service components that deals with starting slave controllers
19  *          and establishing lateral links between controllers
20  * @author Sree Harsha Totakura
21  */
22
23 #include "gnunet-service-testbed.h"
24
25 /**
26  * Redefine LOG with a changed log component string
27  */
28 #ifdef LOG
29 #undef LOG
30 #endif
31 #define LOG(kind,...)                                   \
32   GNUNET_log_from (kind, "testbed-links", __VA_ARGS__)
33
34 /**
35  * The event mask for the events we listen from sub-controllers
36  */
37 #define EVENT_MASK (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED)
38
39
40 /**
41  * States of LCFContext
42  */
43 enum LCFContextState
44 {
45   /**
46    * The Context has been initialized; Nothing has been done on it
47    */
48   INIT,
49
50   /**
51    * Delegated host has been registered at the forwarding controller
52    */
53   DELEGATED_HOST_REGISTERED,
54
55   /**
56    * The slave host has been registred at the forwarding controller
57    */
58   SLAVE_HOST_REGISTERED,
59
60   /**
61    * The context has been finished (may have error)
62    */
63   FINISHED
64 };
65
66
67 /**
68  * Link controllers request forwarding context
69  */
70 struct LCFContext
71 {
72   /**
73    * The LCFContext
74    */
75   struct LCFContext *next;
76
77   /**
78    * The LCFContext
79    */
80   struct LCFContext *prev;
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_SERVICE_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   struct GNUNET_SCHEDULER_Task *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  * Notification context to be used to notify when connection to the neighbour's
132  * controller is opened
133  */
134 struct NeighbourConnectNotification
135 {
136   /**
137    * DLL next for inclusion in neighbour's list of notification requests
138    */
139   struct NeighbourConnectNotification *next;
140
141   /**
142    * DLL prev
143    */
144   struct NeighbourConnectNotification *prev;
145
146   /**
147    * The neighbour
148    */
149   struct Neighbour *n;
150
151   /**
152    * The notification callback to call when we are connect to neighbour
153    */
154   GST_NeigbourConnectNotifyCallback cb;
155
156   /**
157    * The closure for the above callback
158    */
159   void *cb_cls;
160 };
161
162
163 /**
164  * A connected controller which is not our child
165  */
166 struct Neighbour
167 {
168   /**
169    * The controller handle
170    */
171   struct GNUNET_TESTBED_Controller *controller;
172
173   /**
174    * Operation handle for opening a lateral connection to another controller.
175    * Will be NULL if the slave controller is started by this controller
176    */
177   struct GNUNET_TESTBED_Operation *conn_op;
178
179   /**
180    * DLL head for the list of notification requests
181    */
182   struct NeighbourConnectNotification *nl_head;
183
184   /**
185    * DLL tail for the list of notification requests
186    */
187   struct NeighbourConnectNotification *nl_tail;
188
189   /**
190    * Task id for the task to call notifications from the notification list
191    */
192   struct GNUNET_SCHEDULER_Task * notify_task;
193
194   /**
195    * How many references are present currently to this neighbour's connection
196    */
197   unsigned int reference_cnt;
198
199   /**
200    * Is the conn_op inactivated?
201    */
202   unsigned int inactive;
203
204   /**
205    * The id of the host this controller is running on
206    */
207   uint32_t host_id;
208 };
209
210
211 /**
212  * The neighbour list
213  */
214 static struct Neighbour **neighbour_list;
215
216 /**
217  * The size of the neighbour list
218  */
219 static unsigned int neighbour_list_size;
220
221
222 /**
223  * Context information for establishing a link to neighbour (Used is
224  * GST_handle_link_controllers()
225  */
226 struct NeighbourConnectCtxt
227 {
228   /**
229    * DLL next for inclusion in the corresponding context list
230    */
231   struct NeighbourConnectCtxt *next;
232
233   /**
234    * DLL tail
235    */
236   struct NeighbourConnectCtxt *prev;
237
238   /**
239    * The neighbour to whom connection should be made
240    */
241   struct Neighbour *n;
242
243   /**
244    * The client requesting the connection
245    */
246   struct GNUNET_SERVICE_Client *client;
247
248   /**
249    * Task to be run upon timeout
250    */
251   struct GNUNET_SCHEDULER_Task *timeout_task;
252
253   /**
254    * The notification handle associated with the neighbour's connection request
255    */
256   struct NeighbourConnectNotification *nh;
257
258   /**
259    * The id of the link-controllers operation responsible for creating this
260    * context
261    */
262   uint64_t op_id;
263 };
264
265 /**
266  * DLL head for the list of neighbour connect contexts
267  */
268 struct NeighbourConnectCtxt *ncc_head;
269
270 /**
271  * DLL tail for the list of neighbour connect contexts
272  */
273 struct NeighbourConnectCtxt *ncc_tail;
274
275 /**
276  * A list of directly linked neighbours
277  */
278 struct Slave **GST_slave_list;
279
280 /**
281  * The size of directly linked neighbours list
282  */
283 unsigned int GST_slave_list_size;
284
285 /**
286  * A list of routes
287  */
288 static struct Route **route_list;
289
290 /**
291  * The LCF queue
292  */
293 static struct LCFContext *lcf_head;
294
295 /**
296  * The tail for the LCF queue
297  */
298 static struct LCFContext *lcf_tail;
299
300 /**
301  * The lcf_task handle
302  */
303 static struct GNUNET_SCHEDULER_Task * lcf_proc_task_id;
304
305 /**
306  * The size of the route list
307  */
308 static unsigned int route_list_size;
309
310
311 /**
312  * Adds a slave to the slave array
313  *
314  * @param slave the slave controller to add
315  */
316 static void
317 slave_list_add (struct Slave *slave)
318 {
319   if (slave->host_id >= GST_slave_list_size)
320     GST_array_grow_large_enough (GST_slave_list,
321                                  GST_slave_list_size,
322                                  slave->host_id);
323   GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
324   GST_slave_list[slave->host_id] = slave;
325 }
326
327
328 /**
329  * Clean up all forwarded operation overlay context matching the
330  * client given in @a cls.
331  *
332  * @param cls a `struct GNUNET_SERVICE_Client *` to match
333  * @param key unused
334  * @param value the `struct RegisteredHostContext` to search for @a cls
335  * @return #GNUNET_OK (continue iterating)
336  */
337 static int
338 drop_client_entries (void *cls,
339                      const struct GNUNET_HashCode *key,
340                      void *value)
341 {
342   struct GNUNET_SERVICE_Client *client = cls;
343   struct RegisteredHostContext *rhc = value;
344   struct ForwardedOverlayConnectContext *focc;
345   struct ForwardedOverlayConnectContext *foccn;
346
347   for (focc = rhc->focc_dll_head; NULL != focc; focc = foccn)
348   {
349     foccn = focc->next;
350     if (focc->client == client)
351       GST_cleanup_focc (focc);
352   }
353   return GNUNET_OK;
354 }
355
356
357 /**
358  * Adds a route to the route list
359  *
360  * @param route the route to add
361  */
362 static void
363 route_list_add (struct Route *route)
364 {
365   if (route->dest >= route_list_size)
366     GST_array_grow_large_enough (route_list, route_list_size, route->dest);
367   GNUNET_assert (NULL == route_list[route->dest]);
368   route_list[route->dest] = route;
369 }
370
371
372 /**
373  * Add a neighbour to the neighbour list.  Grows the neighbour list
374  * automatically.
375  *
376  * @param n the neighbour to add
377  */
378 static void
379 neighbour_list_add (struct Neighbour *n)
380 {
381   if (n->host_id >= neighbour_list_size)
382     GST_array_grow_large_enough (neighbour_list, neighbour_list_size, n->host_id);
383   GNUNET_assert (NULL == neighbour_list[n->host_id]);
384   neighbour_list[n->host_id] = n;
385 }
386
387
388 /**
389  * Cleans up the route list
390  */
391 void
392 GST_route_list_clear ()
393 {
394   unsigned int id;
395
396   for (id = 0; id < route_list_size; id++)
397     if (NULL != route_list[id])
398       GNUNET_free (route_list[id]);
399   GNUNET_free_non_null (route_list);
400   route_list = NULL;
401 }
402
403
404 /**
405  * Iterator for freeing hash map entries in a slave's reghost_map
406  *
407  * @param cls handle to the slave
408  * @param key current key code
409  * @param value value in the hash map
410  * @return #GNUNET_YES if we should continue to iterate,
411  *         #GNUNET_NO if not.
412  */
413 static int
414 reghost_free_iterator (void *cls,
415                        const struct GNUNET_HashCode *key,
416                        void *value)
417 {
418   struct Slave *slave = cls;
419   struct RegisteredHostContext *rhc = value;
420   struct ForwardedOverlayConnectContext *focc;
421
422   GNUNET_assert (GNUNET_YES ==
423                  GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
424                                                        value));
425   while (NULL != (focc = rhc->focc_dll_head))
426     GST_cleanup_focc (focc);
427   GNUNET_free (value);
428   return GNUNET_YES;
429 }
430
431
432 /**
433  * Kill a #Slave object
434  *
435  * @param slave the #Slave object
436  */
437 static void
438 kill_slave (struct Slave *slave)
439 {
440   struct HostRegistration *hr_entry;
441
442   while (NULL != (hr_entry = slave->hr_dll_head))
443   {
444     GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail,
445                                  hr_entry);
446     GNUNET_free (hr_entry);
447   }
448   if (NULL != slave->rhandle)
449     GNUNET_TESTBED_cancel_registration (slave->rhandle);
450   GNUNET_assert (GNUNET_SYSERR !=
451                  GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map,
452                                                         reghost_free_iterator,
453                                                         slave));
454   GNUNET_CONTAINER_multihashmap_destroy (slave->reghost_map);
455   if (NULL != slave->controller)
456     GNUNET_TESTBED_controller_disconnect (slave->controller);
457   if (NULL != slave->controller_proc)
458   {
459     LOG_DEBUG ("Stopping a slave\n");
460     GNUNET_TESTBED_controller_kill_ (slave->controller_proc);
461   }
462 }
463
464
465 /**
466  * Destroy a #Slave object
467  *
468  * @param slave the #Slave object
469  */
470 static void
471 destroy_slave (struct Slave *slave)
472 {
473   if (NULL != slave->controller_proc)
474   {
475     GNUNET_TESTBED_controller_destroy_ (slave->controller_proc);
476     LOG_DEBUG ("Slave stopped\n");
477   }
478   GST_slave_list[slave->host_id] = NULL;
479   GNUNET_free (slave);
480 }
481
482
483 /**
484  * Cleans up the slave list
485  */
486 void
487 GST_slave_list_clear ()
488 {
489   struct Slave *slave;
490   unsigned int id;
491
492   for (id = 0; id < GST_slave_list_size; id++)
493   {
494     slave = GST_slave_list[id];
495     if (NULL == slave)
496       continue;
497     kill_slave (slave);
498   }
499   for (id = 0; id < GST_slave_list_size; id++)
500   {
501     slave = GST_slave_list[id];
502     if (NULL == slave)
503       continue;
504     destroy_slave (slave);
505   }
506   GNUNET_free_non_null (GST_slave_list);
507   GST_slave_list = NULL;
508 }
509
510
511 /**
512  * Finds the route with directly connected host as destination through which
513  * the destination host can be reached
514  *
515  * @param host_id the id of the destination host
516  * @return the route with directly connected destination host; NULL if no route
517  *           is found
518  */
519 struct Route *
520 GST_find_dest_route (uint32_t host_id)
521 {
522   struct Route *route;
523
524   if (route_list_size <= host_id)
525     return NULL;
526   while (NULL != (route = route_list[host_id]))
527   {
528     if (route->thru == GST_context->host_id)
529       break;
530     host_id = route->thru;
531   }
532   return route;
533 }
534
535
536 /**
537  * Function to send a failure reponse for controller link operation
538  *
539  * @param client the client to send the message to
540  * @param operation_id the operation ID of the controller link request
541  * @param cfg the configuration with which the delegated controller is started.
542  *          Can be NULL if the delegated controller is not started but just
543  *          linked to.
544  * @param emsg set to an error message explaining why the controller link
545  *          failed.  Setting this to NULL signifies success.  !This should be
546  *          NULL if cfg is set!
547  */
548 static void
549 send_controller_link_response (struct GNUNET_SERVICE_Client *client,
550                                uint64_t operation_id,
551                                const struct GNUNET_CONFIGURATION_Handle *cfg,
552                                const char *emsg)
553 {
554   struct GNUNET_MQ_Envelope *env;
555   struct GNUNET_TESTBED_ControllerLinkResponse *msg;
556   char *xconfig;
557   size_t config_size;
558   size_t xconfig_size;
559   uint16_t msize;
560
561   GNUNET_assert ((NULL == cfg) || (NULL == emsg));
562   xconfig = NULL;
563   xconfig_size = 0;
564   config_size = 0;
565   msize = 0;
566   if (NULL != cfg)
567   {
568     xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
569                                             &config_size,
570                                             &xconfig_size);
571     msize += xconfig_size;
572   }
573   if (NULL != emsg)
574     msize += strlen (emsg);
575   env = GNUNET_MQ_msg_extra (msg,
576                              msize,
577                              GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
578   if (NULL == emsg)
579     msg->success = htons (GNUNET_YES);
580   msg->operation_id = GNUNET_htonll (operation_id);
581   msg->config_size = htons ((uint16_t) config_size);
582   if (NULL != xconfig)
583   {
584     GNUNET_memcpy (&msg[1],
585                    xconfig,
586                    xconfig_size);
587     GNUNET_free (xconfig);
588   }
589   if (NULL != emsg)
590     GNUNET_memcpy (&msg[1],
591                    emsg,
592                    strlen (emsg));
593   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
594                   env);
595 }
596
597
598 /**
599  * The  Link Controller forwarding task
600  *
601  * @param cls the LCFContext
602  */
603 static void
604 lcf_proc_task (void *cls);
605
606
607 /**
608  * Completion callback for host registrations while forwarding Link Controller messages
609  *
610  * @param cls the LCFContext
611  * @param emsg the error message; NULL if host registration is successful
612  */
613 static void
614 lcf_proc_cc (void *cls,
615              const char *emsg)
616 {
617   struct LCFContext *lcf = cls;
618
619   GNUNET_assert (NULL == lcf_proc_task_id);
620   switch (lcf->state)
621   {
622   case INIT:
623     if (NULL != emsg)
624       goto registration_error;
625     lcf->state = DELEGATED_HOST_REGISTERED;
626     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
627     break;
628   case DELEGATED_HOST_REGISTERED:
629     if (NULL != emsg)
630       goto registration_error;
631     lcf->state = SLAVE_HOST_REGISTERED;
632     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
633     break;
634   default:
635     GNUNET_assert (0);          /* Shouldn't reach here */
636   }
637   return;
638
639 registration_error:
640   LOG (GNUNET_ERROR_TYPE_WARNING,
641        "Host registration failed with message: %s\n",
642        emsg);
643   lcf->state = FINISHED;
644   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
645                                                lcf);
646 }
647
648
649 /**
650  * The  Link Controller forwarding task
651  *
652  * @param cls the LCFContext
653  */
654 static void
655 lcf_proc_task (void *cls);
656
657
658 /**
659  * Task to free resources when forwarded link controllers has been timedout
660  *
661  * @param cls the LCFContext
662  */
663 static void
664 lcf_forwarded_operation_timeout (void *cls)
665 {
666   struct LCFContext *lcf = cls;
667
668   lcf->timeout_task = NULL;
669   //  GST_forwarded_operation_timeout (lcf->fopc, tc);
670   LOG (GNUNET_ERROR_TYPE_WARNING,
671        "A forwarded controller link operation has timed out\n");
672   send_controller_link_response (lcf->client,
673                                  lcf->operation_id,
674                                  NULL,
675                                  "A forwarded controller link operation has timed out\n");
676   GNUNET_assert (NULL == lcf_proc_task_id);
677   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
678                                                lcf);
679 }
680
681
682 /**
683  * The  Link Controller forwarding task
684  *
685  * @param cls the LCFContext
686  */
687 static void
688 lcf_proc_task (void *cls)
689 {
690   struct LCFContext *lcf = cls;
691
692   lcf_proc_task_id = NULL;
693   switch (lcf->state)
694   {
695   case INIT:
696     if (GNUNET_NO ==
697         GNUNET_TESTBED_is_host_registered_ (GST_host_list
698                                             [lcf->delegated_host_id],
699                                             lcf->gateway->controller))
700     {
701       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
702                                    GST_host_list[lcf->delegated_host_id]);
703     }
704     else
705     {
706       lcf->state = DELEGATED_HOST_REGISTERED;
707       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
708     }
709     break;
710   case DELEGATED_HOST_REGISTERED:
711     if (GNUNET_NO ==
712         GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
713                                             lcf->gateway->controller))
714     {
715       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
716                                    GST_host_list[lcf->slave_host_id]);
717     }
718     else
719     {
720       lcf->state = SLAVE_HOST_REGISTERED;
721       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
722     }
723     break;
724   case SLAVE_HOST_REGISTERED:
725     lcf->op = GNUNET_TESTBED_controller_link (lcf,
726                                               lcf->gateway->controller,
727                                               GST_host_list[lcf->delegated_host_id],
728                                               GST_host_list[lcf->slave_host_id],
729                                               lcf->is_subordinate);
730     lcf->timeout_task =
731         GNUNET_SCHEDULER_add_delayed (GST_timeout,
732                                       &lcf_forwarded_operation_timeout,
733                                       lcf);
734     lcf->state = FINISHED;
735     break;
736   case FINISHED:
737     if (NULL != lcf->op)
738       GNUNET_TESTBED_operation_done (lcf->op);
739     GNUNET_CONTAINER_DLL_remove (lcf_head,
740                                  lcf_tail,
741                                  lcf);
742     GNUNET_free (lcf);
743     if (NULL != lcf_head)
744       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
745                                                    lcf_head);
746   }
747 }
748
749
750 /**
751  * Callback for event from slave controllers
752  *
753  * @param cls NULL
754  * @param event information about the event
755  */
756 static void
757 slave_event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
758 {
759   struct LCFContext *lcf;
760
761   /* We currently only get here when working on LCFContexts */
762   GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
763   lcf = event->op_cls;
764   GNUNET_assert (lcf->op == event->op);
765   GNUNET_TESTBED_operation_done (lcf->op);
766   lcf->op = NULL;
767   GNUNET_assert (FINISHED == lcf->state);
768   GNUNET_assert (NULL != lcf->timeout_task);
769   GNUNET_SCHEDULER_cancel (lcf->timeout_task);
770   if (NULL == event->details.operation_finished.emsg)
771     send_controller_link_response (lcf->client, lcf->operation_id,
772                                    GNUNET_TESTBED_host_get_cfg_
773                                    (GST_host_list[lcf->delegated_host_id]),
774                                    NULL);
775   else
776     send_controller_link_response (lcf->client, lcf->operation_id,
777                                    NULL,
778                                    event->details.operation_finished.emsg);
779   GNUNET_assert (NULL == lcf_proc_task_id);
780   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
781   return;
782 }
783
784
785 /**
786  * Callback to signal successfull startup of the controller process
787  *
788  * @param cls the handle to the slave whose status is to be found here
789  * @param cfg the configuration with which the controller has been started;
790  *          NULL if status is not #GNUNET_OK
791  * @param status #GNUNET_OK if the startup is successfull; #GNUNET_SYSERR if not,
792  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
793  */
794 static void
795 slave_status_cb (void *cls,
796                  const struct GNUNET_CONFIGURATION_Handle *cfg,
797                  int status)
798 {
799   struct Slave *slave = cls;
800   struct LinkControllersContext *lcc;
801
802   lcc = slave->lcc;
803   if (GNUNET_SYSERR == status)
804   {
805     slave->controller_proc = NULL;
806     /* Stop all link controller forwarding tasks since we shutdown here anyway
807        and as these tasks they depend on the operation queues which are created
808        through GNUNET_TESTBED_controller_connect() and in kill_slave() we call
809        the destructor function GNUNET_TESTBED_controller_disconnect() */
810     GST_free_lcf ();
811     kill_slave (slave);
812     destroy_slave (slave);
813     slave = NULL;
814     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
815     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
816     goto clean_lcc;
817   }
818   slave->controller =
819       GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
820                                          EVENT_MASK, &slave_event_cb,
821                                          slave);
822   if (NULL != slave->controller)
823   {
824     send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
825   }
826   else
827   {
828     send_controller_link_response (lcc->client, lcc->operation_id, NULL,
829                                    "Could not connect to delegated controller");
830     kill_slave (slave);
831     destroy_slave (slave);
832     slave = NULL;
833   }
834
835  clean_lcc:
836   if (NULL != lcc)
837   {
838     if (NULL != lcc->client)
839     {
840       GNUNET_SERVICE_client_continue (lcc->client);
841       lcc->client = NULL;
842     }
843     GNUNET_free (lcc);
844   }
845   if (NULL != slave)
846     slave->lcc = NULL;
847 }
848
849
850 /**
851  * Trigger notification task if there are notification requests currently
852  * waiting in the given neighbour.  Also activates the neighbour connect operation
853  * if it was previously inactivated so that the connection to the neighbour can
854  * be re-used
855  *
856  * @param n the neighbour
857  */
858 static void
859 trigger_notifications (struct Neighbour *n);
860
861
862 /**
863  * Task to call the notification queued in the notifications list of the given
864  * neighbour
865  *
866  * @param cls the neighbour
867  */
868 static void
869 neighbour_connect_notify_task (void *cls)
870 {
871   struct Neighbour *n = cls;
872   struct NeighbourConnectNotification *h;
873
874   GNUNET_assert (NULL != (h = n->nl_head));
875   GNUNET_assert (NULL != n->notify_task);
876   n->notify_task = NULL;
877   GNUNET_assert (NULL != n->controller);
878   GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
879   trigger_notifications (n);
880   h->cb (h->cb_cls, n->controller);
881   GNUNET_free (h);
882 }
883
884
885 /**
886  * Trigger notification task if there are notification requests currently
887  * waiting in the given neighbour.  Also activates the neighbour connect operation
888  * if it was previously inactivated so that the connection to the neighbour can
889  * be re-used
890  *
891  * @param n the neighbour
892  */
893 static void
894 trigger_notifications (struct Neighbour *n)
895 {
896   GNUNET_assert (NULL != n->conn_op);
897   if (NULL == n->nl_head)
898     return;
899   if (NULL == n->controller)
900     return;
901   if (NULL != n->notify_task)
902     return;
903   if (1 == n->inactive)
904   {
905     GNUNET_assert (0 == n->reference_cnt);
906     GNUNET_TESTBED_operation_activate_ (n->conn_op);
907     n->inactive = 0;
908   }
909   n->reference_cnt++;
910   n->notify_task =
911       GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n);
912 }
913
914
915 /**
916  * Callback to be called when the neighbour connect operation is started.  The
917  * connection to the neigbour is opened here and any pending notifications are
918  * trigger.
919  *
920  * @param cls the neighbour
921  */
922 static void
923 opstart_neighbour_conn (void *cls)
924 {
925   struct Neighbour *n = cls;
926
927   GNUNET_assert (NULL != n->conn_op);
928   GNUNET_assert (NULL == n->controller);
929   LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
930   n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
931                                                      EVENT_MASK,
932                                                      &slave_event_cb,
933                                                      NULL);
934   trigger_notifications (n);
935 }
936
937
938 /**
939  * Callback to be called when the neighbour connect operation is released
940  *
941  * @param cls the neighbour
942  */
943 static void
944 oprelease_neighbour_conn (void *cls)
945 {
946    struct Neighbour *n = cls;
947
948    GNUNET_assert (0 == n->reference_cnt);
949    GNUNET_assert (NULL == n->notify_task);
950    GNUNET_assert (NULL == n->nl_head);
951    if (NULL != n->controller)
952    {
953      LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
954      GNUNET_TESTBED_controller_disconnect (n->controller);
955      n->controller = NULL;
956    }
957    n->conn_op = NULL;
958    n->inactive = 0;
959 }
960
961
962 /**
963  * Try to open a connection to the given neigbour.  If the connection is open
964  * already, then it is re-used.  If not, the request is queued in the operation
965  * queues responsible for bounding the total number of file descriptors.  The
966  * actual connection will happen when the operation queue marks the
967  * corresponding operation as active.
968  *
969  * @param n the neighbour to open a connection to
970  * @param cb the notification callback to call when the connection is opened
971  * @param cb_cls the closure for the above callback
972  */
973 struct NeighbourConnectNotification *
974 GST_neighbour_get_connection (struct Neighbour *n,
975                               GST_NeigbourConnectNotifyCallback cb,
976                               void *cb_cls)
977 {
978   struct NeighbourConnectNotification *h;
979
980   GNUNET_assert (NULL != cb);
981   LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
982              n->host_id);
983   h = GNUNET_new (struct NeighbourConnectNotification);
984   h->n = n;
985   h->cb  = cb;
986   h->cb_cls = cb_cls;
987   GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
988   if (NULL == n->conn_op)
989   {
990     GNUNET_assert (NULL == n->controller);
991     n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
992                                                    &oprelease_neighbour_conn);
993     GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
994     GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
995     return h;
996   }
997   trigger_notifications (n);
998   return h;
999 }
1000
1001
1002 /**
1003  * Cancel the request for opening a connection to the neighbour
1004  *
1005  * @param h the notification handle
1006  */
1007 void
1008 GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
1009 {
1010   struct Neighbour *n;
1011   int cleanup_task;
1012
1013   n = h->n;
1014   cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
1015   GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
1016   GNUNET_free (h);
1017   if (GNUNET_NO == cleanup_task)
1018     return;
1019   if (NULL == n->notify_task)
1020     return;
1021   GNUNET_assert (0 < n->reference_cnt);
1022   n->reference_cnt--;
1023   GNUNET_SCHEDULER_cancel (n->notify_task);
1024   n->notify_task = NULL;
1025   if (NULL == n->nl_head)
1026   {
1027     if ( (0 == n->reference_cnt) && (0 == n->inactive) )
1028     {
1029       n->inactive = 1;
1030       GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1031     }
1032     return;
1033   }
1034   trigger_notifications (n);
1035 }
1036
1037
1038 /**
1039  * Release the connection to the neighbour.  The actual connection will be
1040  * closed if connections to other neighbour are waiting (to maintain a bound on
1041  * the total number of connections that are open).
1042  *
1043  * @param n the neighbour whose connection can be closed
1044  */
1045 void
1046 GST_neighbour_release_connection (struct Neighbour *n)
1047 {
1048   GNUNET_assert (0 == n->inactive);
1049   GNUNET_assert (0 < n->reference_cnt);
1050   n->reference_cnt--;
1051   if (0 == n->reference_cnt)
1052   {
1053     n->inactive = 1;
1054     GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1055   }
1056 }
1057
1058
1059 /**
1060  * Cleanup neighbour connect contexts
1061  *
1062  * @param ncc the neighbour connect context to cleanup
1063  */
1064 static void
1065 cleanup_ncc (struct NeighbourConnectCtxt *ncc)
1066 {
1067   if (NULL != ncc->nh)
1068     GST_neighbour_get_connection_cancel (ncc->nh);
1069   if (NULL != ncc->timeout_task)
1070     GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1071   GNUNET_CONTAINER_DLL_remove (ncc_head,
1072                                ncc_tail,
1073                                ncc);
1074   GNUNET_free (ncc);
1075 }
1076
1077
1078 /**
1079  * Cleans up the neighbour list
1080  */
1081 void
1082 GST_neighbour_list_clean ()
1083 {
1084   struct Neighbour *n;
1085   unsigned int id;
1086
1087   for (id = 0; id < neighbour_list_size; id++)
1088   {
1089     if (NULL == (n = neighbour_list[id]))
1090       continue;
1091     if (NULL != n->conn_op)
1092       GNUNET_TESTBED_operation_release_ (n->conn_op);
1093     GNUNET_free (n);
1094     neighbour_list[id] = NULL;
1095   }
1096   GNUNET_free_non_null (neighbour_list);
1097 }
1098
1099
1100 /**
1101  * Get a neighbour from the neighbour list
1102  *
1103  * @param id the index of the neighbour in the neighbour list
1104  * @return the Neighbour; NULL if the given index in invalid (index greater than
1105  *           the list size or neighbour at that index is NULL)
1106  */
1107 struct Neighbour *
1108 GST_get_neighbour (uint32_t id)
1109 {
1110   if (neighbour_list_size <= id)
1111     return NULL;
1112   return neighbour_list[id];
1113 }
1114
1115
1116 /**
1117  * Function to cleanup the neighbour connect contexts
1118  */
1119 void
1120 GST_free_nccq ()
1121 {
1122   while (NULL != ncc_head)
1123     cleanup_ncc (ncc_head);
1124 }
1125
1126
1127 /**
1128  * Task to be run upon timeout while attempting to connect to the neighbour
1129  *
1130  * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1131  */
1132 static void
1133 timeout_neighbour_connect (void *cls)
1134 {
1135  struct NeighbourConnectCtxt *ncc = cls;
1136
1137  ncc->timeout_task = NULL;
1138  send_controller_link_response (ncc->client,
1139                                 ncc->op_id,
1140                                 NULL,
1141                                 "Could not connect to delegated controller");
1142  cleanup_ncc (ncc);
1143 }
1144
1145
1146 /**
1147  * Callback called when a connection to the neighbour is made
1148  *
1149  * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1150  * @param c the handle the neighbour's controller
1151  */
1152 static void
1153 neighbour_connect_cb (void *cls,
1154                       struct GNUNET_TESTBED_Controller *c)
1155 {
1156   struct NeighbourConnectCtxt *ncc = cls;
1157
1158   GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1159   ncc->timeout_task = NULL;
1160   ncc->nh = NULL;
1161   GST_neighbour_release_connection (ncc->n);
1162   send_controller_link_response (ncc->client,
1163                                  ncc->op_id,
1164                                  NULL,
1165                                  NULL);
1166   cleanup_ncc (ncc);
1167 }
1168
1169
1170 /**
1171  * Function to create a neigbour and add it into the neighbour list
1172  *
1173  * @param host the host of the neighbour
1174  */
1175 struct Neighbour *
1176 GST_create_neighbour (struct GNUNET_TESTBED_Host *host)
1177 {
1178   struct Neighbour *n;
1179
1180   n = GNUNET_new (struct Neighbour);
1181   n->host_id = GNUNET_TESTBED_host_get_id_ (host);
1182   neighbour_list_add (n);   /* just add; connect on-demand */
1183   return n;
1184 }
1185
1186
1187 /**
1188  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1189  *
1190  * @param cls identification of the client
1191  * @param msg the actual message
1192  */
1193 void
1194 handle_link_controllers (void *cls,
1195                          const struct GNUNET_TESTBED_ControllerLinkRequest *msg)
1196 {
1197   struct GNUNET_SERVICE_Client *client = cls;
1198   struct LCFContext *lcf;
1199   struct Route *route;
1200   struct Route *new_route;
1201   uint64_t op_id;
1202   uint32_t delegated_host_id;
1203   uint32_t slave_host_id;
1204
1205   if (NULL == GST_context)
1206   {
1207     GNUNET_break (0);
1208     GNUNET_SERVICE_client_drop (client);
1209     return;
1210   }
1211   delegated_host_id = ntohl (msg->delegated_host_id);
1212   if (delegated_host_id == GST_context->host_id)
1213   {
1214     GNUNET_break (0);
1215     LOG (GNUNET_ERROR_TYPE_WARNING,
1216          "Trying to link ourselves\n");
1217     GNUNET_SERVICE_client_drop (client);
1218     return;
1219   }
1220   if ((delegated_host_id >= GST_host_list_size) ||
1221       (NULL == GST_host_list[delegated_host_id]))
1222   {
1223     LOG (GNUNET_ERROR_TYPE_WARNING,
1224          "Delegated host %u not registered with us\n",
1225          delegated_host_id);
1226     GNUNET_SERVICE_client_drop (client);
1227     return;
1228   }
1229   slave_host_id = ntohl (msg->slave_host_id);
1230   if ((slave_host_id >= GST_host_list_size) ||
1231       (NULL == GST_host_list[slave_host_id]))
1232   {
1233     LOG (GNUNET_ERROR_TYPE_WARNING,
1234          "Slave host %u not registered with us\n",
1235          slave_host_id);
1236     GNUNET_SERVICE_client_drop (client);
1237     return;
1238   }
1239   if (slave_host_id == delegated_host_id)
1240   {
1241     LOG (GNUNET_ERROR_TYPE_WARNING,
1242          "Slave and delegated host are same\n");
1243     GNUNET_SERVICE_client_drop (client);
1244     return;
1245   }
1246   op_id = GNUNET_ntohll (msg->operation_id);
1247   if (slave_host_id == GST_context->host_id)    /* Link from us */
1248   {
1249     struct Slave *slave;
1250     struct LinkControllersContext *lcc;
1251
1252     if (1 != msg->is_subordinate)
1253     {
1254       struct Neighbour *n;
1255       struct NeighbourConnectCtxt *ncc;
1256
1257       if ((delegated_host_id < neighbour_list_size) &&
1258         (NULL != neighbour_list[delegated_host_id]))
1259       {
1260         GNUNET_break (0);
1261         GNUNET_SERVICE_client_drop (client);
1262         return;
1263       }
1264       LOG_DEBUG ("Received request to establish a link to host %u\n",
1265                  delegated_host_id);
1266       n = GST_create_neighbour (GST_host_list[delegated_host_id]);
1267       ncc = GNUNET_new (struct NeighbourConnectCtxt);
1268       ncc->n = n;
1269       ncc->op_id = op_id;
1270       ncc->client = client;
1271       ncc->nh = GST_neighbour_get_connection (n,
1272                                               &neighbour_connect_cb,
1273                                               ncc);
1274       ncc->timeout_task
1275         = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1276                                         &timeout_neighbour_connect,
1277                                         ncc);
1278       GNUNET_CONTAINER_DLL_insert_tail (ncc_head,
1279                                         ncc_tail,
1280                                         ncc);
1281       GNUNET_SERVICE_client_continue (client);
1282       return;
1283     }
1284     if ( (delegated_host_id < GST_slave_list_size) &&
1285          (NULL != GST_slave_list[delegated_host_id]) )
1286     {
1287       GNUNET_break (0);
1288       GNUNET_SERVICE_client_drop (client);
1289       return;
1290     }
1291     LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1292                delegated_host_id);
1293     slave = GNUNET_new (struct Slave);
1294     slave->host_id = delegated_host_id;
1295     slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100,
1296                                                                GNUNET_NO);
1297     slave_list_add (slave);
1298     lcc = GNUNET_new (struct LinkControllersContext);
1299     lcc->operation_id = op_id;
1300     lcc->client = client;
1301     slave->lcc = lcc;
1302     slave->controller_proc
1303       = GNUNET_TESTBED_controller_start (GST_context->master_ip,
1304                                          GST_host_list[slave->host_id],
1305                                          &slave_status_cb,
1306                                          slave);
1307     new_route = GNUNET_new (struct Route);
1308     new_route->dest = delegated_host_id;
1309     new_route->thru = GST_context->host_id;
1310     route_list_add (new_route);
1311     return;
1312   }
1313
1314   /* Route the request */
1315   if (slave_host_id >= route_list_size)
1316   {
1317     LOG (GNUNET_ERROR_TYPE_WARNING,
1318          "No route towards slave host");
1319     GNUNET_SERVICE_client_drop (client);
1320     return;
1321   }
1322   lcf = GNUNET_new (struct LCFContext);
1323   lcf->delegated_host_id = delegated_host_id;
1324   lcf->slave_host_id = slave_host_id;
1325   route = GST_find_dest_route (slave_host_id);
1326   GNUNET_assert (NULL != route);        /* because we add routes carefully */
1327   GNUNET_assert (route->dest < GST_slave_list_size);
1328   GNUNET_assert (NULL != GST_slave_list[route->dest]);
1329   lcf->is_subordinate = msg->is_subordinate;
1330   lcf->state = INIT;
1331   lcf->operation_id = op_id;
1332   lcf->gateway = GST_slave_list[route->dest];
1333   lcf->client = client;
1334   if (NULL == lcf_head)
1335   {
1336     GNUNET_assert (NULL == lcf_proc_task_id);
1337     GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1338                                       lcf_tail,
1339                                       lcf);
1340     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
1341                                                  lcf);
1342   }
1343   else
1344   {
1345     GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1346                                       lcf_tail,
1347                                       lcf);
1348   }
1349   /* FIXME: Adding a new route should happen after the controllers are linked
1350    * successfully */
1351   if (1 != msg->is_subordinate)
1352   {
1353     GNUNET_SERVICE_client_continue (client);
1354     return;
1355   }
1356   if ( (delegated_host_id < route_list_size) &&
1357        (NULL != route_list[delegated_host_id]) )
1358   {
1359     GNUNET_break_op (0);        /* Are you trying to link delegated host twice
1360                                  * with is subordinate flag set to GNUNET_YES? */
1361     GNUNET_SERVICE_client_drop (client);
1362     return;
1363   }
1364   new_route = GNUNET_new (struct Route);
1365   new_route->dest = delegated_host_id;
1366   new_route->thru = route->dest;
1367   route_list_add (new_route);
1368   GNUNET_SERVICE_client_continue (client);
1369 }
1370
1371
1372 /**
1373  * Clean up @a client handle if we stored any via #handle_link_controllers(),
1374  * the given client disconnected.
1375  *
1376  * @param client the client that is history
1377  */
1378 void
1379 GST_link_notify_disconnect (struct GNUNET_SERVICE_Client *client)
1380 {
1381   struct NeighbourConnectCtxt *ncc;
1382   struct NeighbourConnectCtxt *nccn;
1383   struct LCFContext *lcf;
1384   struct LCFContext *lcfn;
1385
1386   for (ncc = ncc_head; NULL != ncc; ncc = nccn)
1387   {
1388     nccn = ncc->next;
1389     if (ncc->client == client)
1390       cleanup_ncc (ncc);
1391   }
1392   for (unsigned int i=0;i<GST_slave_list_size;i++)
1393   {
1394     struct Slave *slave = GST_slave_list[i];
1395     struct LinkControllersContext *lcc;
1396
1397     if (NULL == slave)
1398       continue;
1399     GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map,
1400                                            &drop_client_entries,
1401                                            client);
1402     lcc = slave->lcc;
1403     if (NULL == lcc)
1404       continue;
1405     if (lcc->client == client)
1406     {
1407       slave->lcc = NULL;
1408       GNUNET_free (lcc);
1409     }
1410   }
1411   for (lcf = lcf_head; NULL != lcf; lcf = lcfn)
1412   {
1413     lcfn = lcf->next;
1414     if ( (NULL != lcf) &&
1415          (client == lcf->client) )
1416     {
1417       if (NULL != lcf->op)
1418         GNUNET_TESTBED_operation_done (lcf->op);
1419       GNUNET_CONTAINER_DLL_remove (lcf_head,
1420                                    lcf_tail,
1421                                    lcf);
1422       GNUNET_free (lcf);
1423     }
1424   }
1425 }
1426
1427
1428 /**
1429  * Cleans up the queue used for forwarding link controllers requests
1430  */
1431 void
1432 GST_free_lcf ()
1433 {
1434   struct LCFContext *lcf;
1435
1436   if (NULL != lcf_head)
1437   {
1438     if (NULL != lcf_proc_task_id)
1439     {
1440       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1441       lcf_proc_task_id = NULL;
1442     }
1443   }
1444   GNUNET_assert (NULL == lcf_proc_task_id);
1445   for (lcf = lcf_head; NULL != lcf; lcf = lcf_head)
1446   {
1447     if (NULL != lcf->op)
1448       GNUNET_TESTBED_operation_done (lcf->op);
1449     if (NULL != lcf->timeout_task)
1450       GNUNET_SCHEDULER_cancel (lcf->timeout_task);
1451     GNUNET_CONTAINER_DLL_remove (lcf_head,
1452                                  lcf_tail,
1453                                  lcf);
1454     GNUNET_free (lcf);
1455   }
1456 }