diff options
author | Sree Harsha Totakura <totakura@in.tum.de> | 2013-04-10 13:04:30 +0000 |
---|---|---|
committer | Sree Harsha Totakura <totakura@in.tum.de> | 2013-04-10 13:04:30 +0000 |
commit | dd2b8d87339226bb3e9a04f7111561740328c40e (patch) | |
tree | 8b3911859227fe2548d7e016b48d0c226809f966 | |
parent | 5c978455a6937620b4d6cfbca428c604096d7ed1 (diff) | |
download | gnunet-dd2b8d87339226bb3e9a04f7111561740328c40e.tar.gz gnunet-dd2b8d87339226bb3e9a04f7111561740328c40e.zip |
- restructure
-rw-r--r-- | src/testbed/Makefile.am | 3 | ||||
-rw-r--r-- | src/testbed/gnunet-service-testbed.c | 706 | ||||
-rw-r--r-- | src/testbed/gnunet-service-testbed.h | 33 | ||||
-rw-r--r-- | src/testbed/gnunet-service-testbed_links.c | 760 |
4 files changed, 799 insertions, 703 deletions
diff --git a/src/testbed/Makefile.am b/src/testbed/Makefile.am index 97e304ff3..6b8b44089 100644 --- a/src/testbed/Makefile.am +++ b/src/testbed/Makefile.am | |||
@@ -32,10 +32,11 @@ bin_PROGRAMS = \ | |||
32 | gnunet_service_testbed_SOURCES = \ | 32 | gnunet_service_testbed_SOURCES = \ |
33 | gnunet-service-testbed.h \ | 33 | gnunet-service-testbed.h \ |
34 | gnunet-service-testbed.c \ | 34 | gnunet-service-testbed.c \ |
35 | gnunet-service-testbed_links.c \ | ||
35 | gnunet-service-testbed_peers.c \ | 36 | gnunet-service-testbed_peers.c \ |
36 | gnunet-service-testbed_cache.c \ | 37 | gnunet-service-testbed_cache.c \ |
37 | gnunet-service-testbed_oc.c \ | 38 | gnunet-service-testbed_oc.c \ |
38 | gnunet-service-testbed_cpustatus.c | 39 | gnunet-service-testbed_cpustatus.c |
39 | gnunet_service_testbed_LDADD = $(XLIB) \ | 40 | gnunet_service_testbed_LDADD = $(XLIB) \ |
40 | $(top_builddir)/src/util/libgnunetutil.la \ | 41 | $(top_builddir)/src/util/libgnunetutil.la \ |
41 | $(top_builddir)/src/core/libgnunetcore.la \ | 42 | $(top_builddir)/src/core/libgnunetcore.la \ |
diff --git a/src/testbed/gnunet-service-testbed.c b/src/testbed/gnunet-service-testbed.c index 05668284b..25bded788 100644 --- a/src/testbed/gnunet-service-testbed.c +++ b/src/testbed/gnunet-service-testbed.c | |||
@@ -42,11 +42,6 @@ struct GNUNET_CONFIGURATION_Handle *our_config; | |||
42 | struct Context *GST_context; | 42 | struct Context *GST_context; |
43 | 43 | ||
44 | /** | 44 | /** |
45 | * A list of directly linked neighbours | ||
46 | */ | ||
47 | struct Slave **GST_slave_list; | ||
48 | |||
49 | /** | ||
50 | * Array of hosts | 45 | * Array of hosts |
51 | */ | 46 | */ |
52 | struct GNUNET_TESTBED_Host **GST_host_list; | 47 | struct GNUNET_TESTBED_Host **GST_host_list; |
@@ -77,11 +72,6 @@ const struct GNUNET_TIME_Relative GST_timeout; | |||
77 | unsigned int GST_host_list_size; | 72 | unsigned int GST_host_list_size; |
78 | 73 | ||
79 | /** | 74 | /** |
80 | * The size of directly linked neighbours list | ||
81 | */ | ||
82 | unsigned int GST_slave_list_size; | ||
83 | |||
84 | /** | ||
85 | * The size of the peer list | 75 | * The size of the peer list |
86 | */ | 76 | */ |
87 | unsigned int GST_peer_list_size; | 77 | unsigned int GST_peer_list_size; |
@@ -128,16 +118,6 @@ static char *hostname; | |||
128 | static struct GNUNET_SERVER_TransmitHandle *transmit_handle; | 118 | static struct GNUNET_SERVER_TransmitHandle *transmit_handle; |
129 | 119 | ||
130 | /** | 120 | /** |
131 | * The head for the LCF queue | ||
132 | */ | ||
133 | static struct LCFContextQueue *lcfq_head; | ||
134 | |||
135 | /** | ||
136 | * The tail for the LCF queue | ||
137 | */ | ||
138 | static struct LCFContextQueue *lcfq_tail; | ||
139 | |||
140 | /** | ||
141 | * The message queue head | 121 | * The message queue head |
142 | */ | 122 | */ |
143 | static struct MessageQueue *mq_head; | 123 | static struct MessageQueue *mq_head; |
@@ -153,26 +133,6 @@ static struct MessageQueue *mq_tail; | |||
153 | static struct GNUNET_CONTAINER_MultiHashMap *ss_map; | 133 | static struct GNUNET_CONTAINER_MultiHashMap *ss_map; |
154 | 134 | ||
155 | /** | 135 | /** |
156 | * A list of routes | ||
157 | */ | ||
158 | static struct Route **route_list; | ||
159 | |||
160 | /** | ||
161 | * The event mask for the events we listen from sub-controllers | ||
162 | */ | ||
163 | static uint64_t event_mask; | ||
164 | |||
165 | /** | ||
166 | * The size of the route list | ||
167 | */ | ||
168 | static unsigned int route_list_size; | ||
169 | |||
170 | /** | ||
171 | * The lcf_task handle | ||
172 | */ | ||
173 | static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id; | ||
174 | |||
175 | /** | ||
176 | * The shutdown task handle | 136 | * The shutdown task handle |
177 | */ | 137 | */ |
178 | static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id; | 138 | static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id; |
@@ -275,62 +235,6 @@ host_list_add (struct GNUNET_TESTBED_Host *host) | |||
275 | 235 | ||
276 | 236 | ||
277 | /** | 237 | /** |
278 | * Adds a route to the route list | ||
279 | * | ||
280 | * @param route the route to add | ||
281 | */ | ||
282 | static void | ||
283 | route_list_add (struct Route *route) | ||
284 | { | ||
285 | if (route->dest >= route_list_size) | ||
286 | GST_array_grow_large_enough (route_list, route_list_size, route->dest); | ||
287 | GNUNET_assert (NULL == route_list[route->dest]); | ||
288 | route_list[route->dest] = route; | ||
289 | } | ||
290 | |||
291 | |||
292 | /** | ||
293 | * Adds a slave to the slave array | ||
294 | * | ||
295 | * @param slave the slave controller to add | ||
296 | */ | ||
297 | static void | ||
298 | slave_list_add (struct Slave *slave) | ||
299 | { | ||
300 | if (slave->host_id >= GST_slave_list_size) | ||
301 | GST_array_grow_large_enough (GST_slave_list, GST_slave_list_size, | ||
302 | slave->host_id); | ||
303 | GNUNET_assert (NULL == GST_slave_list[slave->host_id]); | ||
304 | GST_slave_list[slave->host_id] = slave; | ||
305 | } | ||
306 | |||
307 | |||
308 | /** | ||
309 | * Finds the route with directly connected host as destination through which | ||
310 | * the destination host can be reached | ||
311 | * | ||
312 | * @param host_id the id of the destination host | ||
313 | * @return the route with directly connected destination host; NULL if no route | ||
314 | * is found | ||
315 | */ | ||
316 | struct Route * | ||
317 | GST_find_dest_route (uint32_t host_id) | ||
318 | { | ||
319 | struct Route *route; | ||
320 | |||
321 | if (route_list_size <= host_id) | ||
322 | return NULL; | ||
323 | while (NULL != (route = route_list[host_id])) | ||
324 | { | ||
325 | if (route->thru == GST_context->host_id) | ||
326 | break; | ||
327 | host_id = route->thru; | ||
328 | } | ||
329 | return route; | ||
330 | } | ||
331 | |||
332 | |||
333 | /** | ||
334 | * Routes message to a host given its host_id | 238 | * Routes message to a host given its host_id |
335 | * | 239 | * |
336 | * @param host_id the id of the destination host | 240 | * @param host_id the id of the destination host |
@@ -395,61 +299,6 @@ GST_send_operation_success_msg (struct GNUNET_SERVER_Client *client, | |||
395 | GST_queue_message (client, &msg->header); | 299 | GST_queue_message (client, &msg->header); |
396 | } | 300 | } |
397 | 301 | ||
398 | |||
399 | /** | ||
400 | * Function to send a failure reponse for controller link operation | ||
401 | * | ||
402 | * @param client the client to send the message to | ||
403 | * @param operation_id the operation ID of the controller link request | ||
404 | * @param cfg the configuration with which the delegated controller is started. | ||
405 | * Can be NULL if the delegated controller is not started but just | ||
406 | * linked to. | ||
407 | * @param emsg set to an error message explaining why the controller link | ||
408 | * failed. Setting this to NULL signifies success. !This should be | ||
409 | * NULL if cfg is set! | ||
410 | */ | ||
411 | static void | ||
412 | send_controller_link_response (struct GNUNET_SERVER_Client *client, | ||
413 | uint64_t operation_id, | ||
414 | const struct GNUNET_CONFIGURATION_Handle | ||
415 | *cfg, | ||
416 | const char *emsg) | ||
417 | { | ||
418 | struct GNUNET_TESTBED_ControllerLinkResponse *msg; | ||
419 | char *xconfig; | ||
420 | size_t config_size; | ||
421 | size_t xconfig_size; | ||
422 | uint16_t msize; | ||
423 | |||
424 | GNUNET_assert ((NULL == cfg) || (NULL == emsg)); | ||
425 | xconfig = NULL; | ||
426 | xconfig_size = 0; | ||
427 | config_size = 0; | ||
428 | msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse); | ||
429 | if (NULL != cfg) | ||
430 | { | ||
431 | xconfig = GNUNET_TESTBED_compress_cfg_ (cfg, | ||
432 | &config_size, | ||
433 | &xconfig_size); | ||
434 | msize += xconfig_size; | ||
435 | } | ||
436 | if (NULL != emsg) | ||
437 | msize += strlen (emsg); | ||
438 | msg = GNUNET_malloc (msize); | ||
439 | msg->header.type = htons | ||
440 | (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT); | ||
441 | msg->header.size = htons (msize); | ||
442 | if (NULL == emsg) | ||
443 | msg->success = htons (GNUNET_YES); | ||
444 | msg->operation_id = GNUNET_htonll (operation_id); | ||
445 | msg->config_size = htons ((uint16_t) config_size); | ||
446 | if (NULL != xconfig) | ||
447 | memcpy (&msg[1], xconfig, xconfig_size); | ||
448 | if (NULL != emsg) | ||
449 | memcpy (&msg[1], emsg, strlen (emsg)); | ||
450 | GST_queue_message (client, &msg->header); | ||
451 | } | ||
452 | |||
453 | /** | 302 | /** |
454 | * Callback which will be called after a host registration succeeded or failed | 303 | * Callback which will be called after a host registration succeeded or failed |
455 | * | 304 | * |
@@ -543,55 +392,6 @@ GST_queue_host_registration (struct Slave *slave, | |||
543 | 392 | ||
544 | 393 | ||
545 | /** | 394 | /** |
546 | * The Link Controller forwarding task | ||
547 | * | ||
548 | * @param cls the LCFContext | ||
549 | * @param tc the Task context from scheduler | ||
550 | */ | ||
551 | static void | ||
552 | lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
553 | |||
554 | |||
555 | /** | ||
556 | * Completion callback for host registrations while forwarding Link Controller messages | ||
557 | * | ||
558 | * @param cls the LCFContext | ||
559 | * @param emsg the error message; NULL if host registration is successful | ||
560 | */ | ||
561 | static void | ||
562 | lcf_proc_cc (void *cls, const char *emsg) | ||
563 | { | ||
564 | struct LCFContext *lcf = cls; | ||
565 | |||
566 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); | ||
567 | switch (lcf->state) | ||
568 | { | ||
569 | case INIT: | ||
570 | if (NULL != emsg) | ||
571 | goto registration_error; | ||
572 | lcf->state = DELEGATED_HOST_REGISTERED; | ||
573 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
574 | break; | ||
575 | case DELEGATED_HOST_REGISTERED: | ||
576 | if (NULL != emsg) | ||
577 | goto registration_error; | ||
578 | lcf->state = SLAVE_HOST_REGISTERED; | ||
579 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
580 | break; | ||
581 | default: | ||
582 | GNUNET_assert (0); /* Shouldn't reach here */ | ||
583 | } | ||
584 | return; | ||
585 | |||
586 | registration_error: | ||
587 | LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n", | ||
588 | emsg); | ||
589 | lcf->state = FINISHED; | ||
590 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
591 | } | ||
592 | |||
593 | |||
594 | /** | ||
595 | * Callback to relay the reply msg of a forwarded operation back to the client | 395 | * Callback to relay the reply msg of a forwarded operation back to the client |
596 | * | 396 | * |
597 | * @param cls ForwardedOperationContext | 397 | * @param cls ForwardedOperationContext |
@@ -640,244 +440,6 @@ GST_forwarded_operation_timeout (void *cls, | |||
640 | 440 | ||
641 | 441 | ||
642 | /** | 442 | /** |
643 | * The Link Controller forwarding task | ||
644 | * | ||
645 | * @param cls the LCFContext | ||
646 | * @param tc the Task context from scheduler | ||
647 | */ | ||
648 | static void | ||
649 | lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
650 | |||
651 | |||
652 | /** | ||
653 | * Task to free resources when forwarded link controllers has been timedout | ||
654 | * | ||
655 | * @param cls the LCFContext | ||
656 | * @param tc the task context from scheduler | ||
657 | */ | ||
658 | static void | ||
659 | lcf_forwarded_operation_timeout (void *cls, | ||
660 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
661 | { | ||
662 | struct LCFContext *lcf = cls; | ||
663 | |||
664 | lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
665 | // GST_forwarded_operation_timeout (lcf->fopc, tc); | ||
666 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
667 | "A forwarded controller link operation has timed out\n"); | ||
668 | send_controller_link_response (lcf->client, lcf->operation_id, NULL, | ||
669 | "A forwarded controller link operation has " | ||
670 | "timed out\n"); | ||
671 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); | ||
672 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
673 | } | ||
674 | |||
675 | |||
676 | /** | ||
677 | * The Link Controller forwarding task | ||
678 | * | ||
679 | * @param cls the LCFContext | ||
680 | * @param tc the Task context from scheduler | ||
681 | */ | ||
682 | static void | ||
683 | lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
684 | { | ||
685 | struct LCFContext *lcf = cls; | ||
686 | struct LCFContextQueue *lcfq; | ||
687 | |||
688 | lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK; | ||
689 | switch (lcf->state) | ||
690 | { | ||
691 | case INIT: | ||
692 | if (GNUNET_NO == | ||
693 | GNUNET_TESTBED_is_host_registered_ (GST_host_list | ||
694 | [lcf->delegated_host_id], | ||
695 | lcf->gateway->controller)) | ||
696 | { | ||
697 | GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf, | ||
698 | GST_host_list[lcf->delegated_host_id]); | ||
699 | } | ||
700 | else | ||
701 | { | ||
702 | lcf->state = DELEGATED_HOST_REGISTERED; | ||
703 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
704 | } | ||
705 | break; | ||
706 | case DELEGATED_HOST_REGISTERED: | ||
707 | if (GNUNET_NO == | ||
708 | GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id], | ||
709 | lcf->gateway->controller)) | ||
710 | { | ||
711 | GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf, | ||
712 | GST_host_list[lcf->slave_host_id]); | ||
713 | } | ||
714 | else | ||
715 | { | ||
716 | lcf->state = SLAVE_HOST_REGISTERED; | ||
717 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
718 | } | ||
719 | break; | ||
720 | case SLAVE_HOST_REGISTERED: | ||
721 | lcf->op = GNUNET_TESTBED_controller_link (lcf, | ||
722 | lcf->gateway->controller, | ||
723 | GST_host_list[lcf->delegated_host_id], | ||
724 | GST_host_list[lcf->slave_host_id], | ||
725 | NULL, | ||
726 | lcf->is_subordinate); | ||
727 | lcf->timeout_task = | ||
728 | GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout, | ||
729 | lcf); | ||
730 | lcf->state = FINISHED; | ||
731 | break; | ||
732 | case FINISHED: | ||
733 | lcfq = lcfq_head; | ||
734 | GNUNET_assert (lcfq->lcf == lcf); | ||
735 | GNUNET_assert (NULL != lcf->cfg); | ||
736 | GNUNET_CONFIGURATION_destroy (lcf->cfg); | ||
737 | GNUNET_SERVER_client_drop (lcf->client); | ||
738 | GNUNET_TESTBED_operation_done (lcf->op); | ||
739 | GNUNET_free (lcf); | ||
740 | GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq); | ||
741 | GNUNET_free (lcfq); | ||
742 | if (NULL != lcfq_head) | ||
743 | lcf_proc_task_id = | ||
744 | GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf); | ||
745 | } | ||
746 | } | ||
747 | |||
748 | |||
749 | /** | ||
750 | * Callback for event from slave controllers | ||
751 | * | ||
752 | * @param cls struct Slave * | ||
753 | * @param event information about the event | ||
754 | */ | ||
755 | static void | ||
756 | slave_event_callback (void *cls, | ||
757 | const struct GNUNET_TESTBED_EventInformation *event) | ||
758 | { | ||
759 | struct RegisteredHostContext *rhc; | ||
760 | struct LCFContext *lcf; | ||
761 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
762 | struct GNUNET_TESTBED_Operation *old_op; | ||
763 | |||
764 | /* We currently only get here when working on RegisteredHostContexts and | ||
765 | LCFContexts */ | ||
766 | GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type); | ||
767 | rhc = event->op_cls; | ||
768 | if (CLOSURE_TYPE_RHC == rhc->type) | ||
769 | { | ||
770 | GNUNET_assert (rhc->sub_op == event->op); | ||
771 | switch (rhc->state) | ||
772 | { | ||
773 | case RHC_GET_CFG: | ||
774 | cfg = event->details.operation_finished.generic; | ||
775 | old_op = rhc->sub_op; | ||
776 | rhc->state = RHC_LINK; | ||
777 | rhc->sub_op = | ||
778 | GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller, | ||
779 | rhc->reg_host, rhc->host, cfg, | ||
780 | GNUNET_NO); | ||
781 | GNUNET_TESTBED_operation_done (old_op); | ||
782 | break; | ||
783 | case RHC_LINK: | ||
784 | LOG_DEBUG ("OL: Linking controllers successfull\n"); | ||
785 | GNUNET_TESTBED_operation_done (rhc->sub_op); | ||
786 | rhc->sub_op = NULL; | ||
787 | rhc->state = RHC_OL_CONNECT; | ||
788 | GST_process_next_focc (rhc); | ||
789 | break; | ||
790 | default: | ||
791 | GNUNET_assert (0); | ||
792 | } | ||
793 | return; | ||
794 | } | ||
795 | lcf = event->op_cls; | ||
796 | if (CLOSURE_TYPE_LCF == lcf->type) | ||
797 | { | ||
798 | GNUNET_assert (lcf->op == event->op); | ||
799 | GNUNET_assert (FINISHED == lcf->state); | ||
800 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task); | ||
801 | GNUNET_SCHEDULER_cancel (lcf->timeout_task); | ||
802 | if (NULL == event->details.operation_finished.emsg) | ||
803 | send_controller_link_response (lcf->client, lcf->operation_id, | ||
804 | GNUNET_TESTBED_host_get_cfg_ | ||
805 | (GST_host_list[lcf->delegated_host_id]), | ||
806 | NULL); | ||
807 | else | ||
808 | send_controller_link_response (lcf->client, lcf->operation_id, | ||
809 | NULL, | ||
810 | event->details.operation_finished.emsg); | ||
811 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); | ||
812 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
813 | return; | ||
814 | } | ||
815 | GNUNET_assert (0); | ||
816 | } | ||
817 | |||
818 | |||
819 | /** | ||
820 | * Callback to signal successfull startup of the controller process | ||
821 | * | ||
822 | * @param cls the handle to the slave whose status is to be found here | ||
823 | * @param cfg the configuration with which the controller has been started; | ||
824 | * NULL if status is not GNUNET_OK | ||
825 | * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not, | ||
826 | * GNUNET_TESTBED_controller_stop() shouldn't be called in this case | ||
827 | */ | ||
828 | static void | ||
829 | slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
830 | int status) | ||
831 | { | ||
832 | struct Slave *slave = cls; | ||
833 | struct LinkControllersContext *lcc; | ||
834 | |||
835 | lcc = slave->lcc; | ||
836 | if (GNUNET_SYSERR == status) | ||
837 | { | ||
838 | slave->controller_proc = NULL; | ||
839 | GST_slave_list[slave->host_id] = NULL; | ||
840 | GNUNET_free (slave); | ||
841 | slave = NULL; | ||
842 | LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n"); | ||
843 | GNUNET_SCHEDULER_shutdown (); /* We too shutdown */ | ||
844 | goto clean_lcc; | ||
845 | } | ||
846 | slave->controller = | ||
847 | GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id], | ||
848 | event_mask, &slave_event_callback, | ||
849 | slave); | ||
850 | if (NULL != slave->controller) | ||
851 | { | ||
852 | send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL); | ||
853 | } | ||
854 | else | ||
855 | { | ||
856 | send_controller_link_response (lcc->client, lcc->operation_id, NULL, | ||
857 | "Could not connect to delegated controller"); | ||
858 | GNUNET_TESTBED_controller_stop (slave->controller_proc); | ||
859 | GST_slave_list[slave->host_id] = NULL; | ||
860 | GNUNET_free (slave); | ||
861 | slave = NULL; | ||
862 | } | ||
863 | |||
864 | clean_lcc: | ||
865 | if (NULL != lcc) | ||
866 | { | ||
867 | if (NULL != lcc->client) | ||
868 | { | ||
869 | GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK); | ||
870 | GNUNET_SERVER_client_drop (lcc->client); | ||
871 | lcc->client = NULL; | ||
872 | } | ||
873 | GNUNET_free (lcc); | ||
874 | } | ||
875 | if (NULL != slave) | ||
876 | slave->lcc = NULL; | ||
877 | } | ||
878 | |||
879 | |||
880 | /** | ||
881 | * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages | 443 | * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages |
882 | * | 444 | * |
883 | * @param cls NULL | 445 | * @param cls NULL |
@@ -1139,184 +701,6 @@ handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client, | |||
1139 | 701 | ||
1140 | 702 | ||
1141 | /** | 703 | /** |
1142 | * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message | ||
1143 | * | ||
1144 | * @param cls NULL | ||
1145 | * @param client identification of the client | ||
1146 | * @param message the actual message | ||
1147 | */ | ||
1148 | static void | ||
1149 | handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client, | ||
1150 | const struct GNUNET_MessageHeader *message) | ||
1151 | { | ||
1152 | const struct GNUNET_TESTBED_ControllerLinkRequest *msg; | ||
1153 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
1154 | struct LCFContextQueue *lcfq; | ||
1155 | struct Route *route; | ||
1156 | struct Route *new_route; | ||
1157 | uint32_t delegated_host_id; | ||
1158 | uint32_t slave_host_id; | ||
1159 | uint16_t msize; | ||
1160 | |||
1161 | if (NULL == GST_context) | ||
1162 | { | ||
1163 | GNUNET_break (0); | ||
1164 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1165 | return; | ||
1166 | } | ||
1167 | msize = ntohs (message->size); | ||
1168 | if (sizeof (struct GNUNET_TESTBED_ControllerLinkRequest) >= msize) | ||
1169 | { | ||
1170 | GNUNET_break (0); | ||
1171 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1172 | return; | ||
1173 | } | ||
1174 | msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message; | ||
1175 | delegated_host_id = ntohl (msg->delegated_host_id); | ||
1176 | if (delegated_host_id == GST_context->host_id) | ||
1177 | { | ||
1178 | GNUNET_break (0); | ||
1179 | LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n"); | ||
1180 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1181 | return; | ||
1182 | } | ||
1183 | if ((delegated_host_id >= GST_host_list_size) || | ||
1184 | (NULL == GST_host_list[delegated_host_id])) | ||
1185 | { | ||
1186 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1187 | "Delegated host %u not registered with us\n", delegated_host_id); | ||
1188 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1189 | return; | ||
1190 | } | ||
1191 | slave_host_id = ntohl (msg->slave_host_id); | ||
1192 | if ((slave_host_id >= GST_host_list_size) || | ||
1193 | (NULL == GST_host_list[slave_host_id])) | ||
1194 | { | ||
1195 | LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n", | ||
1196 | slave_host_id); | ||
1197 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1198 | return; | ||
1199 | } | ||
1200 | if (slave_host_id == delegated_host_id) | ||
1201 | { | ||
1202 | LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n"); | ||
1203 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1204 | return; | ||
1205 | } | ||
1206 | cfg = GNUNET_TESTBED_extract_config_ (message); /* destroy cfg here or in lcfcontext */ | ||
1207 | if (NULL == cfg) | ||
1208 | { | ||
1209 | GNUNET_break (0); /* Configuration parsing error */ | ||
1210 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1211 | return; | ||
1212 | } | ||
1213 | if (slave_host_id == GST_context->host_id) /* Link from us */ | ||
1214 | { | ||
1215 | struct Slave *slave; | ||
1216 | struct LinkControllersContext *lcc; | ||
1217 | |||
1218 | if ((delegated_host_id < GST_slave_list_size) && | ||
1219 | (NULL != GST_slave_list[delegated_host_id])) | ||
1220 | { | ||
1221 | GNUNET_break (0); | ||
1222 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1223 | return; | ||
1224 | } | ||
1225 | slave = GNUNET_malloc (sizeof (struct Slave)); | ||
1226 | slave->host_id = delegated_host_id; | ||
1227 | slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO); | ||
1228 | slave_list_add (slave); | ||
1229 | if (1 != msg->is_subordinate) | ||
1230 | { | ||
1231 | slave->controller = | ||
1232 | GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id], | ||
1233 | event_mask, &slave_event_callback, | ||
1234 | slave); | ||
1235 | if (NULL != slave->controller) | ||
1236 | send_controller_link_response (client, | ||
1237 | GNUNET_ntohll (msg->operation_id), | ||
1238 | NULL, | ||
1239 | NULL); | ||
1240 | else | ||
1241 | send_controller_link_response (client, | ||
1242 | GNUNET_ntohll (msg->operation_id), | ||
1243 | NULL, | ||
1244 | "Could not connect to delegated controller"); | ||
1245 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1246 | return; | ||
1247 | } | ||
1248 | lcc = GNUNET_malloc (sizeof (struct LinkControllersContext)); | ||
1249 | lcc->operation_id = GNUNET_ntohll (msg->operation_id); | ||
1250 | GNUNET_SERVER_client_keep (client); | ||
1251 | lcc->client = client; | ||
1252 | slave->lcc = lcc; | ||
1253 | slave->controller_proc = | ||
1254 | GNUNET_TESTBED_controller_start (GST_context->master_ip, | ||
1255 | GST_host_list[slave->host_id], cfg, | ||
1256 | &slave_status_callback, slave); | ||
1257 | GNUNET_CONFIGURATION_destroy (cfg); | ||
1258 | new_route = GNUNET_malloc (sizeof (struct Route)); | ||
1259 | new_route->dest = delegated_host_id; | ||
1260 | new_route->thru = GST_context->host_id; | ||
1261 | route_list_add (new_route); | ||
1262 | return; | ||
1263 | } | ||
1264 | |||
1265 | /* Route the request */ | ||
1266 | if (slave_host_id >= route_list_size) | ||
1267 | { | ||
1268 | LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host"); | ||
1269 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1270 | return; | ||
1271 | } | ||
1272 | lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue)); | ||
1273 | lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext)); | ||
1274 | lcfq->lcf->type = CLOSURE_TYPE_LCF; | ||
1275 | lcfq->lcf->delegated_host_id = delegated_host_id; | ||
1276 | lcfq->lcf->slave_host_id = slave_host_id; | ||
1277 | route = GST_find_dest_route (slave_host_id); | ||
1278 | GNUNET_assert (NULL != route); /* because we add routes carefully */ | ||
1279 | GNUNET_assert (route->dest < GST_slave_list_size); | ||
1280 | GNUNET_assert (NULL != GST_slave_list[route->dest]); | ||
1281 | lcfq->lcf->cfg = cfg; | ||
1282 | lcfq->lcf->is_subordinate = msg->is_subordinate; | ||
1283 | lcfq->lcf->state = INIT; | ||
1284 | lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id); | ||
1285 | lcfq->lcf->gateway = GST_slave_list[route->dest]; | ||
1286 | GNUNET_SERVER_client_keep (client); | ||
1287 | lcfq->lcf->client = client; | ||
1288 | if (NULL == lcfq_head) | ||
1289 | { | ||
1290 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); | ||
1291 | GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq); | ||
1292 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf); | ||
1293 | } | ||
1294 | else | ||
1295 | GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq); | ||
1296 | /* FIXME: Adding a new route should happen after the controllers are linked | ||
1297 | * successfully */ | ||
1298 | if (1 != msg->is_subordinate) | ||
1299 | { | ||
1300 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1301 | return; | ||
1302 | } | ||
1303 | if ((delegated_host_id < route_list_size) && | ||
1304 | (NULL != route_list[delegated_host_id])) | ||
1305 | { | ||
1306 | GNUNET_break_op (0); /* Are you trying to link delegated host twice | ||
1307 | * with is subordinate flag set to GNUNET_YES? */ | ||
1308 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
1309 | return; | ||
1310 | } | ||
1311 | new_route = GNUNET_malloc (sizeof (struct Route)); | ||
1312 | new_route->dest = delegated_host_id; | ||
1313 | new_route->thru = route->dest; | ||
1314 | route_list_add (new_route); | ||
1315 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1316 | } | ||
1317 | |||
1318 | |||
1319 | /** | ||
1320 | * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages | 704 | * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages |
1321 | * | 705 | * |
1322 | * @param cls NULL | 706 | * @param cls NULL |
@@ -1441,41 +825,6 @@ ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value) | |||
1441 | 825 | ||
1442 | 826 | ||
1443 | /** | 827 | /** |
1444 | * Iterator for freeing hash map entries in a slave's reghost_map | ||
1445 | * | ||
1446 | * @param cls handle to the slave | ||
1447 | * @param key current key code | ||
1448 | * @param value value in the hash map | ||
1449 | * @return GNUNET_YES if we should continue to | ||
1450 | * iterate, | ||
1451 | * GNUNET_NO if not. | ||
1452 | */ | ||
1453 | static int | ||
1454 | reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key, | ||
1455 | void *value) | ||
1456 | { | ||
1457 | struct Slave *slave = cls; | ||
1458 | struct RegisteredHostContext *rhc = value; | ||
1459 | struct ForwardedOverlayConnectContext *focc; | ||
1460 | |||
1461 | GNUNET_assert (GNUNET_YES == | ||
1462 | GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key, | ||
1463 | value)); | ||
1464 | while (NULL != (focc = rhc->focc_dll_head)) | ||
1465 | { | ||
1466 | GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc); | ||
1467 | GST_cleanup_focc (focc); | ||
1468 | } | ||
1469 | if (NULL != rhc->sub_op) | ||
1470 | GNUNET_TESTBED_operation_done (rhc->sub_op); | ||
1471 | if (NULL != rhc->client) | ||
1472 | GNUNET_SERVER_client_drop (rhc->client); | ||
1473 | GNUNET_free (value); | ||
1474 | return GNUNET_YES; | ||
1475 | } | ||
1476 | |||
1477 | |||
1478 | /** | ||
1479 | * Task to clean up and shutdown nicely | 828 | * Task to clean up and shutdown nicely |
1480 | * | 829 | * |
1481 | * @param cls NULL | 830 | * @param cls NULL |
@@ -1484,7 +833,6 @@ reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key, | |||
1484 | static void | 833 | static void |
1485 | shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 834 | shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
1486 | { | 835 | { |
1487 | struct LCFContextQueue *lcfq; | ||
1488 | struct MessageQueue *mq_entry; | 836 | struct MessageQueue *mq_entry; |
1489 | uint32_t id; | 837 | uint32_t id; |
1490 | 838 | ||
@@ -1495,24 +843,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
1495 | GNUNET_CONTAINER_multihashmap_destroy (ss_map); | 843 | GNUNET_CONTAINER_multihashmap_destroy (ss_map); |
1496 | /* cleanup any remaining forwarded operations */ | 844 | /* cleanup any remaining forwarded operations */ |
1497 | GST_clear_fopcq (); | 845 | GST_clear_fopcq (); |
1498 | if (NULL != lcfq_head) | 846 | GST_free_lcfq (); |
1499 | { | ||
1500 | if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id) | ||
1501 | { | ||
1502 | GNUNET_SCHEDULER_cancel (lcf_proc_task_id); | ||
1503 | lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK; | ||
1504 | } | ||
1505 | } | ||
1506 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); | ||
1507 | for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head) | ||
1508 | { | ||
1509 | GNUNET_SERVER_client_drop (lcfq->lcf->client); | ||
1510 | GNUNET_assert (NULL != lcfq->lcf->cfg); | ||
1511 | GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg); | ||
1512 | GNUNET_free (lcfq->lcf); | ||
1513 | GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq); | ||
1514 | GNUNET_free (lcfq); | ||
1515 | } | ||
1516 | GST_free_mctxq (); | 847 | GST_free_mctxq (); |
1517 | GST_free_occq (); | 848 | GST_free_occq (); |
1518 | GST_free_roccq (); | 849 | GST_free_roccq (); |
@@ -1524,37 +855,9 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
1524 | GNUNET_TESTBED_host_destroy (GST_host_list[id]); | 855 | GNUNET_TESTBED_host_destroy (GST_host_list[id]); |
1525 | GNUNET_free_non_null (GST_host_list); | 856 | GNUNET_free_non_null (GST_host_list); |
1526 | /* Clear route list */ | 857 | /* Clear route list */ |
1527 | for (id = 0; id < route_list_size; id++) | 858 | GST_route_list_clear (); |
1528 | if (NULL != route_list[id]) | ||
1529 | GNUNET_free (route_list[id]); | ||
1530 | GNUNET_free_non_null (route_list); | ||
1531 | /* Clear GST_slave_list */ | 859 | /* Clear GST_slave_list */ |
1532 | for (id = 0; id < GST_slave_list_size; id++) | 860 | GST_slave_list_clear (); |
1533 | if (NULL != GST_slave_list[id]) | ||
1534 | { | ||
1535 | struct HostRegistration *hr_entry; | ||
1536 | |||
1537 | while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head)) | ||
1538 | { | ||
1539 | GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head, | ||
1540 | GST_slave_list[id]->hr_dll_tail, hr_entry); | ||
1541 | GNUNET_free (hr_entry); | ||
1542 | } | ||
1543 | if (NULL != GST_slave_list[id]->rhandle) | ||
1544 | GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle); | ||
1545 | (void) | ||
1546 | GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list | ||
1547 | [id]->reghost_map, | ||
1548 | reghost_free_iterator, | ||
1549 | GST_slave_list[id]); | ||
1550 | GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map); | ||
1551 | if (NULL != GST_slave_list[id]->controller) | ||
1552 | GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller); | ||
1553 | if (NULL != GST_slave_list[id]->controller_proc) | ||
1554 | GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc); | ||
1555 | GNUNET_free (GST_slave_list[id]); | ||
1556 | } | ||
1557 | GNUNET_free_non_null (GST_slave_list); | ||
1558 | if (NULL != GST_context) | 861 | if (NULL != GST_context) |
1559 | { | 862 | { |
1560 | GNUNET_free_non_null (GST_context->master_ip); | 863 | GNUNET_free_non_null (GST_context->master_ip); |
@@ -1623,7 +926,7 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server, | |||
1623 | {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST, 0}, | 926 | {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST, 0}, |
1624 | {&handle_configure_shared_service, NULL, | 927 | {&handle_configure_shared_service, NULL, |
1625 | GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE, 0}, | 928 | GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE, 0}, |
1626 | {&handle_link_controllers, NULL, | 929 | {&GST_handle_link_controllers, NULL, |
1627 | GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS, 0}, | 930 | GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS, 0}, |
1628 | {&GST_handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER, 0}, | 931 | {&GST_handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER, 0}, |
1629 | {&GST_handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER, | 932 | {&GST_handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER, |
@@ -1685,7 +988,6 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server, | |||
1685 | GNUNET_SCHEDULER_PRIORITY_IDLE, | 988 | GNUNET_SCHEDULER_PRIORITY_IDLE, |
1686 | &shutdown_task, NULL); | 989 | &shutdown_task, NULL); |
1687 | LOG_DEBUG ("Testbed startup complete\n"); | 990 | LOG_DEBUG ("Testbed startup complete\n"); |
1688 | event_mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED; | ||
1689 | GST_stats_init (our_config); | 991 | GST_stats_init (our_config); |
1690 | } | 992 | } |
1691 | 993 | ||
diff --git a/src/testbed/gnunet-service-testbed.h b/src/testbed/gnunet-service-testbed.h index 4a33b92ef..2a410a850 100644 --- a/src/testbed/gnunet-service-testbed.h +++ b/src/testbed/gnunet-service-testbed.h | |||
@@ -748,6 +748,18 @@ GST_find_dest_route (uint32_t host_id); | |||
748 | 748 | ||
749 | 749 | ||
750 | /** | 750 | /** |
751 | * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message | ||
752 | * | ||
753 | * @param cls NULL | ||
754 | * @param client identification of the client | ||
755 | * @param message the actual message | ||
756 | */ | ||
757 | void | ||
758 | GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client, | ||
759 | const struct GNUNET_MessageHeader *message); | ||
760 | |||
761 | |||
762 | /** | ||
751 | * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT messages | 763 | * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT messages |
752 | * | 764 | * |
753 | * @param cls NULL | 765 | * @param cls NULL |
@@ -931,6 +943,27 @@ GST_free_mctxq (); | |||
931 | 943 | ||
932 | 944 | ||
933 | /** | 945 | /** |
946 | * Cleans up the queue used for forwarding link controllers requests | ||
947 | */ | ||
948 | void | ||
949 | GST_free_lcfq (); | ||
950 | |||
951 | |||
952 | /** | ||
953 | * Cleans up the route list | ||
954 | */ | ||
955 | void | ||
956 | GST_route_list_clear (); | ||
957 | |||
958 | |||
959 | /** | ||
960 | * Cleans up the slave list | ||
961 | */ | ||
962 | void | ||
963 | GST_slave_list_clear (); | ||
964 | |||
965 | |||
966 | /** | ||
934 | * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext | 967 | * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext |
935 | * | 968 | * |
936 | * @param rhc the RegisteredHostContext | 969 | * @param rhc the RegisteredHostContext |
diff --git a/src/testbed/gnunet-service-testbed_links.c b/src/testbed/gnunet-service-testbed_links.c new file mode 100644 index 000000000..6f71d8a61 --- /dev/null +++ b/src/testbed/gnunet-service-testbed_links.c | |||
@@ -0,0 +1,760 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2008--2013 Christian Grothoff (and other contributing authors) | ||
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 2, 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., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file testbed/gnunet-service-testbed.c | ||
23 | * @brief implementation of the TESTBED service | ||
24 | * @author Sree Harsha Totakura | ||
25 | */ | ||
26 | |||
27 | #include "gnunet-service-testbed.h" | ||
28 | |||
29 | /** | ||
30 | * The event mask for the events we listen from sub-controllers | ||
31 | */ | ||
32 | #define EVENT_MASK (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED) | ||
33 | |||
34 | /** | ||
35 | * A list of directly linked neighbours | ||
36 | */ | ||
37 | struct Slave **GST_slave_list; | ||
38 | |||
39 | /** | ||
40 | * The size of directly linked neighbours list | ||
41 | */ | ||
42 | unsigned int GST_slave_list_size; | ||
43 | |||
44 | /** | ||
45 | * A list of routes | ||
46 | */ | ||
47 | static struct Route **route_list; | ||
48 | |||
49 | /** | ||
50 | * The head for the LCF queue | ||
51 | */ | ||
52 | static struct LCFContextQueue *lcfq_head; | ||
53 | |||
54 | /** | ||
55 | * The tail for the LCF queue | ||
56 | */ | ||
57 | static struct LCFContextQueue *lcfq_tail; | ||
58 | |||
59 | /** | ||
60 | * The lcf_task handle | ||
61 | */ | ||
62 | static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id; | ||
63 | |||
64 | /** | ||
65 | * The size of the route list | ||
66 | */ | ||
67 | static unsigned int route_list_size; | ||
68 | |||
69 | |||
70 | /** | ||
71 | * Adds a slave to the slave array | ||
72 | * | ||
73 | * @param slave the slave controller to add | ||
74 | */ | ||
75 | static void | ||
76 | slave_list_add (struct Slave *slave) | ||
77 | { | ||
78 | if (slave->host_id >= GST_slave_list_size) | ||
79 | GST_array_grow_large_enough (GST_slave_list, GST_slave_list_size, | ||
80 | slave->host_id); | ||
81 | GNUNET_assert (NULL == GST_slave_list[slave->host_id]); | ||
82 | GST_slave_list[slave->host_id] = slave; | ||
83 | } | ||
84 | |||
85 | |||
86 | /** | ||
87 | * Adds a route to the route list | ||
88 | * | ||
89 | * @param route the route to add | ||
90 | */ | ||
91 | static void | ||
92 | route_list_add (struct Route *route) | ||
93 | { | ||
94 | if (route->dest >= route_list_size) | ||
95 | GST_array_grow_large_enough (route_list, route_list_size, route->dest); | ||
96 | GNUNET_assert (NULL == route_list[route->dest]); | ||
97 | route_list[route->dest] = route; | ||
98 | } | ||
99 | |||
100 | |||
101 | /** | ||
102 | * Cleans up the route list | ||
103 | */ | ||
104 | void | ||
105 | GST_route_list_clear () | ||
106 | { | ||
107 | unsigned int id; | ||
108 | |||
109 | for (id = 0; id < route_list_size; id++) | ||
110 | if (NULL != route_list[id]) | ||
111 | GNUNET_free (route_list[id]); | ||
112 | GNUNET_free_non_null (route_list); | ||
113 | route_list = NULL; | ||
114 | } | ||
115 | |||
116 | |||
117 | /** | ||
118 | * Iterator for freeing hash map entries in a slave's reghost_map | ||
119 | * | ||
120 | * @param cls handle to the slave | ||
121 | * @param key current key code | ||
122 | * @param value value in the hash map | ||
123 | * @return GNUNET_YES if we should continue to | ||
124 | * iterate, | ||
125 | * GNUNET_NO if not. | ||
126 | */ | ||
127 | static int | ||
128 | reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key, | ||
129 | void *value) | ||
130 | { | ||
131 | struct Slave *slave = cls; | ||
132 | struct RegisteredHostContext *rhc = value; | ||
133 | struct ForwardedOverlayConnectContext *focc; | ||
134 | |||
135 | GNUNET_assert (GNUNET_YES == | ||
136 | GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key, | ||
137 | value)); | ||
138 | while (NULL != (focc = rhc->focc_dll_head)) | ||
139 | { | ||
140 | GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc); | ||
141 | GST_cleanup_focc (focc); | ||
142 | } | ||
143 | if (NULL != rhc->sub_op) | ||
144 | GNUNET_TESTBED_operation_done (rhc->sub_op); | ||
145 | if (NULL != rhc->client) | ||
146 | GNUNET_SERVER_client_drop (rhc->client); | ||
147 | GNUNET_free (value); | ||
148 | return GNUNET_YES; | ||
149 | } | ||
150 | |||
151 | |||
152 | /** | ||
153 | * Cleans up the slave list | ||
154 | */ | ||
155 | void | ||
156 | GST_slave_list_clear () | ||
157 | { | ||
158 | unsigned int id; | ||
159 | struct HostRegistration *hr_entry; | ||
160 | |||
161 | for (id = 0; id < GST_slave_list_size; id++) | ||
162 | if (NULL != GST_slave_list[id]) | ||
163 | { | ||
164 | while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head)) | ||
165 | { | ||
166 | GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head, | ||
167 | GST_slave_list[id]->hr_dll_tail, hr_entry); | ||
168 | GNUNET_free (hr_entry); | ||
169 | } | ||
170 | if (NULL != GST_slave_list[id]->rhandle) | ||
171 | GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle); | ||
172 | (void) | ||
173 | GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list | ||
174 | [id]->reghost_map, | ||
175 | reghost_free_iterator, | ||
176 | GST_slave_list[id]); | ||
177 | GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map); | ||
178 | if (NULL != GST_slave_list[id]->controller) | ||
179 | GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller); | ||
180 | if (NULL != GST_slave_list[id]->controller_proc) | ||
181 | GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc); | ||
182 | GNUNET_free (GST_slave_list[id]); | ||
183 | } | ||
184 | GNUNET_free_non_null (GST_slave_list); | ||
185 | GST_slave_list = NULL; | ||
186 | } | ||
187 | |||
188 | |||
189 | /** | ||
190 | * Finds the route with directly connected host as destination through which | ||
191 | * the destination host can be reached | ||
192 | * | ||
193 | * @param host_id the id of the destination host | ||
194 | * @return the route with directly connected destination host; NULL if no route | ||
195 | * is found | ||
196 | */ | ||
197 | struct Route * | ||
198 | GST_find_dest_route (uint32_t host_id) | ||
199 | { | ||
200 | struct Route *route; | ||
201 | |||
202 | if (route_list_size <= host_id) | ||
203 | return NULL; | ||
204 | while (NULL != (route = route_list[host_id])) | ||
205 | { | ||
206 | if (route->thru == GST_context->host_id) | ||
207 | break; | ||
208 | host_id = route->thru; | ||
209 | } | ||
210 | return route; | ||
211 | } | ||
212 | |||
213 | |||
214 | /** | ||
215 | * Function to send a failure reponse for controller link operation | ||
216 | * | ||
217 | * @param client the client to send the message to | ||
218 | * @param operation_id the operation ID of the controller link request | ||
219 | * @param cfg the configuration with which the delegated controller is started. | ||
220 | * Can be NULL if the delegated controller is not started but just | ||
221 | * linked to. | ||
222 | * @param emsg set to an error message explaining why the controller link | ||
223 | * failed. Setting this to NULL signifies success. !This should be | ||
224 | * NULL if cfg is set! | ||
225 | */ | ||
226 | static void | ||
227 | send_controller_link_response (struct GNUNET_SERVER_Client *client, | ||
228 | uint64_t operation_id, | ||
229 | const struct GNUNET_CONFIGURATION_Handle | ||
230 | *cfg, | ||
231 | const char *emsg) | ||
232 | { | ||
233 | struct GNUNET_TESTBED_ControllerLinkResponse *msg; | ||
234 | char *xconfig; | ||
235 | size_t config_size; | ||
236 | size_t xconfig_size; | ||
237 | uint16_t msize; | ||
238 | |||
239 | GNUNET_assert ((NULL == cfg) || (NULL == emsg)); | ||
240 | xconfig = NULL; | ||
241 | xconfig_size = 0; | ||
242 | config_size = 0; | ||
243 | msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse); | ||
244 | if (NULL != cfg) | ||
245 | { | ||
246 | xconfig = GNUNET_TESTBED_compress_cfg_ (cfg, | ||
247 | &config_size, | ||
248 | &xconfig_size); | ||
249 | msize += xconfig_size; | ||
250 | } | ||
251 | if (NULL != emsg) | ||
252 | msize += strlen (emsg); | ||
253 | msg = GNUNET_malloc (msize); | ||
254 | msg->header.type = htons | ||
255 | (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT); | ||
256 | msg->header.size = htons (msize); | ||
257 | if (NULL == emsg) | ||
258 | msg->success = htons (GNUNET_YES); | ||
259 | msg->operation_id = GNUNET_htonll (operation_id); | ||
260 | msg->config_size = htons ((uint16_t) config_size); | ||
261 | if (NULL != xconfig) | ||
262 | memcpy (&msg[1], xconfig, xconfig_size); | ||
263 | if (NULL != emsg) | ||
264 | memcpy (&msg[1], emsg, strlen (emsg)); | ||
265 | GST_queue_message (client, &msg->header); | ||
266 | } | ||
267 | |||
268 | |||
269 | /** | ||
270 | * The Link Controller forwarding task | ||
271 | * | ||
272 | * @param cls the LCFContext | ||
273 | * @param tc the Task context from scheduler | ||
274 | */ | ||
275 | static void | ||
276 | lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
277 | |||
278 | |||
279 | /** | ||
280 | * Completion callback for host registrations while forwarding Link Controller messages | ||
281 | * | ||
282 | * @param cls the LCFContext | ||
283 | * @param emsg the error message; NULL if host registration is successful | ||
284 | */ | ||
285 | static void | ||
286 | lcf_proc_cc (void *cls, const char *emsg) | ||
287 | { | ||
288 | struct LCFContext *lcf = cls; | ||
289 | |||
290 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); | ||
291 | switch (lcf->state) | ||
292 | { | ||
293 | case INIT: | ||
294 | if (NULL != emsg) | ||
295 | goto registration_error; | ||
296 | lcf->state = DELEGATED_HOST_REGISTERED; | ||
297 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
298 | break; | ||
299 | case DELEGATED_HOST_REGISTERED: | ||
300 | if (NULL != emsg) | ||
301 | goto registration_error; | ||
302 | lcf->state = SLAVE_HOST_REGISTERED; | ||
303 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
304 | break; | ||
305 | default: | ||
306 | GNUNET_assert (0); /* Shouldn't reach here */ | ||
307 | } | ||
308 | return; | ||
309 | |||
310 | registration_error: | ||
311 | LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n", | ||
312 | emsg); | ||
313 | lcf->state = FINISHED; | ||
314 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
315 | } | ||
316 | |||
317 | |||
318 | /** | ||
319 | * The Link Controller forwarding task | ||
320 | * | ||
321 | * @param cls the LCFContext | ||
322 | * @param tc the Task context from scheduler | ||
323 | */ | ||
324 | static void | ||
325 | lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
326 | |||
327 | |||
328 | /** | ||
329 | * Task to free resources when forwarded link controllers has been timedout | ||
330 | * | ||
331 | * @param cls the LCFContext | ||
332 | * @param tc the task context from scheduler | ||
333 | */ | ||
334 | static void | ||
335 | lcf_forwarded_operation_timeout (void *cls, | ||
336 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
337 | { | ||
338 | struct LCFContext *lcf = cls; | ||
339 | |||
340 | lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
341 | // GST_forwarded_operation_timeout (lcf->fopc, tc); | ||
342 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
343 | "A forwarded controller link operation has timed out\n"); | ||
344 | send_controller_link_response (lcf->client, lcf->operation_id, NULL, | ||
345 | "A forwarded controller link operation has " | ||
346 | "timed out\n"); | ||
347 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); | ||
348 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
349 | } | ||
350 | |||
351 | |||
352 | /** | ||
353 | * The Link Controller forwarding task | ||
354 | * | ||
355 | * @param cls the LCFContext | ||
356 | * @param tc the Task context from scheduler | ||
357 | */ | ||
358 | static void | ||
359 | lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
360 | { | ||
361 | struct LCFContext *lcf = cls; | ||
362 | struct LCFContextQueue *lcfq; | ||
363 | |||
364 | lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK; | ||
365 | switch (lcf->state) | ||
366 | { | ||
367 | case INIT: | ||
368 | if (GNUNET_NO == | ||
369 | GNUNET_TESTBED_is_host_registered_ (GST_host_list | ||
370 | [lcf->delegated_host_id], | ||
371 | lcf->gateway->controller)) | ||
372 | { | ||
373 | GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf, | ||
374 | GST_host_list[lcf->delegated_host_id]); | ||
375 | } | ||
376 | else | ||
377 | { | ||
378 | lcf->state = DELEGATED_HOST_REGISTERED; | ||
379 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
380 | } | ||
381 | break; | ||
382 | case DELEGATED_HOST_REGISTERED: | ||
383 | if (GNUNET_NO == | ||
384 | GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id], | ||
385 | lcf->gateway->controller)) | ||
386 | { | ||
387 | GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf, | ||
388 | GST_host_list[lcf->slave_host_id]); | ||
389 | } | ||
390 | else | ||
391 | { | ||
392 | lcf->state = SLAVE_HOST_REGISTERED; | ||
393 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
394 | } | ||
395 | break; | ||
396 | case SLAVE_HOST_REGISTERED: | ||
397 | lcf->op = GNUNET_TESTBED_controller_link (lcf, | ||
398 | lcf->gateway->controller, | ||
399 | GST_host_list[lcf->delegated_host_id], | ||
400 | GST_host_list[lcf->slave_host_id], | ||
401 | NULL, | ||
402 | lcf->is_subordinate); | ||
403 | lcf->timeout_task = | ||
404 | GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout, | ||
405 | lcf); | ||
406 | lcf->state = FINISHED; | ||
407 | break; | ||
408 | case FINISHED: | ||
409 | lcfq = lcfq_head; | ||
410 | GNUNET_assert (lcfq->lcf == lcf); | ||
411 | GNUNET_assert (NULL != lcf->cfg); | ||
412 | GNUNET_CONFIGURATION_destroy (lcf->cfg); | ||
413 | GNUNET_SERVER_client_drop (lcf->client); | ||
414 | GNUNET_TESTBED_operation_done (lcf->op); | ||
415 | GNUNET_free (lcf); | ||
416 | GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq); | ||
417 | GNUNET_free (lcfq); | ||
418 | if (NULL != lcfq_head) | ||
419 | lcf_proc_task_id = | ||
420 | GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf); | ||
421 | } | ||
422 | } | ||
423 | |||
424 | |||
425 | /** | ||
426 | * Callback for event from slave controllers | ||
427 | * | ||
428 | * @param cls struct Slave * | ||
429 | * @param event information about the event | ||
430 | */ | ||
431 | static void | ||
432 | slave_event_callback (void *cls, | ||
433 | const struct GNUNET_TESTBED_EventInformation *event) | ||
434 | { | ||
435 | struct RegisteredHostContext *rhc; | ||
436 | struct LCFContext *lcf; | ||
437 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
438 | struct GNUNET_TESTBED_Operation *old_op; | ||
439 | |||
440 | /* We currently only get here when working on RegisteredHostContexts and | ||
441 | LCFContexts */ | ||
442 | GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type); | ||
443 | rhc = event->op_cls; | ||
444 | if (CLOSURE_TYPE_RHC == rhc->type) | ||
445 | { | ||
446 | GNUNET_assert (rhc->sub_op == event->op); | ||
447 | switch (rhc->state) | ||
448 | { | ||
449 | case RHC_GET_CFG: | ||
450 | cfg = event->details.operation_finished.generic; | ||
451 | old_op = rhc->sub_op; | ||
452 | rhc->state = RHC_LINK; | ||
453 | rhc->sub_op = | ||
454 | GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller, | ||
455 | rhc->reg_host, rhc->host, cfg, | ||
456 | GNUNET_NO); | ||
457 | GNUNET_TESTBED_operation_done (old_op); | ||
458 | break; | ||
459 | case RHC_LINK: | ||
460 | LOG_DEBUG ("OL: Linking controllers successfull\n"); | ||
461 | GNUNET_TESTBED_operation_done (rhc->sub_op); | ||
462 | rhc->sub_op = NULL; | ||
463 | rhc->state = RHC_OL_CONNECT; | ||
464 | GST_process_next_focc (rhc); | ||
465 | break; | ||
466 | default: | ||
467 | GNUNET_assert (0); | ||
468 | } | ||
469 | return; | ||
470 | } | ||
471 | lcf = event->op_cls; | ||
472 | if (CLOSURE_TYPE_LCF == lcf->type) | ||
473 | { | ||
474 | GNUNET_assert (lcf->op == event->op); | ||
475 | GNUNET_assert (FINISHED == lcf->state); | ||
476 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task); | ||
477 | GNUNET_SCHEDULER_cancel (lcf->timeout_task); | ||
478 | if (NULL == event->details.operation_finished.emsg) | ||
479 | send_controller_link_response (lcf->client, lcf->operation_id, | ||
480 | GNUNET_TESTBED_host_get_cfg_ | ||
481 | (GST_host_list[lcf->delegated_host_id]), | ||
482 | NULL); | ||
483 | else | ||
484 | send_controller_link_response (lcf->client, lcf->operation_id, | ||
485 | NULL, | ||
486 | event->details.operation_finished.emsg); | ||
487 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); | ||
488 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf); | ||
489 | return; | ||
490 | } | ||
491 | GNUNET_assert (0); | ||
492 | } | ||
493 | |||
494 | |||
495 | /** | ||
496 | * Callback to signal successfull startup of the controller process | ||
497 | * | ||
498 | * @param cls the handle to the slave whose status is to be found here | ||
499 | * @param cfg the configuration with which the controller has been started; | ||
500 | * NULL if status is not GNUNET_OK | ||
501 | * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not, | ||
502 | * GNUNET_TESTBED_controller_stop() shouldn't be called in this case | ||
503 | */ | ||
504 | static void | ||
505 | slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
506 | int status) | ||
507 | { | ||
508 | struct Slave *slave = cls; | ||
509 | struct LinkControllersContext *lcc; | ||
510 | |||
511 | lcc = slave->lcc; | ||
512 | if (GNUNET_SYSERR == status) | ||
513 | { | ||
514 | slave->controller_proc = NULL; | ||
515 | GST_slave_list[slave->host_id] = NULL; | ||
516 | GNUNET_free (slave); | ||
517 | slave = NULL; | ||
518 | LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n"); | ||
519 | GNUNET_SCHEDULER_shutdown (); /* We too shutdown */ | ||
520 | goto clean_lcc; | ||
521 | } | ||
522 | slave->controller = | ||
523 | GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id], | ||
524 | EVENT_MASK, &slave_event_callback, | ||
525 | slave); | ||
526 | if (NULL != slave->controller) | ||
527 | { | ||
528 | send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL); | ||
529 | } | ||
530 | else | ||
531 | { | ||
532 | send_controller_link_response (lcc->client, lcc->operation_id, NULL, | ||
533 | "Could not connect to delegated controller"); | ||
534 | GNUNET_TESTBED_controller_stop (slave->controller_proc); | ||
535 | GST_slave_list[slave->host_id] = NULL; | ||
536 | GNUNET_free (slave); | ||
537 | slave = NULL; | ||
538 | } | ||
539 | |||
540 | clean_lcc: | ||
541 | if (NULL != lcc) | ||
542 | { | ||
543 | if (NULL != lcc->client) | ||
544 | { | ||
545 | GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK); | ||
546 | GNUNET_SERVER_client_drop (lcc->client); | ||
547 | lcc->client = NULL; | ||
548 | } | ||
549 | GNUNET_free (lcc); | ||
550 | } | ||
551 | if (NULL != slave) | ||
552 | slave->lcc = NULL; | ||
553 | } | ||
554 | |||
555 | |||
556 | /** | ||
557 | * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message | ||
558 | * | ||
559 | * @param cls NULL | ||
560 | * @param client identification of the client | ||
561 | * @param message the actual message | ||
562 | */ | ||
563 | void | ||
564 | GST_handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client, | ||
565 | const struct GNUNET_MessageHeader *message) | ||
566 | { | ||
567 | const struct GNUNET_TESTBED_ControllerLinkRequest *msg; | ||
568 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
569 | struct LCFContextQueue *lcfq; | ||
570 | struct Route *route; | ||
571 | struct Route *new_route; | ||
572 | uint32_t delegated_host_id; | ||
573 | uint32_t slave_host_id; | ||
574 | uint16_t msize; | ||
575 | |||
576 | if (NULL == GST_context) | ||
577 | { | ||
578 | GNUNET_break (0); | ||
579 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
580 | return; | ||
581 | } | ||
582 | msize = ntohs (message->size); | ||
583 | if (sizeof (struct GNUNET_TESTBED_ControllerLinkRequest) >= msize) | ||
584 | { | ||
585 | GNUNET_break (0); | ||
586 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
587 | return; | ||
588 | } | ||
589 | msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message; | ||
590 | delegated_host_id = ntohl (msg->delegated_host_id); | ||
591 | if (delegated_host_id == GST_context->host_id) | ||
592 | { | ||
593 | GNUNET_break (0); | ||
594 | LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n"); | ||
595 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
596 | return; | ||
597 | } | ||
598 | if ((delegated_host_id >= GST_host_list_size) || | ||
599 | (NULL == GST_host_list[delegated_host_id])) | ||
600 | { | ||
601 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
602 | "Delegated host %u not registered with us\n", delegated_host_id); | ||
603 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
604 | return; | ||
605 | } | ||
606 | slave_host_id = ntohl (msg->slave_host_id); | ||
607 | if ((slave_host_id >= GST_host_list_size) || | ||
608 | (NULL == GST_host_list[slave_host_id])) | ||
609 | { | ||
610 | LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n", | ||
611 | slave_host_id); | ||
612 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
613 | return; | ||
614 | } | ||
615 | if (slave_host_id == delegated_host_id) | ||
616 | { | ||
617 | LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n"); | ||
618 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
619 | return; | ||
620 | } | ||
621 | cfg = GNUNET_TESTBED_extract_config_ (message); /* destroy cfg here or in lcfcontext */ | ||
622 | if (NULL == cfg) | ||
623 | { | ||
624 | GNUNET_break (0); /* Configuration parsing error */ | ||
625 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
626 | return; | ||
627 | } | ||
628 | if (slave_host_id == GST_context->host_id) /* Link from us */ | ||
629 | { | ||
630 | struct Slave *slave; | ||
631 | struct LinkControllersContext *lcc; | ||
632 | |||
633 | if ((delegated_host_id < GST_slave_list_size) && | ||
634 | (NULL != GST_slave_list[delegated_host_id])) | ||
635 | { | ||
636 | GNUNET_break (0); | ||
637 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
638 | return; | ||
639 | } | ||
640 | slave = GNUNET_malloc (sizeof (struct Slave)); | ||
641 | slave->host_id = delegated_host_id; | ||
642 | slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO); | ||
643 | slave_list_add (slave); | ||
644 | if (1 != msg->is_subordinate) | ||
645 | { | ||
646 | slave->controller = | ||
647 | GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id], | ||
648 | EVENT_MASK, &slave_event_callback, | ||
649 | slave); | ||
650 | if (NULL != slave->controller) | ||
651 | send_controller_link_response (client, | ||
652 | GNUNET_ntohll (msg->operation_id), | ||
653 | NULL, | ||
654 | NULL); | ||
655 | else | ||
656 | send_controller_link_response (client, | ||
657 | GNUNET_ntohll (msg->operation_id), | ||
658 | NULL, | ||
659 | "Could not connect to delegated controller"); | ||
660 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
661 | return; | ||
662 | } | ||
663 | lcc = GNUNET_malloc (sizeof (struct LinkControllersContext)); | ||
664 | lcc->operation_id = GNUNET_ntohll (msg->operation_id); | ||
665 | GNUNET_SERVER_client_keep (client); | ||
666 | lcc->client = client; | ||
667 | slave->lcc = lcc; | ||
668 | slave->controller_proc = | ||
669 | GNUNET_TESTBED_controller_start (GST_context->master_ip, | ||
670 | GST_host_list[slave->host_id], cfg, | ||
671 | &slave_status_callback, slave); | ||
672 | GNUNET_CONFIGURATION_destroy (cfg); | ||
673 | new_route = GNUNET_malloc (sizeof (struct Route)); | ||
674 | new_route->dest = delegated_host_id; | ||
675 | new_route->thru = GST_context->host_id; | ||
676 | route_list_add (new_route); | ||
677 | return; | ||
678 | } | ||
679 | |||
680 | /* Route the request */ | ||
681 | if (slave_host_id >= route_list_size) | ||
682 | { | ||
683 | LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host"); | ||
684 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
685 | return; | ||
686 | } | ||
687 | lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue)); | ||
688 | lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext)); | ||
689 | lcfq->lcf->type = CLOSURE_TYPE_LCF; | ||
690 | lcfq->lcf->delegated_host_id = delegated_host_id; | ||
691 | lcfq->lcf->slave_host_id = slave_host_id; | ||
692 | route = GST_find_dest_route (slave_host_id); | ||
693 | GNUNET_assert (NULL != route); /* because we add routes carefully */ | ||
694 | GNUNET_assert (route->dest < GST_slave_list_size); | ||
695 | GNUNET_assert (NULL != GST_slave_list[route->dest]); | ||
696 | lcfq->lcf->cfg = cfg; | ||
697 | lcfq->lcf->is_subordinate = msg->is_subordinate; | ||
698 | lcfq->lcf->state = INIT; | ||
699 | lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id); | ||
700 | lcfq->lcf->gateway = GST_slave_list[route->dest]; | ||
701 | GNUNET_SERVER_client_keep (client); | ||
702 | lcfq->lcf->client = client; | ||
703 | if (NULL == lcfq_head) | ||
704 | { | ||
705 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); | ||
706 | GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq); | ||
707 | lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf); | ||
708 | } | ||
709 | else | ||
710 | GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq); | ||
711 | /* FIXME: Adding a new route should happen after the controllers are linked | ||
712 | * successfully */ | ||
713 | if (1 != msg->is_subordinate) | ||
714 | { | ||
715 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
716 | return; | ||
717 | } | ||
718 | if ((delegated_host_id < route_list_size) && | ||
719 | (NULL != route_list[delegated_host_id])) | ||
720 | { | ||
721 | GNUNET_break_op (0); /* Are you trying to link delegated host twice | ||
722 | * with is subordinate flag set to GNUNET_YES? */ | ||
723 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
724 | return; | ||
725 | } | ||
726 | new_route = GNUNET_malloc (sizeof (struct Route)); | ||
727 | new_route->dest = delegated_host_id; | ||
728 | new_route->thru = route->dest; | ||
729 | route_list_add (new_route); | ||
730 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
731 | } | ||
732 | |||
733 | |||
734 | /** | ||
735 | * Cleans up the queue used for forwarding link controllers requests | ||
736 | */ | ||
737 | void | ||
738 | GST_free_lcfq () | ||
739 | { | ||
740 | struct LCFContextQueue *lcfq; | ||
741 | |||
742 | if (NULL != lcfq_head) | ||
743 | { | ||
744 | if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id) | ||
745 | { | ||
746 | GNUNET_SCHEDULER_cancel (lcf_proc_task_id); | ||
747 | lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK; | ||
748 | } | ||
749 | } | ||
750 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id); | ||
751 | for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head) | ||
752 | { | ||
753 | GNUNET_SERVER_client_drop (lcfq->lcf->client); | ||
754 | GNUNET_assert (NULL != lcfq->lcf->cfg); | ||
755 | GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg); | ||
756 | GNUNET_free (lcfq->lcf); | ||
757 | GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq); | ||
758 | GNUNET_free (lcfq); | ||
759 | } | ||
760 | } | ||