2 This file is part of GNUnet.
3 (C) 2012 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.c
23 * @brief implementation of the TESTBED service
24 * @author Sree Harsha Totakura
28 #include "gnunet_service_lib.h"
29 #include "gnunet_server_lib.h"
33 #include "gnunet_testbed_service.h"
34 #include "testbed_api_hosts.h"
39 #define LOG(kind,...) \
40 GNUNET_log (kind, __VA_ARGS__)
45 #define LOG_DEBUG(...) \
46 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
49 #define LIST_GROW_STEP 10
54 * The client handle associated with this context
56 struct GNUNET_SERVER_Client *client;
59 * Event mask of event to be responded in this context
64 * Our host id according to this context
71 * The message queue for sending messages to clients
76 * The message to be sent
78 struct GNUNET_MessageHeader *msg;
81 * The client to send the message to
83 struct GNUNET_SERVER_Client *client;
86 * next pointer for DLL
88 struct MessageQueue *next;
91 * prev pointer for DLL
93 struct MessageQueue *prev;
98 * The structure for identifying a shared service
103 * The name of the shared service
108 * Number of shared peers per instance of the shared service
113 * Number of peers currently sharing the service
115 uint32_t num_sharing;
125 * The forwarding (next hop) host id
130 * The controller handle if we have started the controller at the next hop
133 struct GNUNET_TESTBED_Controller *fcontroller;
136 * The controller process handle if we started the controller
138 struct GNUNET_TESTBED_ControllerProc *fcontroller_proc;
143 * States of LCFContext
148 * The Context has been initialized; Nothing has been done on it
153 * Delegated host has been registered at the forwarding controller
155 DELEGATED_HOST_REGISTERED,
158 * The slave host has been registred at the forwarding controller
160 SLAVE_HOST_REGISTERED,
163 * The context has been finished (may have error)
171 * Link controllers request forwarding context
178 struct GNUNET_CONFIGURATION_Handle *cfg;
181 * The handle of the controller this request has to be forwarded to
183 struct GNUNET_TESTBED_Controller *fcontroller;
186 * The host registration handle while registered hosts in this context
188 struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
191 * Should the delegated host be started by the slave host?
196 * The state of this context
198 enum LCFContextState state;
203 uint32_t delegated_host_id;
208 uint32_t slave_host_id;
214 * Structure of a queue entry in LCFContext request queue
216 struct LCFContextQueue
221 struct LCFContext *lcf;
226 struct LCFContextQueue *next;
231 struct LCFContextQueue *prev;
237 * Structure representing a connected(directly-linked) controller
242 * The controller process handle if we had started the controller
244 struct GNUNET_TESTBED_ControllerProc *controller_proc;
247 * The controller handle
249 struct GNUNET_TESTBED_Controller *controller;
252 * The id of the host this controller is running on
259 * The master context; generated with the first INIT message
261 static struct Context *master_context;
270 static struct GNUNET_DISK_FileHandle *fh;
273 * Current Transmit Handle; NULL if no notify transmit exists currently
275 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
282 * The head for the LCF queue
284 static struct LCFContextQueue *lcfq_head;
287 * The tail for the LCF queue
289 static struct LCFContextQueue *lcfq_tail;
292 * The message queue head
294 static struct MessageQueue *mq_head;
297 * The message queue tail
299 static struct MessageQueue *mq_tail;
304 static struct GNUNET_TESTBED_Host **host_list;
309 static struct Route **route_list;
312 * A list of directly linked neighbours
314 static struct Slave **slave_list;
317 * The hashmap of shared services
319 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
322 * The size of the host list
324 static uint32_t host_list_size;
327 * The size of the route list
329 static uint32_t route_list_size;
332 * The size of directly linked neighbours list
334 static uint32_t slave_list_size;
341 * The lcf_task handle
343 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
346 * The shutdown task handle
348 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
352 * Function called to notify a client about the connection begin ready to queue
353 * more data. "buf" will be NULL and "size" zero if the connection was closed
354 * for writing in the meantime.
357 * @param size number of bytes available in buf
358 * @param buf where the callee should write the message
359 * @return number of bytes written to buf
362 transmit_ready_notify (void *cls, size_t size, void *buf)
364 struct MessageQueue *mq_entry;
366 transmit_handle = NULL;
368 GNUNET_assert (NULL != mq_entry);
371 GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
372 size = ntohs (mq_entry->msg->size);
373 memcpy (buf, mq_entry->msg, size);
374 GNUNET_free (mq_entry->msg);
375 GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
376 GNUNET_free (mq_entry);
378 if (NULL != mq_entry)
380 GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
381 ntohs (mq_entry->msg->size),
382 GNUNET_TIME_UNIT_FOREVER_REL,
383 &transmit_ready_notify, NULL);
389 * Queues a message in send queue for sending to the service
391 * @param client the client to whom the queued message has to be sent
392 * @param msg the message to queue
395 queue_message (struct GNUNET_SERVER_Client *client,
396 struct GNUNET_MessageHeader *msg)
398 struct MessageQueue *mq_entry;
402 type = ntohs (msg->type);
403 size = ntohs (msg->size);
404 GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
405 (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
406 mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
408 mq_entry->client = client;
409 LOG_DEBUG ( "Queueing message of type %u, size %u for sending\n", type,
411 GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
412 if (NULL == transmit_handle)
414 GNUNET_SERVER_notify_transmit_ready (client, size,
415 GNUNET_TIME_UNIT_FOREVER_REL,
416 &transmit_ready_notify, NULL);
421 * Function to add a host to the current list of known hosts
423 * @param host the host to add
424 * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
428 host_list_add (struct GNUNET_TESTBED_Host *host)
432 host_id = GNUNET_TESTBED_host_get_id_ (host);
433 if (host_list_size <= host_id)
435 host_list = GNUNET_realloc (host_list,
436 sizeof (struct GNUNET_TESTBED_Host *)
438 host_list_size += (host_id + 10);
440 if (NULL != host_list[host_id])
442 LOG_DEBUG ("A host with id: %u already exists\n", host_id);
443 return GNUNET_SYSERR;
445 host_list[host_id] = host;
451 * Routes message to a host given its host_id
453 * @param host_id the id of the destination host
454 * @param msg the message to be routed
457 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
464 * The Link Controller forwarding task
466 * @param cls the LCFContext
467 * @param tc the Task context from scheduler
470 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
474 * Completion callback for host registrations while forwarding Link Controller messages
476 * @param cls the LCFContext
477 * @param emsg the error message; NULL if host registration is successful
480 lcf_proc_cc (void *cls, const char *emsg)
482 struct LCFContext *lcf = cls;
485 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
490 goto registration_error;
491 lcf->state = DELEGATED_HOST_REGISTERED;
492 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
494 case DELEGATED_HOST_REGISTERED:
496 goto registration_error;
497 lcf->state = SLAVE_HOST_REGISTERED;
498 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
501 GNUNET_assert (0); /* Shouldn't reach here */
506 LOG (GNUNET_ERROR_TYPE_WARNING,
507 "Host registration failed with message: %s\n", emsg);
508 lcf->state = FINISHED;
509 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
514 * The Link Controller forwarding task
516 * @param cls the LCFContext
517 * @param tc the Task context from scheduler
520 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
522 struct LCFContext *lcf = cls;
523 struct LCFContextQueue *lcfq;
525 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
530 GNUNET_TESTBED_is_host_registered_ (host_list[lcf->delegated_host_id],
534 GNUNET_TESTBED_register_host (lcf->fcontroller,
535 host_list[lcf->delegated_host_id],
540 lcf->state = DELEGATED_HOST_REGISTERED;
541 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
544 case DELEGATED_HOST_REGISTERED:
546 GNUNET_TESTBED_is_host_registered_ (host_list[lcf->slave_host_id],
550 GNUNET_TESTBED_register_host (lcf->fcontroller,
551 host_list[lcf->slave_host_id],
556 lcf->state = SLAVE_HOST_REGISTERED;
557 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
560 case SLAVE_HOST_REGISTERED:
561 GNUNET_TESTBED_controller_link (lcf->fcontroller,
562 host_list[lcf->delegated_host_id],
563 host_list[lcf->slave_host_id],
564 lcf->cfg, lcf->is_subordinate);
565 lcf->state = FINISHED;
568 GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg);
569 GNUNET_free (lcfq->lcf);
570 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
572 if (NULL != lcfq_head)
573 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
579 * Callback for event from slave controllers
581 * @param cls struct Slave *
582 * @param event information about the event
585 slave_event_callback(void *cls,
586 const struct GNUNET_TESTBED_EventInformation *event)
594 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
597 * @param client identification of the client
598 * @param message the actual message
601 handle_init (void *cls,
602 struct GNUNET_SERVER_Client *client,
603 const struct GNUNET_MessageHeader *message)
605 const struct GNUNET_TESTBED_InitMessage *msg;
606 struct GNUNET_TESTBED_Host *host;
608 if (NULL != master_context)
611 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
614 msg = (const struct GNUNET_TESTBED_InitMessage *) message;
615 master_context = GNUNET_malloc (sizeof (struct Context));
616 master_context->client = client;
617 master_context->host_id = ntohl (msg->host_id);
618 host = GNUNET_TESTBED_host_create_with_id (master_context->host_id,
620 host_list_add (host);
621 master_context->event_mask = GNUNET_ntohll (msg->event_mask);
622 GNUNET_SERVER_client_keep (client);
623 LOG_DEBUG ("Created master context with host ID: %u\n",
624 master_context->host_id);
625 GNUNET_SERVER_receive_done (client, GNUNET_OK);
630 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
633 * @param client identification of the client
634 * @param message the actual message
637 handle_add_host (void *cls,
638 struct GNUNET_SERVER_Client *client,
639 const struct GNUNET_MessageHeader *message)
641 struct GNUNET_TESTBED_Host *host;
642 const struct GNUNET_TESTBED_AddHostMessage *msg;
643 struct GNUNET_TESTBED_HostConfirmedMessage *reply;
648 uint16_t username_length;
649 uint16_t hostname_length;
652 msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
653 username_length = ntohs (msg->user_name_length);
654 username_length = (0 == username_length) ? 0 : username_length + 1;
655 username = (char *) &(msg[1]);
656 hostname = username + username_length;
657 if (ntohs (message->size) <=
658 (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length))
661 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
664 hostname_length = ntohs (message->size)
665 - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
666 if (strlen (hostname) != hostname_length)
669 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
672 host_id = ntohl (msg->host_id);
673 LOG_DEBUG ("Received ADDHOST message\n");
674 LOG_DEBUG ("-------host id: %u\n", host_id);
675 if (NULL != hostname) LOG_DEBUG ("-------hostname: %s\n", hostname);
676 if (NULL != username) LOG_DEBUG ("-------username: %s\n", username);
677 LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
678 host = GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
679 ntohs (msg->ssh_port));
680 GNUNET_SERVER_receive_done (client, GNUNET_OK);
681 reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
682 if (GNUNET_OK != host_list_add (host))
684 /* We are unable to add a host */
685 emsg = "A host exists with given host-id";
686 LOG_DEBUG ("%s: %u", emsg, host_id);
687 GNUNET_TESTBED_host_destroy (host);
688 reply_size += strlen (emsg) + 1;
689 reply = GNUNET_malloc (reply_size);
690 memcpy (&reply[1], emsg, strlen (emsg) + 1);
693 reply = GNUNET_malloc (reply_size);
694 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM);
695 reply->header.size = htons (reply_size);
696 reply->host_id = htonl (host_id);
697 queue_message (client, (struct GNUNET_MessageHeader *) reply);
702 * Iterator over hash map entries.
705 * @param key current key code
706 * @param value value in the hash map
707 * @return GNUNET_YES if we should continue to
711 int ss_exists_iterator (void *cls,
712 const struct GNUNET_HashCode * key,
715 struct SharedService *queried_ss = cls;
716 struct SharedService *ss = value;
718 if (0 == strcmp (ss->name, queried_ss->name))
725 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
728 * @param client identification of the client
729 * @param message the actual message
732 handle_configure_shared_service (void *cls,
733 struct GNUNET_SERVER_Client *client,
734 const struct GNUNET_MessageHeader *message)
736 const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
737 struct SharedService *ss;
739 struct GNUNET_HashCode hash;
741 uint16_t service_name_size;
743 msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
744 msg_size = ntohs (message->size);
745 if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
748 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
751 service_name_size = msg_size -
752 sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
753 service_name = (char *) &msg[1];
754 if ('\0' != service_name[service_name_size - 1])
757 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
760 LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
761 service_name, ntohl (msg->num_peers));
762 if (ntohl (msg->host_id) != master_context->host_id)
764 route_message (ntohl (msg->host_id), message);
765 GNUNET_SERVER_receive_done (client, GNUNET_OK);
768 GNUNET_SERVER_receive_done (client, GNUNET_OK);
769 ss = GNUNET_malloc (sizeof (struct SharedService));
770 ss->name = strdup (service_name);
771 ss->num_shared = ntohl (msg->num_peers);
772 GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
774 GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
775 &ss_exists_iterator, ss))
777 LOG (GNUNET_ERROR_TYPE_WARNING,
778 "Service %s already configured as a shared service. "
779 "Ignoring service sharing request \n", ss->name);
780 GNUNET_free (ss->name);
784 GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
785 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
790 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
793 * @param client identification of the client
794 * @param message the actual message
797 handle_link_controllers (void *cls,
798 struct GNUNET_SERVER_Client *client,
799 const struct GNUNET_MessageHeader *message)
801 const struct GNUNET_TESTBED_ControllerLinkMessage *msg;
802 struct GNUNET_CONFIGURATION_Handle *cfg;
803 struct LCFContextQueue *lcfq;
808 uint32_t delegated_host_id;
809 uint32_t slave_host_id;
812 if (NULL == master_context)
815 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
818 msize = ntohs (message->size);
819 if (sizeof (struct GNUNET_TESTBED_ControllerLinkMessage) >= msize)
822 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
825 msg = (const struct GNUNET_TESTBED_ControllerLinkMessage *) message;
826 delegated_host_id = ntohl (msg->delegated_host_id);
827 if (delegated_host_id == master_context->host_id)
830 LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
831 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
834 if ((delegated_host_id >= host_list_size) ||
835 (NULL == host_list[delegated_host_id]))
837 LOG (GNUNET_ERROR_TYPE_WARNING, "Delegated host not registered with us\n");
838 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
841 slave_host_id = ntohl (msg->slave_host_id);
842 if ((slave_host_id >= host_list_size) || (NULL == host_list[slave_host_id]))
844 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host not registered with us\n");
845 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
848 if (slave_host_id == master_context->host_id) /* Link from us */
850 if ((delegated_host_id < slave_list_size) &&
851 (NULL != slave_list[delegated_host_id])) /* We have already added */
853 LOG (GNUNET_ERROR_TYPE_WARNING, "Host %u already connected\n",
855 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
858 config_size = ntohs (msg->config_size);
859 config = GNUNET_malloc (config_size);
860 dest_size = (uLongf) config_size;
861 msize -= sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
862 if (Z_OK != uncompress ((Bytef *) config, &dest_size,
863 (const Bytef *) &msg[1], (uLong) msize))
865 GNUNET_break (0); /* Compression error */
866 GNUNET_free (config);
867 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
870 GNUNET_assert (config_size == dest_size);
871 cfg = GNUNET_CONFIGURATION_create (); /* Free here or in lcfcontext */
872 if (GNUNET_OK != GNUNET_CONFIGURATION_deserialize (cfg, config, config_size,
875 GNUNET_break (0); /* Configuration parsing error */
876 GNUNET_break (config);
877 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
880 GNUNET_free (config);
881 if (delegated_host_id >= slave_list_size)
883 slave_list_size += LIST_GROW_STEP;
884 slave_list = GNUNET_realloc (slave_list,
885 sizeof (struct Slave *) * slave_list_size);
888 slave = GNUNET_malloc (sizeof (struct Slave));
889 slave->host = delegated_host_id;
890 slave_list[delegated_host_id] = slave;
891 if (1 == msg->is_subordinate)
893 slave->controller_proc =
894 GNUNET_TESTBED_controller_start (host_list[delegated_host_id]);
897 GNUNET_TESTBED_controller_connect (cfg, host_list[delegated_host_id],
898 master_context->event_mask,
899 &slave_event_callback, slave);
900 GNUNET_CONFIGURATION_destroy (cfg);
902 /* Route the request */
906 /* If delegated host and slave host are not same we have to forward
907 towards delegated host */
908 if (slave_host_id != delegated_host_id)
910 if ((slave_host_id >= route_list_size) ||
911 (NULL == (route = route_list[slave_host_id])) ||
912 (NULL == route->fcontroller))
914 LOG (GNUNET_ERROR_TYPE_WARNING, "Not route towards slave host");
915 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
918 if (slave_host_id == route->next_hop) /* Slave directly connected */
920 /* Then make slave host and delegated host same so that slave
921 will startup directly link to the delegated host */
922 slave_host_id = delegated_host_id;
924 lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
925 lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
926 lcfq->lcf->delegated_host_id = delegated_host_id;
927 lcfq->lcf->slave_host_id = slave_host_id;
928 lcfq->lcf->is_subordinate =
929 (1 == msg->is_subordinate) ? GNUNET_YES : GNUNET_NO;
930 lcfq->lcf->state = INIT;
931 lcfq->lcf->fcontroller = route->fcontroller;
932 lcfq->lcf->cfg = cfg;
933 if (NULL == lcfq_head)
935 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
936 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
937 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq);
940 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
941 GNUNET_SERVER_receive_done (client, GNUNET_OK);
948 GNUNET_SERVER_receive_done (client, GNUNET_OK);
949 /* If we are not the slave controller then we have to route the request
950 towards the slave controller */
951 if (1 == msg->is_subordinate)
953 GNUNET_break (0); /* FIXME: Implement the slave controller
960 * Iterator over hash map entries.
963 * @param key current key code
964 * @param value value in the hash map
965 * @return GNUNET_YES if we should continue to
970 ss_map_free_iterator (void *cls,
971 const struct GNUNET_HashCode * key, void *value)
973 struct SharedService *ss = value;
975 GNUNET_assert (GNUNET_YES ==
976 GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
977 GNUNET_free (ss->name);
984 * Task to clean up and shutdown nicely
987 * @param tc the TaskContext from scheduler
990 shutdown_task (void *cls,
991 const struct GNUNET_SCHEDULER_TaskContext *tc)
993 struct LCFContextQueue *lcfq;
997 shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
998 GNUNET_SCHEDULER_shutdown ();
999 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
1000 (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
1002 GNUNET_CONTAINER_multihashmap_destroy (ss_map);
1005 GNUNET_DISK_file_close (fh);
1008 if (NULL != lcfq_head)
1010 if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
1012 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1013 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1015 if (NULL != lcfq_head->lcf->rhandle)
1016 GNUNET_TESTBED_cancel_registration (lcfq_head->lcf->rhandle);
1018 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1019 for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
1021 GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg);
1022 GNUNET_free (lcfq->lcf);
1023 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
1026 /* Clear host list */
1027 for (host_id = 0; host_id < host_list_size; host_id++)
1028 if (NULL != host_list[host_id])
1029 GNUNET_TESTBED_host_destroy (host_list[host_id]);
1030 GNUNET_free_non_null (host_list);
1031 /* Clear route list */
1032 for (route_id = 0; route_id < route_list_size; route_id++)
1033 if (NULL != route_list[route_id])
1035 if (NULL != route_list[route_id]->fcontroller)
1036 GNUNET_TESTBED_controller_disconnect (route_list[route_id]->fcontroller);
1037 if (NULL != route_list[route_id]->fcontroller_proc)
1038 GNUNET_TESTBED_controller_stop (route_list[route_id]->fcontroller_proc);
1039 GNUNET_free (route_list[route_id]);
1041 GNUNET_free_non_null (route_list);
1042 GNUNET_free_non_null (master_context);
1047 * Callback for client disconnect
1050 * @param client the client which has disconnected
1053 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
1055 if (NULL == master_context)
1057 if (client == master_context->client)
1059 LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
1060 GNUNET_SERVER_client_drop (client);
1061 /* should not be needed as we're terminated by failure to read
1062 from stdin, but if stdin fails for some reason, this shouldn't
1063 hurt for now --- might need to revise this later if we ever
1064 decide that master connections might be temporarily down
1066 GNUNET_SCHEDULER_shutdown ();
1074 * @param cls closure
1075 * @param server the initialized server
1076 * @param cfg configuration to use
1079 testbed_run (void *cls,
1080 struct GNUNET_SERVER_Handle *server,
1081 const struct GNUNET_CONFIGURATION_Handle *cfg)
1083 static const struct GNUNET_SERVER_MessageHandler message_handlers[] =
1085 {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT,
1086 sizeof (struct GNUNET_TESTBED_InitMessage)},
1087 {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST, 0},
1088 {&handle_configure_shared_service, NULL,
1089 GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE, 0},
1090 {&handle_link_controllers, NULL,
1091 GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS, 0},
1095 GNUNET_SERVER_add_handlers (server,
1097 GNUNET_SERVER_disconnect_notify (server,
1098 &client_disconnect_cb,
1100 ss_map = GNUNET_CONTAINER_multihashmap_create (5);
1101 fh = GNUNET_DISK_get_handle_from_native (stdin);
1104 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1109 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1117 * The starting point of execution
1119 int main (int argc, char *const *argv)
1123 GNUNET_SERVICE_run (argc,
1126 GNUNET_SERVICE_OPTION_NONE,