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