src: for every AGPL3.0 file, add SPDX identifier.
[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 /**
136  * Notification context to be used to notify when connection to the neighbour's
137  * controller is opened
138  */
139 struct NeighbourConnectNotification
140 {
141   /**
142    * DLL next for inclusion in neighbour's list of notification requests
143    */
144   struct NeighbourConnectNotification *next;
145
146   /**
147    * DLL prev
148    */
149   struct NeighbourConnectNotification *prev;
150
151   /**
152    * The neighbour
153    */
154   struct Neighbour *n;
155
156   /**
157    * The notification callback to call when we are connect to neighbour
158    */
159   GST_NeigbourConnectNotifyCallback cb;
160
161   /**
162    * The closure for the above callback
163    */
164   void *cb_cls;
165 };
166
167
168 /**
169  * A connected controller which is not our child
170  */
171 struct Neighbour
172 {
173   /**
174    * The controller handle
175    */
176   struct GNUNET_TESTBED_Controller *controller;
177
178   /**
179    * Operation handle for opening a lateral connection to another controller.
180    * Will be NULL if the slave controller is started by this controller
181    */
182   struct GNUNET_TESTBED_Operation *conn_op;
183
184   /**
185    * DLL head for the list of notification requests
186    */
187   struct NeighbourConnectNotification *nl_head;
188
189   /**
190    * DLL tail for the list of notification requests
191    */
192   struct NeighbourConnectNotification *nl_tail;
193
194   /**
195    * Task id for the task to call notifications from the notification list
196    */
197   struct GNUNET_SCHEDULER_Task * notify_task;
198
199   /**
200    * How many references are present currently to this neighbour's connection
201    */
202   unsigned int reference_cnt;
203
204   /**
205    * Is the conn_op inactivated?
206    */
207   unsigned int inactive;
208
209   /**
210    * The id of the host this controller is running on
211    */
212   uint32_t host_id;
213 };
214
215
216 /**
217  * The neighbour list
218  */
219 static struct Neighbour **neighbour_list;
220
221 /**
222  * The size of the neighbour list
223  */
224 static unsigned int neighbour_list_size;
225
226
227 /**
228  * Context information for establishing a link to neighbour (Used is
229  * GST_handle_link_controllers()
230  */
231 struct NeighbourConnectCtxt
232 {
233   /**
234    * DLL next for inclusion in the corresponding context list
235    */
236   struct NeighbourConnectCtxt *next;
237
238   /**
239    * DLL tail
240    */
241   struct NeighbourConnectCtxt *prev;
242
243   /**
244    * The neighbour to whom connection should be made
245    */
246   struct Neighbour *n;
247
248   /**
249    * The client requesting the connection
250    */
251   struct GNUNET_SERVICE_Client *client;
252
253   /**
254    * Task to be run upon timeout
255    */
256   struct GNUNET_SCHEDULER_Task *timeout_task;
257
258   /**
259    * The notification handle associated with the neighbour's connection request
260    */
261   struct NeighbourConnectNotification *nh;
262
263   /**
264    * The id of the link-controllers operation responsible for creating this
265    * context
266    */
267   uint64_t op_id;
268 };
269
270 /**
271  * DLL head for the list of neighbour connect contexts
272  */
273 struct NeighbourConnectCtxt *ncc_head;
274
275 /**
276  * DLL tail for the list of neighbour connect contexts
277  */
278 struct NeighbourConnectCtxt *ncc_tail;
279
280 /**
281  * A list of directly linked neighbours
282  */
283 struct Slave **GST_slave_list;
284
285 /**
286  * The size of directly linked neighbours list
287  */
288 unsigned int GST_slave_list_size;
289
290 /**
291  * A list of routes
292  */
293 static struct Route **route_list;
294
295 /**
296  * The LCF queue
297  */
298 static struct LCFContext *lcf_head;
299
300 /**
301  * The tail for the LCF queue
302  */
303 static struct LCFContext *lcf_tail;
304
305 /**
306  * The lcf_task handle
307  */
308 static struct GNUNET_SCHEDULER_Task * lcf_proc_task_id;
309
310 /**
311  * The size of the route list
312  */
313 static unsigned int route_list_size;
314
315
316 /**
317  * Adds a slave to the slave array
318  *
319  * @param slave the slave controller to add
320  */
321 static void
322 slave_list_add (struct Slave *slave)
323 {
324   if (slave->host_id >= GST_slave_list_size)
325     GST_array_grow_large_enough (GST_slave_list,
326                                  GST_slave_list_size,
327                                  slave->host_id);
328   GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
329   GST_slave_list[slave->host_id] = slave;
330 }
331
332
333 /**
334  * Clean up all forwarded operation overlay context matching the
335  * client given in @a cls.
336  *
337  * @param cls a `struct GNUNET_SERVICE_Client *` to match
338  * @param key unused
339  * @param value the `struct RegisteredHostContext` to search for @a cls
340  * @return #GNUNET_OK (continue iterating)
341  */
342 static int
343 drop_client_entries (void *cls,
344                      const struct GNUNET_HashCode *key,
345                      void *value)
346 {
347   struct GNUNET_SERVICE_Client *client = cls;
348   struct RegisteredHostContext *rhc = value;
349   struct ForwardedOverlayConnectContext *focc;
350   struct ForwardedOverlayConnectContext *foccn;
351
352   for (focc = rhc->focc_dll_head; NULL != focc; focc = foccn)
353   {
354     foccn = focc->next;
355     if (focc->client == client)
356       GST_cleanup_focc (focc);
357   }
358   return GNUNET_OK;
359 }
360
361
362 /**
363  * Adds a route to the route list
364  *
365  * @param route the route to add
366  */
367 static void
368 route_list_add (struct Route *route)
369 {
370   if (route->dest >= route_list_size)
371     GST_array_grow_large_enough (route_list, route_list_size, route->dest);
372   GNUNET_assert (NULL == route_list[route->dest]);
373   route_list[route->dest] = route;
374 }
375
376
377 /**
378  * Add a neighbour to the neighbour list.  Grows the neighbour list
379  * automatically.
380  *
381  * @param n the neighbour to add
382  */
383 static void
384 neighbour_list_add (struct Neighbour *n)
385 {
386   if (n->host_id >= neighbour_list_size)
387     GST_array_grow_large_enough (neighbour_list, neighbour_list_size, 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   case DELEGATED_HOST_REGISTERED:
634     if (NULL != emsg)
635       goto registration_error;
636     lcf->state = SLAVE_HOST_REGISTERED;
637     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
638     break;
639   default:
640     GNUNET_assert (0);          /* Shouldn't reach here */
641   }
642   return;
643
644 registration_error:
645   LOG (GNUNET_ERROR_TYPE_WARNING,
646        "Host registration failed with message: %s\n",
647        emsg);
648   lcf->state = FINISHED;
649   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
650                                                lcf);
651 }
652
653
654 /**
655  * The  Link Controller forwarding task
656  *
657  * @param cls the LCFContext
658  */
659 static void
660 lcf_proc_task (void *cls);
661
662
663 /**
664  * Task to free resources when forwarded link controllers has been timedout
665  *
666  * @param cls the LCFContext
667  */
668 static void
669 lcf_forwarded_operation_timeout (void *cls)
670 {
671   struct LCFContext *lcf = cls;
672
673   lcf->timeout_task = NULL;
674   //  GST_forwarded_operation_timeout (lcf->fopc, tc);
675   LOG (GNUNET_ERROR_TYPE_WARNING,
676        "A forwarded controller link operation has timed out\n");
677   send_controller_link_response (lcf->client,
678                                  lcf->operation_id,
679                                  NULL,
680                                  "A forwarded controller link operation has timed out\n");
681   GNUNET_assert (NULL == lcf_proc_task_id);
682   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
683                                                lcf);
684 }
685
686
687 /**
688  * The  Link Controller forwarding task
689  *
690  * @param cls the LCFContext
691  */
692 static void
693 lcf_proc_task (void *cls)
694 {
695   struct LCFContext *lcf = cls;
696
697   lcf_proc_task_id = NULL;
698   switch (lcf->state)
699   {
700   case INIT:
701     if (GNUNET_NO ==
702         GNUNET_TESTBED_is_host_registered_ (GST_host_list
703                                             [lcf->delegated_host_id],
704                                             lcf->gateway->controller))
705     {
706       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
707                                    GST_host_list[lcf->delegated_host_id]);
708     }
709     else
710     {
711       lcf->state = DELEGATED_HOST_REGISTERED;
712       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
713     }
714     break;
715   case DELEGATED_HOST_REGISTERED:
716     if (GNUNET_NO ==
717         GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
718                                             lcf->gateway->controller))
719     {
720       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
721                                    GST_host_list[lcf->slave_host_id]);
722     }
723     else
724     {
725       lcf->state = SLAVE_HOST_REGISTERED;
726       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
727     }
728     break;
729   case SLAVE_HOST_REGISTERED:
730     lcf->op = GNUNET_TESTBED_controller_link (lcf,
731                                               lcf->gateway->controller,
732                                               GST_host_list[lcf->delegated_host_id],
733                                               GST_host_list[lcf->slave_host_id],
734                                               lcf->is_subordinate);
735     lcf->timeout_task =
736         GNUNET_SCHEDULER_add_delayed (GST_timeout,
737                                       &lcf_forwarded_operation_timeout,
738                                       lcf);
739     lcf->state = FINISHED;
740     break;
741   case FINISHED:
742     if (NULL != lcf->op)
743       GNUNET_TESTBED_operation_done (lcf->op);
744     GNUNET_CONTAINER_DLL_remove (lcf_head,
745                                  lcf_tail,
746                                  lcf);
747     GNUNET_free (lcf);
748     if (NULL != lcf_head)
749       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
750                                                    lcf_head);
751   }
752 }
753
754
755 /**
756  * Callback for event from slave controllers
757  *
758  * @param cls NULL
759  * @param event information about the event
760  */
761 static void
762 slave_event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
763 {
764   struct LCFContext *lcf;
765
766   /* We currently only get here when working on LCFContexts */
767   GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
768   lcf = event->op_cls;
769   GNUNET_assert (lcf->op == event->op);
770   GNUNET_TESTBED_operation_done (lcf->op);
771   lcf->op = NULL;
772   GNUNET_assert (FINISHED == lcf->state);
773   GNUNET_assert (NULL != lcf->timeout_task);
774   GNUNET_SCHEDULER_cancel (lcf->timeout_task);
775   if (NULL == event->details.operation_finished.emsg)
776     send_controller_link_response (lcf->client, lcf->operation_id,
777                                    GNUNET_TESTBED_host_get_cfg_
778                                    (GST_host_list[lcf->delegated_host_id]),
779                                    NULL);
780   else
781     send_controller_link_response (lcf->client, lcf->operation_id,
782                                    NULL,
783                                    event->details.operation_finished.emsg);
784   GNUNET_assert (NULL == lcf_proc_task_id);
785   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
786   return;
787 }
788
789
790 /**
791  * Callback to signal successfull startup of the controller process
792  *
793  * @param cls the handle to the slave whose status is to be found here
794  * @param cfg the configuration with which the controller has been started;
795  *          NULL if status is not #GNUNET_OK
796  * @param status #GNUNET_OK if the startup is successfull; #GNUNET_SYSERR if not,
797  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
798  */
799 static void
800 slave_status_cb (void *cls,
801                  const struct GNUNET_CONFIGURATION_Handle *cfg,
802                  int status)
803 {
804   struct Slave *slave = cls;
805   struct LinkControllersContext *lcc;
806
807   lcc = slave->lcc;
808   if (GNUNET_SYSERR == status)
809   {
810     slave->controller_proc = NULL;
811     /* Stop all link controller forwarding tasks since we shutdown here anyway
812        and as these tasks they depend on the operation queues which are created
813        through GNUNET_TESTBED_controller_connect() and in kill_slave() we call
814        the destructor function GNUNET_TESTBED_controller_disconnect() */
815     GST_free_lcf ();
816     kill_slave (slave);
817     destroy_slave (slave);
818     slave = NULL;
819     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
820     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
821     goto clean_lcc;
822   }
823   slave->controller =
824       GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
825                                          EVENT_MASK, &slave_event_cb,
826                                          slave);
827   if (NULL != slave->controller)
828   {
829     send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
830   }
831   else
832   {
833     send_controller_link_response (lcc->client, lcc->operation_id, NULL,
834                                    "Could not connect to delegated controller");
835     kill_slave (slave);
836     destroy_slave (slave);
837     slave = NULL;
838   }
839
840  clean_lcc:
841   if (NULL != lcc)
842   {
843     if (NULL != lcc->client)
844     {
845       GNUNET_SERVICE_client_continue (lcc->client);
846       lcc->client = NULL;
847     }
848     GNUNET_free (lcc);
849   }
850   if (NULL != slave)
851     slave->lcc = NULL;
852 }
853
854
855 /**
856  * Trigger notification task if there are notification requests currently
857  * waiting in the given neighbour.  Also activates the neighbour connect operation
858  * if it was previously inactivated so that the connection to the neighbour can
859  * be re-used
860  *
861  * @param n the neighbour
862  */
863 static void
864 trigger_notifications (struct Neighbour *n);
865
866
867 /**
868  * Task to call the notification queued in the notifications list of the given
869  * neighbour
870  *
871  * @param cls the neighbour
872  */
873 static void
874 neighbour_connect_notify_task (void *cls)
875 {
876   struct Neighbour *n = cls;
877   struct NeighbourConnectNotification *h;
878
879   GNUNET_assert (NULL != (h = n->nl_head));
880   GNUNET_assert (NULL != n->notify_task);
881   n->notify_task = NULL;
882   GNUNET_assert (NULL != n->controller);
883   GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
884   trigger_notifications (n);
885   h->cb (h->cb_cls, n->controller);
886   GNUNET_free (h);
887 }
888
889
890 /**
891  * Trigger notification task if there are notification requests currently
892  * waiting in the given neighbour.  Also activates the neighbour connect operation
893  * if it was previously inactivated so that the connection to the neighbour can
894  * be re-used
895  *
896  * @param n the neighbour
897  */
898 static void
899 trigger_notifications (struct Neighbour *n)
900 {
901   GNUNET_assert (NULL != n->conn_op);
902   if (NULL == n->nl_head)
903     return;
904   if (NULL == n->controller)
905     return;
906   if (NULL != n->notify_task)
907     return;
908   if (1 == n->inactive)
909   {
910     GNUNET_assert (0 == n->reference_cnt);
911     GNUNET_TESTBED_operation_activate_ (n->conn_op);
912     n->inactive = 0;
913   }
914   n->reference_cnt++;
915   n->notify_task =
916       GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n);
917 }
918
919
920 /**
921  * Callback to be called when the neighbour connect operation is started.  The
922  * connection to the neigbour is opened here and any pending notifications are
923  * trigger.
924  *
925  * @param cls the neighbour
926  */
927 static void
928 opstart_neighbour_conn (void *cls)
929 {
930   struct Neighbour *n = cls;
931
932   GNUNET_assert (NULL != n->conn_op);
933   GNUNET_assert (NULL == n->controller);
934   LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
935   n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
936                                                      EVENT_MASK,
937                                                      &slave_event_cb,
938                                                      NULL);
939   trigger_notifications (n);
940 }
941
942
943 /**
944  * Callback to be called when the neighbour connect operation is released
945  *
946  * @param cls the neighbour
947  */
948 static void
949 oprelease_neighbour_conn (void *cls)
950 {
951    struct Neighbour *n = cls;
952
953    GNUNET_assert (0 == n->reference_cnt);
954    GNUNET_assert (NULL == n->notify_task);
955    GNUNET_assert (NULL == n->nl_head);
956    if (NULL != n->controller)
957    {
958      LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
959      GNUNET_TESTBED_controller_disconnect (n->controller);
960      n->controller = NULL;
961    }
962    n->conn_op = NULL;
963    n->inactive = 0;
964 }
965
966
967 /**
968  * Try to open a connection to the given neigbour.  If the connection is open
969  * already, then it is re-used.  If not, the request is queued in the operation
970  * queues responsible for bounding the total number of file descriptors.  The
971  * actual connection will happen when the operation queue marks the
972  * corresponding operation as active.
973  *
974  * @param n the neighbour to open a connection to
975  * @param cb the notification callback to call when the connection is opened
976  * @param cb_cls the closure for the above callback
977  */
978 struct NeighbourConnectNotification *
979 GST_neighbour_get_connection (struct Neighbour *n,
980                               GST_NeigbourConnectNotifyCallback cb,
981                               void *cb_cls)
982 {
983   struct NeighbourConnectNotification *h;
984
985   GNUNET_assert (NULL != cb);
986   LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
987              n->host_id);
988   h = GNUNET_new (struct NeighbourConnectNotification);
989   h->n = n;
990   h->cb  = cb;
991   h->cb_cls = cb_cls;
992   GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
993   if (NULL == n->conn_op)
994   {
995     GNUNET_assert (NULL == n->controller);
996     n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
997                                                    &oprelease_neighbour_conn);
998     GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
999     GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
1000     return h;
1001   }
1002   trigger_notifications (n);
1003   return h;
1004 }
1005
1006
1007 /**
1008  * Cancel the request for opening a connection to the neighbour
1009  *
1010  * @param h the notification handle
1011  */
1012 void
1013 GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
1014 {
1015   struct Neighbour *n;
1016   int cleanup_task;
1017
1018   n = h->n;
1019   cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
1020   GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
1021   GNUNET_free (h);
1022   if (GNUNET_NO == cleanup_task)
1023     return;
1024   if (NULL == n->notify_task)
1025     return;
1026   GNUNET_assert (0 < n->reference_cnt);
1027   n->reference_cnt--;
1028   GNUNET_SCHEDULER_cancel (n->notify_task);
1029   n->notify_task = NULL;
1030   if (NULL == n->nl_head)
1031   {
1032     if ( (0 == n->reference_cnt) && (0 == n->inactive) )
1033     {
1034       n->inactive = 1;
1035       GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1036     }
1037     return;
1038   }
1039   trigger_notifications (n);
1040 }
1041
1042
1043 /**
1044  * Release the connection to the neighbour.  The actual connection will be
1045  * closed if connections to other neighbour are waiting (to maintain a bound on
1046  * the total number of connections that are open).
1047  *
1048  * @param n the neighbour whose connection can be closed
1049  */
1050 void
1051 GST_neighbour_release_connection (struct Neighbour *n)
1052 {
1053   GNUNET_assert (0 == n->inactive);
1054   GNUNET_assert (0 < n->reference_cnt);
1055   n->reference_cnt--;
1056   if (0 == n->reference_cnt)
1057   {
1058     n->inactive = 1;
1059     GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1060   }
1061 }
1062
1063
1064 /**
1065  * Cleanup neighbour connect contexts
1066  *
1067  * @param ncc the neighbour connect context to cleanup
1068  */
1069 static void
1070 cleanup_ncc (struct NeighbourConnectCtxt *ncc)
1071 {
1072   if (NULL != ncc->nh)
1073     GST_neighbour_get_connection_cancel (ncc->nh);
1074   if (NULL != ncc->timeout_task)
1075     GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1076   GNUNET_CONTAINER_DLL_remove (ncc_head,
1077                                ncc_tail,
1078                                ncc);
1079   GNUNET_free (ncc);
1080 }
1081
1082
1083 /**
1084  * Cleans up the neighbour list
1085  */
1086 void
1087 GST_neighbour_list_clean ()
1088 {
1089   struct Neighbour *n;
1090   unsigned int id;
1091
1092   for (id = 0; id < neighbour_list_size; id++)
1093   {
1094     if (NULL == (n = neighbour_list[id]))
1095       continue;
1096     if (NULL != n->conn_op)
1097       GNUNET_TESTBED_operation_release_ (n->conn_op);
1098     GNUNET_free (n);
1099     neighbour_list[id] = NULL;
1100   }
1101   GNUNET_free_non_null (neighbour_list);
1102 }
1103
1104
1105 /**
1106  * Get a neighbour from the neighbour list
1107  *
1108  * @param id the index of the neighbour in the neighbour list
1109  * @return the Neighbour; NULL if the given index in invalid (index greater than
1110  *           the list size or neighbour at that index is NULL)
1111  */
1112 struct Neighbour *
1113 GST_get_neighbour (uint32_t id)
1114 {
1115   if (neighbour_list_size <= id)
1116     return NULL;
1117   return neighbour_list[id];
1118 }
1119
1120
1121 /**
1122  * Function to cleanup the neighbour connect contexts
1123  */
1124 void
1125 GST_free_nccq ()
1126 {
1127   while (NULL != ncc_head)
1128     cleanup_ncc (ncc_head);
1129 }
1130
1131
1132 /**
1133  * Task to be run upon timeout while attempting to connect to the neighbour
1134  *
1135  * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1136  */
1137 static void
1138 timeout_neighbour_connect (void *cls)
1139 {
1140  struct NeighbourConnectCtxt *ncc = cls;
1141
1142  ncc->timeout_task = NULL;
1143  send_controller_link_response (ncc->client,
1144                                 ncc->op_id,
1145                                 NULL,
1146                                 "Could not connect to delegated controller");
1147  cleanup_ncc (ncc);
1148 }
1149
1150
1151 /**
1152  * Callback called when a connection to the neighbour is made
1153  *
1154  * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1155  * @param c the handle the neighbour's controller
1156  */
1157 static void
1158 neighbour_connect_cb (void *cls,
1159                       struct GNUNET_TESTBED_Controller *c)
1160 {
1161   struct NeighbourConnectCtxt *ncc = cls;
1162
1163   GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1164   ncc->timeout_task = NULL;
1165   ncc->nh = NULL;
1166   GST_neighbour_release_connection (ncc->n);
1167   send_controller_link_response (ncc->client,
1168                                  ncc->op_id,
1169                                  NULL,
1170                                  NULL);
1171   cleanup_ncc (ncc);
1172 }
1173
1174
1175 /**
1176  * Function to create a neigbour and add it into the neighbour list
1177  *
1178  * @param host the host of the neighbour
1179  */
1180 struct Neighbour *
1181 GST_create_neighbour (struct GNUNET_TESTBED_Host *host)
1182 {
1183   struct Neighbour *n;
1184
1185   n = GNUNET_new (struct Neighbour);
1186   n->host_id = GNUNET_TESTBED_host_get_id_ (host);
1187   neighbour_list_add (n);   /* just add; connect on-demand */
1188   return n;
1189 }
1190
1191
1192 /**
1193  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1194  *
1195  * @param cls identification of the client
1196  * @param msg the actual message
1197  */
1198 void
1199 handle_link_controllers (void *cls,
1200                          const struct GNUNET_TESTBED_ControllerLinkRequest *msg)
1201 {
1202   struct GNUNET_SERVICE_Client *client = cls;
1203   struct LCFContext *lcf;
1204   struct Route *route;
1205   struct Route *new_route;
1206   uint64_t op_id;
1207   uint32_t delegated_host_id;
1208   uint32_t slave_host_id;
1209
1210   if (NULL == GST_context)
1211   {
1212     GNUNET_break (0);
1213     GNUNET_SERVICE_client_drop (client);
1214     return;
1215   }
1216   delegated_host_id = ntohl (msg->delegated_host_id);
1217   if (delegated_host_id == GST_context->host_id)
1218   {
1219     GNUNET_break (0);
1220     LOG (GNUNET_ERROR_TYPE_WARNING,
1221          "Trying to link ourselves\n");
1222     GNUNET_SERVICE_client_drop (client);
1223     return;
1224   }
1225   if ((delegated_host_id >= GST_host_list_size) ||
1226       (NULL == GST_host_list[delegated_host_id]))
1227   {
1228     LOG (GNUNET_ERROR_TYPE_WARNING,
1229          "Delegated host %u not registered with us\n",
1230          delegated_host_id);
1231     GNUNET_SERVICE_client_drop (client);
1232     return;
1233   }
1234   slave_host_id = ntohl (msg->slave_host_id);
1235   if ((slave_host_id >= GST_host_list_size) ||
1236       (NULL == GST_host_list[slave_host_id]))
1237   {
1238     LOG (GNUNET_ERROR_TYPE_WARNING,
1239          "Slave host %u not registered with us\n",
1240          slave_host_id);
1241     GNUNET_SERVICE_client_drop (client);
1242     return;
1243   }
1244   if (slave_host_id == delegated_host_id)
1245   {
1246     LOG (GNUNET_ERROR_TYPE_WARNING,
1247          "Slave and delegated host are same\n");
1248     GNUNET_SERVICE_client_drop (client);
1249     return;
1250   }
1251   op_id = GNUNET_ntohll (msg->operation_id);
1252   if (slave_host_id == GST_context->host_id)    /* Link from us */
1253   {
1254     struct Slave *slave;
1255     struct LinkControllersContext *lcc;
1256
1257     if (1 != msg->is_subordinate)
1258     {
1259       struct Neighbour *n;
1260       struct NeighbourConnectCtxt *ncc;
1261
1262       if ((delegated_host_id < neighbour_list_size) &&
1263         (NULL != neighbour_list[delegated_host_id]))
1264       {
1265         GNUNET_break (0);
1266         GNUNET_SERVICE_client_drop (client);
1267         return;
1268       }
1269       LOG_DEBUG ("Received request to establish a link to host %u\n",
1270                  delegated_host_id);
1271       n = GST_create_neighbour (GST_host_list[delegated_host_id]);
1272       ncc = GNUNET_new (struct NeighbourConnectCtxt);
1273       ncc->n = n;
1274       ncc->op_id = op_id;
1275       ncc->client = client;
1276       ncc->nh = GST_neighbour_get_connection (n,
1277                                               &neighbour_connect_cb,
1278                                               ncc);
1279       ncc->timeout_task
1280         = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1281                                         &timeout_neighbour_connect,
1282                                         ncc);
1283       GNUNET_CONTAINER_DLL_insert_tail (ncc_head,
1284                                         ncc_tail,
1285                                         ncc);
1286       GNUNET_SERVICE_client_continue (client);
1287       return;
1288     }
1289     if ( (delegated_host_id < GST_slave_list_size) &&
1290          (NULL != GST_slave_list[delegated_host_id]) )
1291     {
1292       GNUNET_break (0);
1293       GNUNET_SERVICE_client_drop (client);
1294       return;
1295     }
1296     LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1297                delegated_host_id);
1298     slave = GNUNET_new (struct Slave);
1299     slave->host_id = delegated_host_id;
1300     slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100,
1301                                                                GNUNET_NO);
1302     slave_list_add (slave);
1303     lcc = GNUNET_new (struct LinkControllersContext);
1304     lcc->operation_id = op_id;
1305     lcc->client = client;
1306     slave->lcc = lcc;
1307     slave->controller_proc
1308       = GNUNET_TESTBED_controller_start (GST_context->master_ip,
1309                                          GST_host_list[slave->host_id],
1310                                          &slave_status_cb,
1311                                          slave);
1312     new_route = GNUNET_new (struct Route);
1313     new_route->dest = delegated_host_id;
1314     new_route->thru = GST_context->host_id;
1315     route_list_add (new_route);
1316     return;
1317   }
1318
1319   /* Route the request */
1320   if (slave_host_id >= route_list_size)
1321   {
1322     LOG (GNUNET_ERROR_TYPE_WARNING,
1323          "No route towards slave host");
1324     GNUNET_SERVICE_client_drop (client);
1325     return;
1326   }
1327   lcf = GNUNET_new (struct LCFContext);
1328   lcf->delegated_host_id = delegated_host_id;
1329   lcf->slave_host_id = slave_host_id;
1330   route = GST_find_dest_route (slave_host_id);
1331   GNUNET_assert (NULL != route);        /* because we add routes carefully */
1332   GNUNET_assert (route->dest < GST_slave_list_size);
1333   GNUNET_assert (NULL != GST_slave_list[route->dest]);
1334   lcf->is_subordinate = msg->is_subordinate;
1335   lcf->state = INIT;
1336   lcf->operation_id = op_id;
1337   lcf->gateway = GST_slave_list[route->dest];
1338   lcf->client = client;
1339   if (NULL == lcf_head)
1340   {
1341     GNUNET_assert (NULL == lcf_proc_task_id);
1342     GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1343                                       lcf_tail,
1344                                       lcf);
1345     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
1346                                                  lcf);
1347   }
1348   else
1349   {
1350     GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1351                                       lcf_tail,
1352                                       lcf);
1353   }
1354   /* FIXME: Adding a new route should happen after the controllers are linked
1355    * successfully */
1356   if (1 != msg->is_subordinate)
1357   {
1358     GNUNET_SERVICE_client_continue (client);
1359     return;
1360   }
1361   if ( (delegated_host_id < route_list_size) &&
1362        (NULL != route_list[delegated_host_id]) )
1363   {
1364     GNUNET_break_op (0);        /* Are you trying to link delegated host twice
1365                                  * with is subordinate flag set to GNUNET_YES? */
1366     GNUNET_SERVICE_client_drop (client);
1367     return;
1368   }
1369   new_route = GNUNET_new (struct Route);
1370   new_route->dest = delegated_host_id;
1371   new_route->thru = route->dest;
1372   route_list_add (new_route);
1373   GNUNET_SERVICE_client_continue (client);
1374 }
1375
1376
1377 /**
1378  * Clean up @a client handle if we stored any via #handle_link_controllers(),
1379  * the given client disconnected.
1380  *
1381  * @param client the client that is history
1382  */
1383 void
1384 GST_link_notify_disconnect (struct GNUNET_SERVICE_Client *client)
1385 {
1386   struct NeighbourConnectCtxt *ncc;
1387   struct NeighbourConnectCtxt *nccn;
1388   struct LCFContext *lcf;
1389   struct LCFContext *lcfn;
1390
1391   for (ncc = ncc_head; NULL != ncc; ncc = nccn)
1392   {
1393     nccn = ncc->next;
1394     if (ncc->client == client)
1395       cleanup_ncc (ncc);
1396   }
1397   for (unsigned int i=0;i<GST_slave_list_size;i++)
1398   {
1399     struct Slave *slave = GST_slave_list[i];
1400     struct LinkControllersContext *lcc;
1401
1402     if (NULL == slave)
1403       continue;
1404     GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map,
1405                                            &drop_client_entries,
1406                                            client);
1407     lcc = slave->lcc;
1408     if (NULL == lcc)
1409       continue;
1410     if (lcc->client == client)
1411     {
1412       slave->lcc = NULL;
1413       GNUNET_free (lcc);
1414     }
1415   }
1416   for (lcf = lcf_head; NULL != lcf; lcf = lcfn)
1417   {
1418     lcfn = lcf->next;
1419     if ( (NULL != lcf) &&
1420          (client == lcf->client) )
1421     {
1422       if (NULL != lcf->op)
1423         GNUNET_TESTBED_operation_done (lcf->op);
1424       GNUNET_CONTAINER_DLL_remove (lcf_head,
1425                                    lcf_tail,
1426                                    lcf);
1427       GNUNET_free (lcf);
1428     }
1429   }
1430 }
1431
1432
1433 /**
1434  * Cleans up the queue used for forwarding link controllers requests
1435  */
1436 void
1437 GST_free_lcf ()
1438 {
1439   struct LCFContext *lcf;
1440
1441   if (NULL != lcf_head)
1442   {
1443     if (NULL != lcf_proc_task_id)
1444     {
1445       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1446       lcf_proc_task_id = NULL;
1447     }
1448   }
1449   GNUNET_assert (NULL == lcf_proc_task_id);
1450   for (lcf = lcf_head; NULL != lcf; lcf = lcf_head)
1451   {
1452     if (NULL != lcf->op)
1453       GNUNET_TESTBED_operation_done (lcf->op);
1454     if (NULL != lcf->timeout_task)
1455       GNUNET_SCHEDULER_cancel (lcf->timeout_task);
1456     GNUNET_CONTAINER_DLL_remove (lcf_head,
1457                                  lcf_tail,
1458                                  lcf);
1459     GNUNET_free (lcf);
1460   }
1461 }