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 gateway which will pass the link message to delegated host
80 struct Slave *gateway;
83 * The client which has asked to perform this operation
85 struct GNUNET_SERVER_Client *client;
88 * Handle for operations which are forwarded while linking controllers
90 struct GNUNET_TESTBED_Operation *op;
95 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
98 * The id of the operation which created this context
100 uint64_t operation_id;
103 * should the slave controller start the delegated controller?
108 * The state of this context
110 enum LCFContextState state;
115 uint32_t delegated_host_id;
120 uint32_t slave_host_id;
126 * Structure of a queue entry in LCFContext request queue
128 struct LCFContextQueue
133 struct LCFContext *lcf;
138 struct LCFContextQueue *next;
143 struct LCFContextQueue *prev;
148 * Notification context to be used to notify when connection to the neighbour's
149 * controller is opened
151 struct NeighbourConnectNotification
154 * DLL next for inclusion in neighbour's list of notification requests
156 struct NeighbourConnectNotification *next;
161 struct NeighbourConnectNotification *prev;
169 * The notification callback to call when we are connect to neighbour
171 GST_NeigbourConnectNotifyCallback cb;
174 * The closure for the above callback
181 * A connected controller which is not our child
186 * The controller handle
188 struct GNUNET_TESTBED_Controller *controller;
191 * Operation handle for opening a lateral connection to another controller.
192 * Will be NULL if the slave controller is started by this controller
194 struct GNUNET_TESTBED_Operation *conn_op;
197 * DLL head for the list of notification requests
199 struct NeighbourConnectNotification *nl_head;
202 * DLL tail for the list of notification requests
204 struct NeighbourConnectNotification *nl_tail;
207 * Task id for the task to call notifications from the notification list
209 GNUNET_SCHEDULER_TaskIdentifier notify_task;
212 * How many references are present currently to this neighbour's connection
214 unsigned int reference_cnt;
217 * Is the conn_op inactivated?
219 unsigned int inactive;
222 * The id of the host this controller is running on
231 static struct Neighbour **neighbour_list;
234 * The size of the neighbour list
236 static unsigned int neighbour_list_size;
240 * Context information for establishing a link to neighbour (Used is
241 * GST_handle_link_controllers()
243 struct NeighbourConnectCtxt
246 * DLL next for inclusion in the corresponding context list
248 struct NeighbourConnectCtxt *next;
253 struct NeighbourConnectCtxt *prev;
256 * The neighbour to whom connection should be made
261 * The client requesting the connection
263 struct GNUNET_SERVER_Client *client;
266 * Task to be run upon timeout
268 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
271 * The notification handle associated with the neighbour's connection request
273 struct NeighbourConnectNotification *nh;
276 * The id of the link-controllers operation responsible for creating this
283 * DLL head for the list of neighbour connect contexts
285 struct NeighbourConnectCtxt *ncc_head;
288 * DLL tail for the list of neighbour connect contexts
290 struct NeighbourConnectCtxt *ncc_tail;
293 * A list of directly linked neighbours
295 struct Slave **GST_slave_list;
298 * The size of directly linked neighbours list
300 unsigned int GST_slave_list_size;
305 static struct Route **route_list;
308 * The head for the LCF queue
310 static struct LCFContextQueue *lcfq_head;
313 * The tail for the LCF queue
315 static struct LCFContextQueue *lcfq_tail;
318 * The lcf_task handle
320 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
323 * The size of the route list
325 static unsigned int route_list_size;
329 * Adds a slave to the slave array
331 * @param slave the slave controller to add
334 slave_list_add (struct Slave *slave)
336 if (slave->host_id >= GST_slave_list_size)
337 GST_array_grow_large_enough (GST_slave_list, GST_slave_list_size,
339 GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
340 GST_slave_list[slave->host_id] = slave;
345 * Adds a route to the route list
347 * @param route the route to add
350 route_list_add (struct Route *route)
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;
360 * Add a neighbour to the neighbour list. Grows the neighbour list
363 * @param n the neighbour to add
366 neighbour_list_add (struct Neighbour *n)
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;
376 * Cleans up the route list
379 GST_route_list_clear ()
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);
392 * Iterator for freeing hash map entries in a slave's reghost_map
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
402 reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key,
405 struct Slave *slave = cls;
406 struct RegisteredHostContext *rhc = value;
407 struct ForwardedOverlayConnectContext *focc;
409 GNUNET_assert (GNUNET_YES ==
410 GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
412 while (NULL != (focc = rhc->focc_dll_head))
414 GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
415 GST_cleanup_focc (focc);
423 * Cleans up the slave list
426 GST_slave_list_clear ()
428 struct HostRegistration *hr_entry;
429 struct GNUNET_TESTBED_ControllerProc *cproc;
432 for (id = 0; id < GST_slave_list_size; id++)
434 if (NULL == GST_slave_list[id])
436 while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head))
438 GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head,
439 GST_slave_list[id]->hr_dll_tail, hr_entry);
440 GNUNET_free (hr_entry);
442 if (NULL != GST_slave_list[id]->rhandle)
443 GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle);
445 GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list
447 reghost_free_iterator,
449 GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map);
450 if (NULL != GST_slave_list[id]->controller)
451 GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller);
452 if (NULL != (cproc = GST_slave_list[id]->controller_proc))
454 LOG_DEBUG ("Stopping a slave\n");
455 GNUNET_TESTBED_controller_kill_ (cproc);
458 for (id = 0; id < GST_slave_list_size; id++)
460 if (NULL == GST_slave_list[id])
462 if (NULL != (cproc = GST_slave_list[id]->controller_proc))
464 GNUNET_TESTBED_controller_destroy_ (cproc);
465 LOG_DEBUG ("Slave stopped\n");
467 GNUNET_free (GST_slave_list[id]);
469 GNUNET_free_non_null (GST_slave_list);
470 GST_slave_list = NULL;
475 * Finds the route with directly connected host as destination through which
476 * the destination host can be reached
478 * @param host_id the id of the destination host
479 * @return the route with directly connected destination host; NULL if no route
483 GST_find_dest_route (uint32_t host_id)
487 if (route_list_size <= host_id)
489 while (NULL != (route = route_list[host_id]))
491 if (route->thru == GST_context->host_id)
493 host_id = route->thru;
500 * Function to send a failure reponse for controller link operation
502 * @param client the client to send the message to
503 * @param operation_id the operation ID of the controller link request
504 * @param cfg the configuration with which the delegated controller is started.
505 * Can be NULL if the delegated controller is not started but just
507 * @param emsg set to an error message explaining why the controller link
508 * failed. Setting this to NULL signifies success. !This should be
509 * NULL if cfg is set!
512 send_controller_link_response (struct GNUNET_SERVER_Client *client,
513 uint64_t operation_id,
514 const struct GNUNET_CONFIGURATION_Handle
518 struct GNUNET_TESTBED_ControllerLinkResponse *msg;
524 GNUNET_assert ((NULL == cfg) || (NULL == emsg));
528 msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse);
531 xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
534 msize += xconfig_size;
537 msize += strlen (emsg);
538 msg = GNUNET_malloc (msize);
539 msg->header.type = htons
540 (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
541 msg->header.size = htons (msize);
543 msg->success = htons (GNUNET_YES);
544 msg->operation_id = GNUNET_htonll (operation_id);
545 msg->config_size = htons ((uint16_t) config_size);
548 memcpy (&msg[1], xconfig, xconfig_size);
549 GNUNET_free (xconfig);
552 memcpy (&msg[1], emsg, strlen (emsg));
553 GST_queue_message (client, &msg->header);
558 * The Link Controller forwarding task
560 * @param cls the LCFContext
561 * @param tc the Task context from scheduler
564 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
568 * Completion callback for host registrations while forwarding Link Controller messages
570 * @param cls the LCFContext
571 * @param emsg the error message; NULL if host registration is successful
574 lcf_proc_cc (void *cls, const char *emsg)
576 struct LCFContext *lcf = cls;
578 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
583 goto registration_error;
584 lcf->state = DELEGATED_HOST_REGISTERED;
585 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
587 case DELEGATED_HOST_REGISTERED:
589 goto registration_error;
590 lcf->state = SLAVE_HOST_REGISTERED;
591 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
594 GNUNET_assert (0); /* Shouldn't reach here */
599 LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
601 lcf->state = FINISHED;
602 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
607 * The Link Controller forwarding task
609 * @param cls the LCFContext
610 * @param tc the Task context from scheduler
613 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
617 * Task to free resources when forwarded link controllers has been timedout
619 * @param cls the LCFContext
620 * @param tc the task context from scheduler
623 lcf_forwarded_operation_timeout (void *cls,
624 const struct GNUNET_SCHEDULER_TaskContext *tc)
626 struct LCFContext *lcf = cls;
628 lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK;
629 // GST_forwarded_operation_timeout (lcf->fopc, tc);
630 LOG (GNUNET_ERROR_TYPE_WARNING,
631 "A forwarded controller link operation has timed out\n");
632 send_controller_link_response (lcf->client, lcf->operation_id, NULL,
633 "A forwarded controller link operation has "
635 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
636 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
641 * The Link Controller forwarding task
643 * @param cls the LCFContext
644 * @param tc the Task context from scheduler
647 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
649 struct LCFContext *lcf = cls;
650 struct LCFContextQueue *lcfq;
652 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
657 GNUNET_TESTBED_is_host_registered_ (GST_host_list
658 [lcf->delegated_host_id],
659 lcf->gateway->controller))
661 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
662 GST_host_list[lcf->delegated_host_id]);
666 lcf->state = DELEGATED_HOST_REGISTERED;
667 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
670 case DELEGATED_HOST_REGISTERED:
672 GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
673 lcf->gateway->controller))
675 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
676 GST_host_list[lcf->slave_host_id]);
680 lcf->state = SLAVE_HOST_REGISTERED;
681 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
684 case SLAVE_HOST_REGISTERED:
685 lcf->op = GNUNET_TESTBED_controller_link (lcf,
686 lcf->gateway->controller,
687 GST_host_list[lcf->delegated_host_id],
688 GST_host_list[lcf->slave_host_id],
689 lcf->is_subordinate);
691 GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout,
693 lcf->state = FINISHED;
697 GNUNET_assert (lcfq->lcf == lcf);
698 GNUNET_SERVER_client_drop (lcf->client);
699 GNUNET_TESTBED_operation_done (lcf->op);
701 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
703 if (NULL != lcfq_head)
705 GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
711 * Callback for event from slave controllers
714 * @param event information about the event
717 slave_event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
719 struct LCFContext *lcf;
721 /* We currently only get here when working on RegisteredHostContexts and
723 GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
725 GNUNET_assert (lcf->op == event->op);
726 GNUNET_assert (FINISHED == lcf->state);
727 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task);
728 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
729 if (NULL == event->details.operation_finished.emsg)
730 send_controller_link_response (lcf->client, lcf->operation_id,
731 GNUNET_TESTBED_host_get_cfg_
732 (GST_host_list[lcf->delegated_host_id]),
735 send_controller_link_response (lcf->client, lcf->operation_id,
737 event->details.operation_finished.emsg);
738 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
739 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
745 * Callback to signal successfull startup of the controller process
747 * @param cls the handle to the slave whose status is to be found here
748 * @param cfg the configuration with which the controller has been started;
749 * NULL if status is not GNUNET_OK
750 * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
751 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
754 slave_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
757 struct Slave *slave = cls;
758 struct LinkControllersContext *lcc;
761 if (GNUNET_SYSERR == status)
763 slave->controller_proc = NULL;
764 GST_slave_list[slave->host_id] = NULL;
767 LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
768 GNUNET_SCHEDULER_shutdown (); /* We too shutdown */
772 GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
773 EVENT_MASK, &slave_event_cb,
775 if (NULL != slave->controller)
777 send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
781 send_controller_link_response (lcc->client, lcc->operation_id, NULL,
782 "Could not connect to delegated controller");
783 GNUNET_TESTBED_controller_stop (slave->controller_proc);
784 GST_slave_list[slave->host_id] = NULL;
792 if (NULL != lcc->client)
794 GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
795 GNUNET_SERVER_client_drop (lcc->client);
806 * Trigger notification task if there are notification requests currently
807 * waiting in the given neighbour. Also activates the neighbour connect operation
808 * if it was previously inactivated so that the connection to the neighbour can
811 * @param n the neighbour
814 trigger_notifications (struct Neighbour *n);
818 * Task to call the notification queued in the notifications list of the given
821 * @param cls the neighbour
822 * @param tc scheduler task context
825 neighbour_connect_notify_task (void *cls,
826 const struct GNUNET_SCHEDULER_TaskContext *tc)
828 struct Neighbour *n = cls;
829 struct NeighbourConnectNotification *h;
831 GNUNET_assert (NULL != (h = n->nl_head));
832 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->notify_task);
833 n->notify_task = GNUNET_SCHEDULER_NO_TASK;
834 GNUNET_assert (NULL != n->controller);
835 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
836 trigger_notifications (n);
837 h->cb (h->cb_cls, n->controller);
843 * Trigger notification task if there are notification requests currently
844 * waiting in the given neighbour. Also activates the neighbour connect operation
845 * if it was previously inactivated so that the connection to the neighbour can
848 * @param n the neighbour
851 trigger_notifications (struct Neighbour *n)
853 GNUNET_assert (NULL != n->conn_op);
854 if (NULL == n->nl_head)
856 if (NULL == n->controller)
858 if (GNUNET_SCHEDULER_NO_TASK != n->notify_task)
860 if (1 == n->inactive)
862 GNUNET_assert (0 == n->reference_cnt);
863 GNUNET_TESTBED_operation_activate_ (n->conn_op);
868 GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n);
873 * Callback to be called when the neighbour connect operation is started. The
874 * connection to the neigbour is opened here and any pending notifications are
877 * @param cls the neighbour
880 opstart_neighbour_conn (void *cls)
882 struct Neighbour *n = cls;
884 GNUNET_assert (NULL != n->conn_op);
885 GNUNET_assert (NULL == n->controller);
886 LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
887 n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
891 trigger_notifications (n);
896 * Callback to be called when the neighbour connect operation is released
898 * @param cls the neighbour
901 oprelease_neighbour_conn (void *cls)
903 struct Neighbour *n = cls;
905 GNUNET_assert (0 == n->reference_cnt);
906 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->notify_task);
907 GNUNET_assert (NULL == n->nl_head);
908 if (NULL != n->controller)
910 LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
911 GNUNET_TESTBED_controller_disconnect (n->controller);
912 n->controller = NULL;
920 * Try to open a connection to the given neigbour. If the connection is open
921 * already, then it is re-used. If not, the request is queued in the operation
922 * queues responsible for bounding the total number of file descriptors. The
923 * actual connection will happen when the operation queue marks the
924 * corresponding operation as active.
926 * @param n the neighbour to open a connection to
927 * @param cb the notification callback to call when the connection is opened
928 * @param cb_cls the closure for the above callback
930 struct NeighbourConnectNotification *
931 GST_neighbour_get_connection (struct Neighbour *n,
932 GST_NeigbourConnectNotifyCallback cb,
935 struct NeighbourConnectNotification *h;
937 GNUNET_assert (NULL != cb);
938 LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
940 h = GNUNET_malloc (sizeof (struct NeighbourConnectNotification));
944 GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
945 if (NULL == n->conn_op)
947 GNUNET_assert (NULL == n->controller);
948 n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
949 &oprelease_neighbour_conn);
950 GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
951 GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
954 trigger_notifications (n);
960 * Cancel the request for opening a connection to the neighbour
962 * @param h the notification handle
965 GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
971 cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
972 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
974 if (GNUNET_NO == cleanup_task)
976 if (GNUNET_SCHEDULER_NO_TASK == n->notify_task)
978 GNUNET_assert (0 < n->reference_cnt);
980 GNUNET_SCHEDULER_cancel (n->notify_task);
981 n->notify_task = GNUNET_SCHEDULER_NO_TASK;
982 if (NULL == n->nl_head)
984 if ( (0 == n->reference_cnt) && (0 == n->inactive) )
987 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
991 trigger_notifications (n);
996 * Release the connection to the neighbour. The actual connection will be
997 * closed if connections to other neighbour are waiting (to maintain a bound on
998 * the total number of connections that are open).
1000 * @param n the neighbour whose connection can be closed
1003 GST_neighbour_release_connection (struct Neighbour *n)
1005 GNUNET_assert (0 == n->inactive);
1006 GNUNET_assert (0 < n->reference_cnt);
1008 if (0 == n->reference_cnt)
1011 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1017 * Cleanup neighbour connect contexts
1019 * @param ncc the neighbour connect context to cleanup
1022 cleanup_ncc (struct NeighbourConnectCtxt *ncc)
1024 if (NULL != ncc->nh)
1025 GST_neighbour_get_connection_cancel (ncc->nh);
1026 if (GNUNET_SCHEDULER_NO_TASK != ncc->timeout_task)
1027 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1028 GNUNET_SERVER_client_drop (ncc->client);
1029 GNUNET_CONTAINER_DLL_remove (ncc_head, ncc_tail, ncc);
1035 * Cleans up the neighbour list
1038 GST_neighbour_list_clean()
1040 struct Neighbour *n;
1043 for (id = 0; id < neighbour_list_size; id++)
1045 if (NULL == (n = neighbour_list[id]))
1047 if (NULL != n->conn_op)
1048 GNUNET_TESTBED_operation_release_ (n->conn_op);
1050 neighbour_list[id] = NULL;
1052 GNUNET_free_non_null (neighbour_list);
1057 * Get a neighbour from the neighbour list
1059 * @param id the index of the neighbour in the neighbour list
1060 * @return the Neighbour; NULL if the given index in invalid (index greater than
1061 * the list size or neighbour at that index is NULL)
1064 GST_get_neighbour (uint32_t id)
1066 if (neighbour_list_size <= id)
1069 return neighbour_list[id];
1074 * Function to cleanup the neighbour connect contexts
1079 while (NULL != ncc_head)
1080 cleanup_ncc (ncc_head);
1085 * Task to be run upon timeout while attempting to connect to the neighbour
1087 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1088 * @param tc the scheduler task context
1091 timeout_neighbour_connect (void *cls,
1092 const struct GNUNET_SCHEDULER_TaskContext *tc)
1094 struct NeighbourConnectCtxt *ncc = cls;
1096 ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1097 send_controller_link_response (ncc->client, ncc->op_id, NULL,
1098 "Could not connect to delegated controller");
1104 * Callback called when a connection to the neighbour is made
1106 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1107 * @param c the handle the neighbour's controller
1110 neighbour_connect_cb (void *cls, struct GNUNET_TESTBED_Controller *c)
1112 struct NeighbourConnectCtxt *ncc = cls;
1114 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1115 ncc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1117 GST_neighbour_release_connection (ncc->n);
1118 send_controller_link_response (ncc->client, ncc->op_id, NULL, NULL);
1124 * Function to create a neigbour and add it into the neighbour list
1126 * @param host the host of the neighbour
1129 GST_create_neighbour (struct GNUNET_TESTBED_Host *host)
1131 struct Neighbour *n;
1133 n = GNUNET_malloc (sizeof (struct Neighbour));
1134 n->host_id = GNUNET_TESTBED_host_get_id_ (host);
1135 neighbour_list_add (n); /* just add; connect on-demand */
1141 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1144 * @param client identification of the client
1145 * @param message the actual message
1148 GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
1149 const struct GNUNET_MessageHeader *message)
1151 const struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1152 struct LCFContextQueue *lcfq;
1153 struct Route *route;
1154 struct Route *new_route;
1156 uint32_t delegated_host_id;
1157 uint32_t slave_host_id;
1159 if (NULL == GST_context)
1162 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1165 msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message;
1166 delegated_host_id = ntohl (msg->delegated_host_id);
1167 if (delegated_host_id == GST_context->host_id)
1170 LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
1171 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1174 if ((delegated_host_id >= GST_host_list_size) ||
1175 (NULL == GST_host_list[delegated_host_id]))
1177 LOG (GNUNET_ERROR_TYPE_WARNING,
1178 "Delegated host %u not registered with us\n", delegated_host_id);
1179 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1182 slave_host_id = ntohl (msg->slave_host_id);
1183 if ((slave_host_id >= GST_host_list_size) ||
1184 (NULL == GST_host_list[slave_host_id]))
1186 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
1188 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1191 if (slave_host_id == delegated_host_id)
1193 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
1194 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1197 op_id = GNUNET_ntohll (msg->operation_id);
1198 if (slave_host_id == GST_context->host_id) /* Link from us */
1200 struct Slave *slave;
1201 struct LinkControllersContext *lcc;
1204 if (1 != msg->is_subordinate)
1206 struct Neighbour *n;
1207 struct NeighbourConnectCtxt *ncc;
1209 if ((delegated_host_id < neighbour_list_size) &&
1210 (NULL != neighbour_list[delegated_host_id]))
1213 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1216 LOG_DEBUG ("Received request to establish a link to host %u\n",
1218 n = GST_create_neighbour (GST_host_list[delegated_host_id]);
1219 ncc = GNUNET_malloc (sizeof (struct NeighbourConnectCtxt));
1222 ncc->client = client;
1223 GNUNET_SERVER_client_keep (client);
1224 ncc->nh = GST_neighbour_get_connection (n, neighbour_connect_cb, ncc);
1225 ncc->timeout_task = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1226 &timeout_neighbour_connect,
1228 GNUNET_CONTAINER_DLL_insert_tail (ncc_head, ncc_tail, ncc);
1229 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1232 if ((delegated_host_id < GST_slave_list_size) &&
1233 (NULL != GST_slave_list[delegated_host_id]))
1236 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1239 LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1241 slave = GNUNET_malloc (sizeof (struct Slave));
1242 slave->host_id = delegated_host_id;
1243 slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
1244 slave_list_add (slave);
1245 lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
1246 lcc->operation_id = op_id;
1247 GNUNET_SERVER_client_keep (client);
1248 lcc->client = client;
1250 slave->controller_proc =
1251 GNUNET_TESTBED_controller_start (GST_context->master_ip,
1252 GST_host_list[slave->host_id],
1253 &slave_status_cb, slave);
1254 new_route = GNUNET_malloc (sizeof (struct Route));
1255 new_route->dest = delegated_host_id;
1256 new_route->thru = GST_context->host_id;
1257 route_list_add (new_route);
1261 /* Route the request */
1262 if (slave_host_id >= route_list_size)
1264 LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1265 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1268 lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
1269 lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
1270 lcfq->lcf->delegated_host_id = delegated_host_id;
1271 lcfq->lcf->slave_host_id = slave_host_id;
1272 route = GST_find_dest_route (slave_host_id);
1273 GNUNET_assert (NULL != route); /* because we add routes carefully */
1274 GNUNET_assert (route->dest < GST_slave_list_size);
1275 GNUNET_assert (NULL != GST_slave_list[route->dest]);
1276 lcfq->lcf->is_subordinate = msg->is_subordinate;
1277 lcfq->lcf->state = INIT;
1278 lcfq->lcf->operation_id = op_id;
1279 lcfq->lcf->gateway = GST_slave_list[route->dest];
1280 GNUNET_SERVER_client_keep (client);
1281 lcfq->lcf->client = client;
1282 if (NULL == lcfq_head)
1284 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1285 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1286 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
1289 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1290 /* FIXME: Adding a new route should happen after the controllers are linked
1292 if (1 != msg->is_subordinate)
1294 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1297 if ((delegated_host_id < route_list_size) &&
1298 (NULL != route_list[delegated_host_id]))
1300 GNUNET_break_op (0); /* Are you trying to link delegated host twice
1301 * with is subordinate flag set to GNUNET_YES? */
1302 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1305 new_route = GNUNET_malloc (sizeof (struct Route));
1306 new_route->dest = delegated_host_id;
1307 new_route->thru = route->dest;
1308 route_list_add (new_route);
1309 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1314 * Cleans up the queue used for forwarding link controllers requests
1319 struct LCFContextQueue *lcfq;
1321 if (NULL != lcfq_head)
1323 if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
1325 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1326 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1329 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1330 for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
1332 GNUNET_SERVER_client_drop (lcfq->lcf->client);
1333 GNUNET_free (lcfq->lcf);
1334 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);