2 This file is part of GNUnet.
3 (C) 2008--2013 Christian Grothoff (and other contributing authors)
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 2, or (at your
8 option) any later version.
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.
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
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
28 #include "gnunet-service-testbed.h"
31 * Redefine LOG with a changed log component string
36 #define LOG(kind,...) \
37 GNUNET_log_from (kind, "testbed-links", __VA_ARGS__)
40 * The event mask for the events we listen from sub-controllers
42 #define EVENT_MASK (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED)
46 * States of LCFContext
51 * The Context has been initialized; Nothing has been done on it
56 * Delegated host has been registered at the forwarding controller
58 DELEGATED_HOST_REGISTERED,
61 * The slave host has been registred at the forwarding controller
63 SLAVE_HOST_REGISTERED,
66 * The context has been finished (may have error)
73 * Link controllers request forwarding context
78 * The type of this data structure. Set this to CLOSURE_TYPE_LCF
80 enum ClosureType type;
83 * The gateway which will pass the link message to delegated host
85 struct Slave *gateway;
88 * The client which has asked to perform this operation
90 struct GNUNET_SERVER_Client *client;
93 * Handle for operations which are forwarded while linking controllers
95 struct GNUNET_TESTBED_Operation *op;
100 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
103 * The id of the operation which created this context
105 uint64_t operation_id;
108 * should the slave controller start the delegated controller?
113 * The state of this context
115 enum LCFContextState state;
120 uint32_t delegated_host_id;
125 uint32_t slave_host_id;
131 * Structure of a queue entry in LCFContext request queue
133 struct LCFContextQueue
138 struct LCFContext *lcf;
143 struct LCFContextQueue *next;
148 struct LCFContextQueue *prev;
151 struct NeighbourConnectNotification
153 struct NeighbourConnectNotification *next;
154 struct NeighbourConnectNotification *prev;
156 GST_NeigbourConnectNotifyCallback cb;
161 * A connected controller which is not our child
166 * The controller handle
168 struct GNUNET_TESTBED_Controller *controller;
171 * Operation handle for opening a lateral connection to another controller.
172 * Will be NULL if the slave controller is started by this controller
174 struct GNUNET_TESTBED_Operation *conn_op;
176 struct NeighbourConnectNotification *nl_head;
178 struct NeighbourConnectNotification *nl_tail;
180 GNUNET_SCHEDULER_TaskIdentifier notify_task;
182 unsigned int reference_cnt;
184 unsigned int inactive;
188 * The id of the host this controller is running on
194 static struct Neighbour **neighbour_list;
195 static unsigned int neighbour_list_size;
197 struct NeighbourConnectCtxt
199 struct NeighbourConnectCtxt *next;
200 struct NeighbourConnectCtxt *prev;
202 struct GNUNET_SERVER_Client *client;
203 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
204 struct NeighbourConnectNotification *nh;
208 struct NeighbourConnectCtxt *ncc_head;
209 struct NeighbourConnectCtxt *ncc_tail;
212 * A list of directly linked neighbours
214 struct Slave **GST_slave_list;
217 * The size of directly linked neighbours list
219 unsigned int GST_slave_list_size;
224 static struct Route **route_list;
227 * The head for the LCF queue
229 static struct LCFContextQueue *lcfq_head;
232 * The tail for the LCF queue
234 static struct LCFContextQueue *lcfq_tail;
237 * The lcf_task handle
239 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
242 * The size of the route list
244 static unsigned int route_list_size;
248 * Adds a slave to the slave array
250 * @param slave the slave controller to add
253 slave_list_add (struct Slave *slave)
255 if (slave->host_id >= GST_slave_list_size)
256 GST_array_grow_large_enough (GST_slave_list, GST_slave_list_size,
258 GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
259 GST_slave_list[slave->host_id] = slave;
264 * Adds a route to the route list
266 * @param route the route to add
269 route_list_add (struct Route *route)
271 if (route->dest >= route_list_size)
272 GST_array_grow_large_enough (route_list, route_list_size, route->dest);
273 GNUNET_assert (NULL == route_list[route->dest]);
274 route_list[route->dest] = route;
278 neighbour_list_add (struct Neighbour *n)
280 if (n->host_id >= neighbour_list_size)
281 GST_array_grow_large_enough (neighbour_list, neighbour_list_size, n->host_id);
282 GNUNET_assert (NULL == neighbour_list[n->host_id]);
283 neighbour_list[n->host_id] = n;
288 * Cleans up the route list
291 GST_route_list_clear ()
295 for (id = 0; id < route_list_size; id++)
296 if (NULL != route_list[id])
297 GNUNET_free (route_list[id]);
298 GNUNET_free_non_null (route_list);
304 * Iterator for freeing hash map entries in a slave's reghost_map
306 * @param cls handle to the slave
307 * @param key current key code
308 * @param value value in the hash map
309 * @return GNUNET_YES if we should continue to
314 reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key,
317 struct Slave *slave = cls;
318 struct RegisteredHostContext *rhc = value;
319 struct ForwardedOverlayConnectContext *focc;
321 GNUNET_assert (GNUNET_YES ==
322 GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
324 while (NULL != (focc = rhc->focc_dll_head))
326 GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
327 GST_cleanup_focc (focc);
335 * Cleans up the slave list
338 GST_slave_list_clear ()
341 struct HostRegistration *hr_entry;
343 for (id = 0; id < GST_slave_list_size; id++)
344 if (NULL != GST_slave_list[id])
346 while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head))
348 GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head,
349 GST_slave_list[id]->hr_dll_tail, hr_entry);
350 GNUNET_free (hr_entry);
352 if (NULL != GST_slave_list[id]->rhandle)
353 GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle);
355 GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list
357 reghost_free_iterator,
359 GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map);
360 if (NULL != GST_slave_list[id]->controller)
361 GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller);
362 if (NULL != GST_slave_list[id]->controller_proc)
363 GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc);
364 GNUNET_free (GST_slave_list[id]);
366 GNUNET_free_non_null (GST_slave_list);
367 GST_slave_list = NULL;
372 * Finds the route with directly connected host as destination through which
373 * the destination host can be reached
375 * @param host_id the id of the destination host
376 * @return the route with directly connected destination host; NULL if no route
380 GST_find_dest_route (uint32_t host_id)
384 if (route_list_size <= host_id)
386 while (NULL != (route = route_list[host_id]))
388 if (route->thru == GST_context->host_id)
390 host_id = route->thru;
397 * Function to send a failure reponse for controller link operation
399 * @param client the client to send the message to
400 * @param operation_id the operation ID of the controller link request
401 * @param cfg the configuration with which the delegated controller is started.
402 * Can be NULL if the delegated controller is not started but just
404 * @param emsg set to an error message explaining why the controller link
405 * failed. Setting this to NULL signifies success. !This should be
406 * NULL if cfg is set!
409 send_controller_link_response (struct GNUNET_SERVER_Client *client,
410 uint64_t operation_id,
411 const struct GNUNET_CONFIGURATION_Handle
415 struct GNUNET_TESTBED_ControllerLinkResponse *msg;
421 GNUNET_assert ((NULL == cfg) || (NULL == emsg));
425 msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse);
428 xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
431 msize += xconfig_size;
434 msize += strlen (emsg);
435 msg = GNUNET_malloc (msize);
436 msg->header.type = htons
437 (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
438 msg->header.size = htons (msize);
440 msg->success = htons (GNUNET_YES);
441 msg->operation_id = GNUNET_htonll (operation_id);
442 msg->config_size = htons ((uint16_t) config_size);
445 memcpy (&msg[1], xconfig, xconfig_size);
446 GNUNET_free (xconfig);
449 memcpy (&msg[1], emsg, strlen (emsg));
450 GST_queue_message (client, &msg->header);
455 * The Link Controller forwarding task
457 * @param cls the LCFContext
458 * @param tc the Task context from scheduler
461 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
465 * Completion callback for host registrations while forwarding Link Controller messages
467 * @param cls the LCFContext
468 * @param emsg the error message; NULL if host registration is successful
471 lcf_proc_cc (void *cls, const char *emsg)
473 struct LCFContext *lcf = cls;
475 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
480 goto registration_error;
481 lcf->state = DELEGATED_HOST_REGISTERED;
482 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
484 case DELEGATED_HOST_REGISTERED:
486 goto registration_error;
487 lcf->state = SLAVE_HOST_REGISTERED;
488 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
491 GNUNET_assert (0); /* Shouldn't reach here */
496 LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
498 lcf->state = FINISHED;
499 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
504 * The Link Controller forwarding task
506 * @param cls the LCFContext
507 * @param tc the Task context from scheduler
510 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
514 * Task to free resources when forwarded link controllers has been timedout
516 * @param cls the LCFContext
517 * @param tc the task context from scheduler
520 lcf_forwarded_operation_timeout (void *cls,
521 const struct GNUNET_SCHEDULER_TaskContext *tc)
523 struct LCFContext *lcf = cls;
525 lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK;
526 // GST_forwarded_operation_timeout (lcf->fopc, tc);
527 LOG (GNUNET_ERROR_TYPE_WARNING,
528 "A forwarded controller link operation has timed out\n");
529 send_controller_link_response (lcf->client, lcf->operation_id, NULL,
530 "A forwarded controller link operation has "
532 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
533 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
538 * The Link Controller forwarding task
540 * @param cls the LCFContext
541 * @param tc the Task context from scheduler
544 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
546 struct LCFContext *lcf = cls;
547 struct LCFContextQueue *lcfq;
549 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
554 GNUNET_TESTBED_is_host_registered_ (GST_host_list
555 [lcf->delegated_host_id],
556 lcf->gateway->controller))
558 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
559 GST_host_list[lcf->delegated_host_id]);
563 lcf->state = DELEGATED_HOST_REGISTERED;
564 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
567 case DELEGATED_HOST_REGISTERED:
569 GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
570 lcf->gateway->controller))
572 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
573 GST_host_list[lcf->slave_host_id]);
577 lcf->state = SLAVE_HOST_REGISTERED;
578 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
581 case SLAVE_HOST_REGISTERED:
582 lcf->op = GNUNET_TESTBED_controller_link (lcf,
583 lcf->gateway->controller,
584 GST_host_list[lcf->delegated_host_id],
585 GST_host_list[lcf->slave_host_id],
586 lcf->is_subordinate);
588 GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout,
590 lcf->state = FINISHED;
594 GNUNET_assert (lcfq->lcf == lcf);
595 GNUNET_SERVER_client_drop (lcf->client);
596 GNUNET_TESTBED_operation_done (lcf->op);
598 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
600 if (NULL != lcfq_head)
602 GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
608 * Callback for event from slave controllers
611 * @param event information about the event
614 slave_event_callback (void *cls,
615 const struct GNUNET_TESTBED_EventInformation *event)
617 struct LCFContext *lcf;
619 /* We currently only get here when working on RegisteredHostContexts and
621 GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
623 if (CLOSURE_TYPE_LCF == lcf->type)
625 GNUNET_assert (lcf->op == event->op);
626 GNUNET_assert (FINISHED == lcf->state);
627 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task);
628 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
629 if (NULL == event->details.operation_finished.emsg)
630 send_controller_link_response (lcf->client, lcf->operation_id,
631 GNUNET_TESTBED_host_get_cfg_
632 (GST_host_list[lcf->delegated_host_id]),
635 send_controller_link_response (lcf->client, lcf->operation_id,
637 event->details.operation_finished.emsg);
638 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
639 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
646 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
650 * Callback to signal successfull startup of the controller process
652 * @param cls the handle to the slave whose status is to be found here
653 * @param cfg the configuration with which the controller has been started;
654 * NULL if status is not GNUNET_OK
655 * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
656 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
659 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
662 struct Slave *slave = cls;
663 struct LinkControllersContext *lcc;
666 if (GNUNET_SYSERR == status)
668 slave->controller_proc = NULL;
669 GST_slave_list[slave->host_id] = NULL;
672 LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
673 GNUNET_SCHEDULER_shutdown (); /* We too shutdown */
677 GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
678 EVENT_MASK, &slave_event_callback,
680 if (NULL != slave->controller)
682 send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
686 send_controller_link_response (lcc->client, lcc->operation_id, NULL,
687 "Could not connect to delegated controller");
688 GNUNET_TESTBED_controller_stop (slave->controller_proc);
689 GST_slave_list[slave->host_id] = NULL;
697 if (NULL != lcc->client)
699 GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
700 GNUNET_SERVER_client_drop (lcc->client);
710 neighbour_connect_notify_task (void *cls,
711 const struct GNUNET_SCHEDULER_TaskContext *tc);
714 trigger_notifications (struct Neighbour *n)
716 GNUNET_assert (NULL != n->conn_op);
717 if (NULL == n->nl_head)
719 if (NULL == n->controller)
721 if (GNUNET_SCHEDULER_NO_TASK != n->notify_task)
723 if (1 == n->inactive)
725 GNUNET_assert (0 == n->reference_cnt);
726 GNUNET_TESTBED_operation_activate_ (n->conn_op);
731 GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n);
735 neighbour_connect_notify_task (void *cls,
736 const struct GNUNET_SCHEDULER_TaskContext *tc)
738 struct Neighbour *n = cls;
739 struct NeighbourConnectNotification *h;
741 GNUNET_assert (NULL != (h = n->nl_head));
742 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->notify_task);
743 n->notify_task = GNUNET_SCHEDULER_NO_TASK;
744 GNUNET_assert (NULL != n->controller);
745 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
746 trigger_notifications (n);
747 h->cb (h->cb_cls, n->controller);
752 opstart_neighbour_conn (void *cls)
754 struct Neighbour *n = cls;
756 GNUNET_assert (NULL != n->conn_op);
757 GNUNET_assert (NULL == n->controller);
758 LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
759 n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
761 &slave_event_callback,
763 trigger_notifications (n);
767 oprelease_neighbour_conn (void *cls)
769 struct Neighbour *n = cls;
771 GNUNET_assert (0 == n->reference_cnt);
772 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->notify_task);
773 GNUNET_assert (NULL == n->nl_head);
774 if (NULL != n->controller)
776 LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
777 GNUNET_TESTBED_controller_disconnect (n->controller);
778 n->controller = NULL;
784 struct NeighbourConnectNotification *
785 GST_neighbour_get_connection (struct Neighbour *n,
786 GST_NeigbourConnectNotifyCallback cb,
789 struct NeighbourConnectNotification *h;
791 GNUNET_assert (NULL != cb);
792 LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
794 h = GNUNET_malloc (sizeof (struct NeighbourConnectNotification));
798 GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
799 if (NULL == n->conn_op)
801 GNUNET_assert (NULL == n->controller);
802 n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
803 &oprelease_neighbour_conn);
804 GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
805 GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
808 trigger_notifications (n);
813 GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
819 cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
820 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
822 if (GNUNET_NO == cleanup_task)
824 if (GNUNET_SCHEDULER_NO_TASK == n->notify_task)
826 GNUNET_assert (0 < n->reference_cnt);
828 GNUNET_SCHEDULER_cancel (n->notify_task);
829 n->notify_task = GNUNET_SCHEDULER_NO_TASK;
830 if (NULL == n->nl_head)
832 if ( (0 == n->reference_cnt) && (0 == n->inactive) )
835 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
839 trigger_notifications (n);
843 GST_neighbour_release_connection (struct Neighbour *n)
845 GNUNET_assert (0 == n->inactive);
846 GNUNET_assert (0 < n->reference_cnt);
848 if (0 == n->reference_cnt)
851 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
856 cleanup_ncc (struct NeighbourConnectCtxt *ncc)
859 GST_neighbour_get_connection_cancel (ncc->nh);
860 if (GNUNET_SCHEDULER_NO_TASK != ncc->timeout_task)
861 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
862 GNUNET_SERVER_client_drop (ncc->client);
863 GNUNET_CONTAINER_DLL_remove (ncc_head, ncc_tail, ncc);
868 GST_neighbour_list_clean()
873 for (id = 0; id < neighbour_list_size; id++)
875 if (NULL == (n = neighbour_list[id]))
877 if (NULL != n->conn_op)
878 GNUNET_TESTBED_operation_release_ (n->conn_op);
880 neighbour_list[id] = NULL;
882 GNUNET_free_non_null (neighbour_list);
886 GST_get_neighbour (uint32_t id)
888 if (neighbour_list_size <= id)
891 return neighbour_list[id];
897 while (NULL != ncc_head)
898 cleanup_ncc (ncc_head);
902 timeout_neighbour_connect (void *cls,
903 const struct GNUNET_SCHEDULER_TaskContext *tc)
905 struct NeighbourConnectCtxt *ncc = cls;
907 ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
908 send_controller_link_response (ncc->client, ncc->op_id, NULL,
909 "Could not connect to delegated controller");
914 neighbour_connect_cb (void *cls, struct GNUNET_TESTBED_Controller *c)
916 struct NeighbourConnectCtxt *ncc = cls;
918 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
919 ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
921 GST_neighbour_release_connection (ncc->n);
922 send_controller_link_response (ncc->client, ncc->op_id, NULL, NULL);
927 GST_create_neighbour (struct GNUNET_TESTBED_Host *host)
931 n = GNUNET_malloc (sizeof (struct Neighbour));
932 n->host_id = GNUNET_TESTBED_host_get_id_ (host);
933 neighbour_list_add (n); /* just add; connect on-demand */
939 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
942 * @param client identification of the client
943 * @param message the actual message
946 GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
947 const struct GNUNET_MessageHeader *message)
949 const struct GNUNET_TESTBED_ControllerLinkRequest *msg;
950 struct LCFContextQueue *lcfq;
952 struct Route *new_route;
954 uint32_t delegated_host_id;
955 uint32_t slave_host_id;
957 if (NULL == GST_context)
960 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
963 msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message;
964 delegated_host_id = ntohl (msg->delegated_host_id);
965 if (delegated_host_id == GST_context->host_id)
968 LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
969 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
972 if ((delegated_host_id >= GST_host_list_size) ||
973 (NULL == GST_host_list[delegated_host_id]))
975 LOG (GNUNET_ERROR_TYPE_WARNING,
976 "Delegated host %u not registered with us\n", delegated_host_id);
977 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
980 slave_host_id = ntohl (msg->slave_host_id);
981 if ((slave_host_id >= GST_host_list_size) ||
982 (NULL == GST_host_list[slave_host_id]))
984 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
986 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
989 if (slave_host_id == delegated_host_id)
991 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
992 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
995 op_id = GNUNET_ntohll (msg->operation_id);
996 if (slave_host_id == GST_context->host_id) /* Link from us */
999 struct LinkControllersContext *lcc;
1002 if (1 != msg->is_subordinate)
1004 struct Neighbour *n;
1005 struct NeighbourConnectCtxt *ncc;
1007 if ((delegated_host_id < neighbour_list_size) &&
1008 (NULL != neighbour_list[delegated_host_id]))
1011 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1014 LOG_DEBUG ("Received request to establish a link to host %u\n",
1016 n = GST_create_neighbour (GST_host_list[delegated_host_id]);
1017 ncc = GNUNET_malloc (sizeof (struct NeighbourConnectCtxt));
1020 ncc->client = client;
1021 GNUNET_SERVER_client_keep (client);
1022 ncc->nh = GST_neighbour_get_connection (n, neighbour_connect_cb, ncc);
1023 ncc->timeout_task = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1024 &timeout_neighbour_connect,
1026 GNUNET_CONTAINER_DLL_insert_tail (ncc_head, ncc_tail, ncc);
1027 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1030 if ((delegated_host_id < GST_slave_list_size) &&
1031 (NULL != GST_slave_list[delegated_host_id]))
1034 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1037 LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1039 slave = GNUNET_malloc (sizeof (struct Slave));
1040 slave->host_id = delegated_host_id;
1041 slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
1042 slave_list_add (slave);
1043 lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
1044 lcc->operation_id = op_id;
1045 GNUNET_SERVER_client_keep (client);
1046 lcc->client = client;
1048 slave->controller_proc =
1049 GNUNET_TESTBED_controller_start (GST_context->master_ip,
1050 GST_host_list[slave->host_id],
1051 &slave_status_callback, slave);
1052 new_route = GNUNET_malloc (sizeof (struct Route));
1053 new_route->dest = delegated_host_id;
1054 new_route->thru = GST_context->host_id;
1055 route_list_add (new_route);
1059 /* Route the request */
1060 if (slave_host_id >= route_list_size)
1062 LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1063 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1066 lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
1067 lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
1068 lcfq->lcf->type = CLOSURE_TYPE_LCF;
1069 lcfq->lcf->delegated_host_id = delegated_host_id;
1070 lcfq->lcf->slave_host_id = slave_host_id;
1071 route = GST_find_dest_route (slave_host_id);
1072 GNUNET_assert (NULL != route); /* because we add routes carefully */
1073 GNUNET_assert (route->dest < GST_slave_list_size);
1074 GNUNET_assert (NULL != GST_slave_list[route->dest]);
1075 lcfq->lcf->is_subordinate = msg->is_subordinate;
1076 lcfq->lcf->state = INIT;
1077 lcfq->lcf->operation_id = op_id;
1078 lcfq->lcf->gateway = GST_slave_list[route->dest];
1079 GNUNET_SERVER_client_keep (client);
1080 lcfq->lcf->client = client;
1081 if (NULL == lcfq_head)
1083 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1084 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1085 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
1088 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1089 /* FIXME: Adding a new route should happen after the controllers are linked
1091 if (1 != msg->is_subordinate)
1093 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1096 if ((delegated_host_id < route_list_size) &&
1097 (NULL != route_list[delegated_host_id]))
1099 GNUNET_break_op (0); /* Are you trying to link delegated host twice
1100 * with is subordinate flag set to GNUNET_YES? */
1101 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1104 new_route = GNUNET_malloc (sizeof (struct Route));
1105 new_route->dest = delegated_host_id;
1106 new_route->thru = route->dest;
1107 route_list_add (new_route);
1108 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1113 * Cleans up the queue used for forwarding link controllers requests
1118 struct LCFContextQueue *lcfq;
1120 if (NULL != lcfq_head)
1122 if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
1124 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1125 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1128 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1129 for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
1131 GNUNET_SERVER_client_drop (lcfq->lcf->client);
1132 GNUNET_free (lcfq->lcf);
1133 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);