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