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;
185 * The id of the host this controller is running on
192 static struct Neighbour **neighbour_list;
193 static unsigned int neighbour_list_size;
195 struct NeighbourConnectCtxt
197 struct NeighbourConnectCtxt *next;
198 struct NeighbourConnectCtxt *prev;
200 struct GNUNET_SERVER_Client *client;
201 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
202 struct NeighbourConnectNotification *nh;
206 struct NeighbourConnectCtxt *ncc_head;
207 struct NeighbourConnectCtxt *ncc_tail;
210 * A list of directly linked neighbours
212 struct Slave **GST_slave_list;
215 * The size of directly linked neighbours list
217 unsigned int GST_slave_list_size;
222 static struct Route **route_list;
225 * The head for the LCF queue
227 static struct LCFContextQueue *lcfq_head;
230 * The tail for the LCF queue
232 static struct LCFContextQueue *lcfq_tail;
235 * The lcf_task handle
237 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
240 * The size of the route list
242 static unsigned int route_list_size;
246 * Adds a slave to the slave array
248 * @param slave the slave controller to add
251 slave_list_add (struct Slave *slave)
253 if (slave->host_id >= GST_slave_list_size)
254 GST_array_grow_large_enough (GST_slave_list, GST_slave_list_size,
256 GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
257 GST_slave_list[slave->host_id] = slave;
262 * Adds a route to the route list
264 * @param route the route to add
267 route_list_add (struct Route *route)
269 if (route->dest >= route_list_size)
270 GST_array_grow_large_enough (route_list, route_list_size, route->dest);
271 GNUNET_assert (NULL == route_list[route->dest]);
272 route_list[route->dest] = route;
276 neighbour_list_add (struct Neighbour *n)
278 if (n->host_id >= neighbour_list_size)
279 GST_array_grow_large_enough (neighbour_list, neighbour_list_size, n->host_id);
280 GNUNET_assert (NULL == neighbour_list[n->host_id]);
281 neighbour_list[n->host_id] = n;
286 * Cleans up the route list
289 GST_route_list_clear ()
293 for (id = 0; id < route_list_size; id++)
294 if (NULL != route_list[id])
295 GNUNET_free (route_list[id]);
296 GNUNET_free_non_null (route_list);
302 * Iterator for freeing hash map entries in a slave's reghost_map
304 * @param cls handle to the slave
305 * @param key current key code
306 * @param value value in the hash map
307 * @return GNUNET_YES if we should continue to
312 reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key,
315 struct Slave *slave = cls;
316 struct RegisteredHostContext *rhc = value;
317 struct ForwardedOverlayConnectContext *focc;
319 GNUNET_assert (GNUNET_YES ==
320 GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
322 while (NULL != (focc = rhc->focc_dll_head))
324 GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
325 GST_cleanup_focc (focc);
327 if (NULL != rhc->sub_op)
328 GNUNET_TESTBED_operation_done (rhc->sub_op);
329 if (NULL != rhc->client)
330 GNUNET_SERVER_client_drop (rhc->client);
337 * Cleans up the slave list
340 GST_slave_list_clear ()
343 struct HostRegistration *hr_entry;
345 for (id = 0; id < GST_slave_list_size; id++)
346 if (NULL != GST_slave_list[id])
348 while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head))
350 GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head,
351 GST_slave_list[id]->hr_dll_tail, hr_entry);
352 GNUNET_free (hr_entry);
354 if (NULL != GST_slave_list[id]->rhandle)
355 GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle);
357 GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list
359 reghost_free_iterator,
361 GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map);
362 if (NULL != GST_slave_list[id]->controller)
363 GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller);
364 if (NULL != GST_slave_list[id]->controller_proc)
365 GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc);
366 GNUNET_free (GST_slave_list[id]);
368 GNUNET_free_non_null (GST_slave_list);
369 GST_slave_list = NULL;
374 * Finds the route with directly connected host as destination through which
375 * the destination host can be reached
377 * @param host_id the id of the destination host
378 * @return the route with directly connected destination host; NULL if no route
382 GST_find_dest_route (uint32_t host_id)
386 if (route_list_size <= host_id)
388 while (NULL != (route = route_list[host_id]))
390 if (route->thru == GST_context->host_id)
392 host_id = route->thru;
399 * Function to send a failure reponse for controller link operation
401 * @param client the client to send the message to
402 * @param operation_id the operation ID of the controller link request
403 * @param cfg the configuration with which the delegated controller is started.
404 * Can be NULL if the delegated controller is not started but just
406 * @param emsg set to an error message explaining why the controller link
407 * failed. Setting this to NULL signifies success. !This should be
408 * NULL if cfg is set!
411 send_controller_link_response (struct GNUNET_SERVER_Client *client,
412 uint64_t operation_id,
413 const struct GNUNET_CONFIGURATION_Handle
417 struct GNUNET_TESTBED_ControllerLinkResponse *msg;
423 GNUNET_assert ((NULL == cfg) || (NULL == emsg));
427 msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse);
430 xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
433 msize += xconfig_size;
436 msize += strlen (emsg);
437 msg = GNUNET_malloc (msize);
438 msg->header.type = htons
439 (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
440 msg->header.size = htons (msize);
442 msg->success = htons (GNUNET_YES);
443 msg->operation_id = GNUNET_htonll (operation_id);
444 msg->config_size = htons ((uint16_t) config_size);
447 memcpy (&msg[1], xconfig, xconfig_size);
448 GNUNET_free (xconfig);
451 memcpy (&msg[1], emsg, strlen (emsg));
452 GST_queue_message (client, &msg->header);
457 * The Link Controller forwarding task
459 * @param cls the LCFContext
460 * @param tc the Task context from scheduler
463 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
467 * Completion callback for host registrations while forwarding Link Controller messages
469 * @param cls the LCFContext
470 * @param emsg the error message; NULL if host registration is successful
473 lcf_proc_cc (void *cls, const char *emsg)
475 struct LCFContext *lcf = cls;
477 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
482 goto registration_error;
483 lcf->state = DELEGATED_HOST_REGISTERED;
484 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
486 case DELEGATED_HOST_REGISTERED:
488 goto registration_error;
489 lcf->state = SLAVE_HOST_REGISTERED;
490 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
493 GNUNET_assert (0); /* Shouldn't reach here */
498 LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
500 lcf->state = FINISHED;
501 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
506 * The Link Controller forwarding task
508 * @param cls the LCFContext
509 * @param tc the Task context from scheduler
512 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
516 * Task to free resources when forwarded link controllers has been timedout
518 * @param cls the LCFContext
519 * @param tc the task context from scheduler
522 lcf_forwarded_operation_timeout (void *cls,
523 const struct GNUNET_SCHEDULER_TaskContext *tc)
525 struct LCFContext *lcf = cls;
527 lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK;
528 // GST_forwarded_operation_timeout (lcf->fopc, tc);
529 LOG (GNUNET_ERROR_TYPE_WARNING,
530 "A forwarded controller link operation has timed out\n");
531 send_controller_link_response (lcf->client, lcf->operation_id, NULL,
532 "A forwarded controller link operation has "
534 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
535 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
540 * The Link Controller forwarding task
542 * @param cls the LCFContext
543 * @param tc the Task context from scheduler
546 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
548 struct LCFContext *lcf = cls;
549 struct LCFContextQueue *lcfq;
551 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
556 GNUNET_TESTBED_is_host_registered_ (GST_host_list
557 [lcf->delegated_host_id],
558 lcf->gateway->controller))
560 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
561 GST_host_list[lcf->delegated_host_id]);
565 lcf->state = DELEGATED_HOST_REGISTERED;
566 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
569 case DELEGATED_HOST_REGISTERED:
571 GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
572 lcf->gateway->controller))
574 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
575 GST_host_list[lcf->slave_host_id]);
579 lcf->state = SLAVE_HOST_REGISTERED;
580 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
583 case SLAVE_HOST_REGISTERED:
584 lcf->op = GNUNET_TESTBED_controller_link (lcf,
585 lcf->gateway->controller,
586 GST_host_list[lcf->delegated_host_id],
587 GST_host_list[lcf->slave_host_id],
589 lcf->is_subordinate);
591 GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout,
593 lcf->state = FINISHED;
597 GNUNET_assert (lcfq->lcf == lcf);
598 GNUNET_SERVER_client_drop (lcf->client);
599 GNUNET_TESTBED_operation_done (lcf->op);
601 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
603 if (NULL != lcfq_head)
605 GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
611 * Callback for event from slave controllers
614 * @param event information about the event
617 slave_event_callback (void *cls,
618 const struct GNUNET_TESTBED_EventInformation *event)
620 struct RegisteredHostContext *rhc;
621 struct LCFContext *lcf;
622 struct GNUNET_CONFIGURATION_Handle *cfg;
623 struct GNUNET_TESTBED_Operation *old_op;
625 /* We currently only get here when working on RegisteredHostContexts and
627 GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
629 if (CLOSURE_TYPE_RHC == rhc->type)
631 GNUNET_assert (rhc->sub_op == event->op);
635 cfg = event->details.operation_finished.generic;
636 old_op = rhc->sub_op;
637 rhc->state = RHC_LINK;
639 GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller,
640 rhc->reg_host, rhc->host, cfg,
642 GNUNET_TESTBED_operation_done (old_op);
645 LOG_DEBUG ("OL: Linking controllers successfull\n");
646 GNUNET_TESTBED_operation_done (rhc->sub_op);
648 rhc->state = RHC_OL_CONNECT;
649 GST_process_next_focc (rhc);
657 if (CLOSURE_TYPE_LCF == lcf->type)
659 GNUNET_assert (lcf->op == event->op);
660 GNUNET_assert (FINISHED == lcf->state);
661 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task);
662 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
663 if (NULL == event->details.operation_finished.emsg)
664 send_controller_link_response (lcf->client, lcf->operation_id,
665 GNUNET_TESTBED_host_get_cfg_
666 (GST_host_list[lcf->delegated_host_id]),
669 send_controller_link_response (lcf->client, lcf->operation_id,
671 event->details.operation_finished.emsg);
672 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
673 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
680 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
684 * Callback to signal successfull startup of the controller process
686 * @param cls the handle to the slave whose status is to be found here
687 * @param cfg the configuration with which the controller has been started;
688 * NULL if status is not GNUNET_OK
689 * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
690 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
693 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
696 struct Slave *slave = cls;
697 struct LinkControllersContext *lcc;
700 if (GNUNET_SYSERR == status)
702 slave->controller_proc = NULL;
703 GST_slave_list[slave->host_id] = NULL;
706 LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
707 GNUNET_SCHEDULER_shutdown (); /* We too shutdown */
711 GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
712 EVENT_MASK, &slave_event_callback,
714 if (NULL != slave->controller)
716 send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
720 send_controller_link_response (lcc->client, lcc->operation_id, NULL,
721 "Could not connect to delegated controller");
722 GNUNET_TESTBED_controller_stop (slave->controller_proc);
723 GST_slave_list[slave->host_id] = NULL;
731 if (NULL != lcc->client)
733 GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
734 GNUNET_SERVER_client_drop (lcc->client);
744 neighbour_connect_notify_task (void *cls,
745 const struct GNUNET_SCHEDULER_TaskContext *tc);
748 trigger_notifications (struct Neighbour *n)
750 GNUNET_assert (NULL != n->conn_op);
751 if (NULL == n->nl_head)
753 if (NULL == n->controller)
755 if (GNUNET_SCHEDULER_NO_TASK != n->notify_task)
758 GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n->nl_head);
762 neighbour_connect_notify_task (void *cls,
763 const struct GNUNET_SCHEDULER_TaskContext *tc)
765 struct NeighbourConnectNotification *h = cls;
769 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->notify_task);
770 n->notify_task = GNUNET_SCHEDULER_NO_TASK;
771 GNUNET_assert (NULL != n->controller);
772 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
773 trigger_notifications (n);
774 if ((0 == n->reference_cnt) && (1 == n->inactive))
776 GNUNET_TESTBED_operation_activate_ (n->conn_op);
780 h->cb (h->cb_cls, n->controller);
785 opstart_neighbour_conn (void *cls)
787 struct Neighbour *n = cls;
789 GNUNET_assert (NULL != n->conn_op);
790 GNUNET_assert (NULL == n->controller);
791 LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
792 n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
794 &slave_event_callback,
796 trigger_notifications (n);
800 oprelease_neighbour_conn (void *cls)
802 struct Neighbour *n = cls;
804 GNUNET_assert (0 == n->reference_cnt);
805 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->notify_task);
806 GNUNET_assert (NULL == n->nl_head);
807 LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
808 GNUNET_TESTBED_controller_disconnect (n->controller);
809 n->controller = NULL;
813 struct NeighbourConnectNotification *
814 GST_neighbour_get_connection (struct Neighbour *n,
815 GST_NeigbourConnectNotifyCallback cb,
818 struct NeighbourConnectNotification *h;
820 GNUNET_assert (NULL != cb);
821 LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
823 h = GNUNET_malloc (sizeof (struct NeighbourConnectNotification));
827 GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
828 if (NULL == n->conn_op)
830 GNUNET_assert (NULL == n->controller);
831 n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
832 &oprelease_neighbour_conn);
833 GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
834 GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
837 trigger_notifications (n);
842 GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
847 if ((h == n->nl_head) && (GNUNET_SCHEDULER_NO_TASK != n->notify_task))
849 GNUNET_SCHEDULER_cancel (n->notify_task);
850 n->notify_task = GNUNET_SCHEDULER_NO_TASK;
852 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
857 GST_neighbour_release_connection (struct Neighbour *n)
859 GNUNET_assert (0 == n->inactive);
860 GNUNET_assert (0 < n->reference_cnt);
862 if (0 == n->reference_cnt)
864 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
870 cleanup_ncc (struct NeighbourConnectCtxt *ncc)
873 GST_neighbour_get_connection_cancel (ncc->nh);
874 if (GNUNET_SCHEDULER_NO_TASK != ncc->timeout_task)
875 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
876 GNUNET_SERVER_client_drop (ncc->client);
877 GNUNET_CONTAINER_DLL_remove (ncc_head, ncc_tail, ncc);
882 GST_neighbour_list_clean()
887 for (id = 0; id < neighbour_list_size; id++)
889 if (NULL == (n = neighbour_list[id]))
891 if (NULL != n->conn_op)
892 GNUNET_TESTBED_operation_release_ (n->conn_op);
894 neighbour_list[id] = NULL;
896 GNUNET_free_non_null (neighbour_list);
900 GST_get_neighbour (uint32_t id)
902 if (neighbour_list_size <= id)
905 return neighbour_list[id];
911 while (NULL != ncc_head)
912 cleanup_ncc (ncc_head);
916 timeout_neighbour_connect (void *cls,
917 const struct GNUNET_SCHEDULER_TaskContext *tc)
919 struct NeighbourConnectCtxt *ncc = cls;
921 ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
922 send_controller_link_response (ncc->client, ncc->op_id, NULL,
923 "Could not connect to delegated controller");
928 neighbour_connect_cb (void *cls, struct GNUNET_TESTBED_Controller *c)
930 struct NeighbourConnectCtxt *ncc = cls;
932 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
933 ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
935 GST_neighbour_release_connection (ncc->n);
936 send_controller_link_response (ncc->client, ncc->op_id, NULL, NULL);
941 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
944 * @param client identification of the client
945 * @param message the actual message
948 GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
949 const struct GNUNET_MessageHeader *message)
951 const struct GNUNET_TESTBED_ControllerLinkRequest *msg;
952 struct LCFContextQueue *lcfq;
954 struct Route *new_route;
956 uint32_t delegated_host_id;
957 uint32_t slave_host_id;
959 if (NULL == GST_context)
962 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
965 msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message;
966 delegated_host_id = ntohl (msg->delegated_host_id);
967 if (delegated_host_id == GST_context->host_id)
970 LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
971 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
974 if ((delegated_host_id >= GST_host_list_size) ||
975 (NULL == GST_host_list[delegated_host_id]))
977 LOG (GNUNET_ERROR_TYPE_WARNING,
978 "Delegated host %u not registered with us\n", delegated_host_id);
979 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
982 slave_host_id = ntohl (msg->slave_host_id);
983 if ((slave_host_id >= GST_host_list_size) ||
984 (NULL == GST_host_list[slave_host_id]))
986 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
988 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
991 if (slave_host_id == delegated_host_id)
993 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
994 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
997 op_id = GNUNET_ntohll (msg->operation_id);
998 if (slave_host_id == GST_context->host_id) /* Link from us */
1000 struct Slave *slave;
1001 struct LinkControllersContext *lcc;
1004 if (1 != msg->is_subordinate)
1006 struct Neighbour *n;
1007 struct NeighbourConnectCtxt *ncc;
1009 if ((delegated_host_id < neighbour_list_size) &&
1010 (NULL != neighbour_list[delegated_host_id]))
1013 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1016 LOG_DEBUG ("Received request to establish a link to host %u\n",
1018 n = GNUNET_malloc (sizeof (struct Neighbour));
1019 n->host_id = delegated_host_id;
1020 neighbour_list_add (n); /* just add; connect on-demand */
1021 ncc = GNUNET_malloc (sizeof (struct NeighbourConnectCtxt));
1024 ncc->client = client;
1025 GNUNET_SERVER_client_keep (client);
1026 ncc->nh = GST_neighbour_get_connection (n, neighbour_connect_cb, ncc);
1027 ncc->timeout_task = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1028 &timeout_neighbour_connect,
1030 GNUNET_CONTAINER_DLL_insert_tail (ncc_head, ncc_tail, ncc);
1031 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1034 if ((delegated_host_id < GST_slave_list_size) &&
1035 (NULL != GST_slave_list[delegated_host_id]))
1038 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1041 LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1043 slave = GNUNET_malloc (sizeof (struct Slave));
1044 slave->host_id = delegated_host_id;
1045 slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
1046 slave_list_add (slave);
1047 lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
1048 lcc->operation_id = op_id;
1049 GNUNET_SERVER_client_keep (client);
1050 lcc->client = client;
1052 slave->controller_proc =
1053 GNUNET_TESTBED_controller_start (GST_context->master_ip,
1054 GST_host_list[slave->host_id],
1055 &slave_status_callback, slave);
1056 new_route = GNUNET_malloc (sizeof (struct Route));
1057 new_route->dest = delegated_host_id;
1058 new_route->thru = GST_context->host_id;
1059 route_list_add (new_route);
1063 /* Route the request */
1064 if (slave_host_id >= route_list_size)
1066 LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1067 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1070 lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
1071 lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
1072 lcfq->lcf->type = CLOSURE_TYPE_LCF;
1073 lcfq->lcf->delegated_host_id = delegated_host_id;
1074 lcfq->lcf->slave_host_id = slave_host_id;
1075 route = GST_find_dest_route (slave_host_id);
1076 GNUNET_assert (NULL != route); /* because we add routes carefully */
1077 GNUNET_assert (route->dest < GST_slave_list_size);
1078 GNUNET_assert (NULL != GST_slave_list[route->dest]);
1079 lcfq->lcf->is_subordinate = msg->is_subordinate;
1080 lcfq->lcf->state = INIT;
1081 lcfq->lcf->operation_id = op_id;
1082 lcfq->lcf->gateway = GST_slave_list[route->dest];
1083 GNUNET_SERVER_client_keep (client);
1084 lcfq->lcf->client = client;
1085 if (NULL == lcfq_head)
1087 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1088 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1089 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
1092 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1093 /* FIXME: Adding a new route should happen after the controllers are linked
1095 if (1 != msg->is_subordinate)
1097 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1100 if ((delegated_host_id < route_list_size) &&
1101 (NULL != route_list[delegated_host_id]))
1103 GNUNET_break_op (0); /* Are you trying to link delegated host twice
1104 * with is subordinate flag set to GNUNET_YES? */
1105 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1108 new_route = GNUNET_malloc (sizeof (struct Route));
1109 new_route->dest = delegated_host_id;
1110 new_route->thru = route->dest;
1111 route_list_add (new_route);
1112 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1117 * Cleans up the queue used for forwarding link controllers requests
1122 struct LCFContextQueue *lcfq;
1124 if (NULL != lcfq_head)
1126 if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
1128 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1129 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1132 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1133 for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
1135 GNUNET_SERVER_client_drop (lcfq->lcf->client);
1136 GNUNET_free (lcfq->lcf);
1137 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);