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