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;
130 * The host destination is reachable thru
137 * Structure representing a connected(directly-linked) controller
142 * The controller process handle if we had started the controller
144 struct GNUNET_TESTBED_ControllerProc *controller_proc;
147 * The controller handle
149 struct GNUNET_TESTBED_Controller *controller;
152 * The id of the host this controller is running on
159 * States of LCFContext
164 * The Context has been initialized; Nothing has been done on it
169 * Delegated host has been registered at the forwarding controller
171 DELEGATED_HOST_REGISTERED,
174 * The context has been finished (may have error)
182 * Link controllers request forwarding context
187 * The serialized and compressed configuration
192 * The gateway which will pass the link message to delegated host
194 struct Slave *gateway;
197 * The host registration handle while registered hosts in this context
199 struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
202 * The size of the compressed serialized configuration
207 * The size of the uncompressed configuration
212 * Should the delegated host be started by the slave host?
217 * The state of this context
219 enum LCFContextState state;
224 uint32_t delegated_host_id;
231 * Structure of a queue entry in LCFContext request queue
233 struct LCFContextQueue
238 struct LCFContext *lcf;
243 struct LCFContextQueue *next;
248 struct LCFContextQueue *prev;
253 * The master context; generated with the first INIT message
255 static struct Context *master_context;
264 static struct GNUNET_DISK_FileHandle *fh;
267 * Current Transmit Handle; NULL if no notify transmit exists currently
269 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
276 * The head for the LCF queue
278 static struct LCFContextQueue *lcfq_head;
281 * The tail for the LCF queue
283 static struct LCFContextQueue *lcfq_tail;
286 * The message queue head
288 static struct MessageQueue *mq_head;
291 * The message queue tail
293 static struct MessageQueue *mq_tail;
298 static struct GNUNET_TESTBED_Host **host_list;
303 static struct Route **route_list;
306 * A list of directly linked neighbours
308 static struct Slave **slave_list;
311 * The hashmap of shared services
313 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
316 * The size of the host list
318 static uint32_t host_list_size;
321 * The size of the route list
323 static uint32_t route_list_size;
326 * The size of directly linked neighbours list
328 static uint32_t slave_list_size;
335 * The lcf_task handle
337 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
340 * The shutdown task handle
342 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
346 * Function called to notify a client about the connection begin ready to queue
347 * more data. "buf" will be NULL and "size" zero if the connection was closed
348 * for writing in the meantime.
351 * @param size number of bytes available in buf
352 * @param buf where the callee should write the message
353 * @return number of bytes written to buf
356 transmit_ready_notify (void *cls, size_t size, void *buf)
358 struct MessageQueue *mq_entry;
360 transmit_handle = NULL;
362 GNUNET_assert (NULL != mq_entry);
365 GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
366 size = ntohs (mq_entry->msg->size);
367 memcpy (buf, mq_entry->msg, size);
368 GNUNET_free (mq_entry->msg);
369 GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
370 GNUNET_free (mq_entry);
372 if (NULL != mq_entry)
374 GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
375 ntohs (mq_entry->msg->size),
376 GNUNET_TIME_UNIT_FOREVER_REL,
377 &transmit_ready_notify, NULL);
383 * Queues a message in send queue for sending to the service
385 * @param client the client to whom the queued message has to be sent
386 * @param msg the message to queue
389 queue_message (struct GNUNET_SERVER_Client *client,
390 struct GNUNET_MessageHeader *msg)
392 struct MessageQueue *mq_entry;
396 type = ntohs (msg->type);
397 size = ntohs (msg->size);
398 GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
399 (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
400 mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
402 mq_entry->client = client;
403 LOG_DEBUG ( "Queueing message of type %u, size %u for sending\n", type,
405 GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
406 if (NULL == transmit_handle)
408 GNUNET_SERVER_notify_transmit_ready (client, size,
409 GNUNET_TIME_UNIT_FOREVER_REL,
410 &transmit_ready_notify, NULL);
415 * Function to add a host to the current list of known hosts
417 * @param host the host to add
418 * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
422 host_list_add (struct GNUNET_TESTBED_Host *host)
427 host_id = GNUNET_TESTBED_host_get_id_ (host);
428 if (host_list_size <= host_id)
430 new_size = host_list_size + LIST_GROW_STEP;
431 host_list = GNUNET_realloc (host_list,
432 sizeof (struct GNUNET_TESTBED_Host *)
434 memset (&host_list[host_list_size], 0,
435 sizeof (struct Slave *) * LIST_GROW_STEP);
436 host_list_size = new_size;
438 if (NULL != host_list[host_id])
440 LOG_DEBUG ("A host with id: %u already exists\n", host_id);
441 return GNUNET_SYSERR;
443 host_list[host_id] = host;
449 * Adds a route to the route list
451 * @param route the route to add
454 route_list_add (struct Route *route)
458 if (route->dest >= route_list_size)
460 new_size = route_list_size + LIST_GROW_STEP;
461 route_list = GNUNET_realloc (route_list, sizeof (struct Route *)
463 memset (&route_list[route_list_size], 0,
464 sizeof (struct Slave *) * LIST_GROW_STEP);
465 route_list_size = new_size;
467 GNUNET_assert (NULL == route_list[route->dest]);
468 route_list[route->dest] = route;
473 * Adds a slave to the slave array
475 * @param route the route to add
478 slave_list_add (struct Slave *slave)
482 if (slave->host_id >= slave_list_size)
484 new_size = slave_list_size + LIST_GROW_STEP;
485 slave_list = GNUNET_realloc (slave_list, sizeof (struct Slave *)
487 memset (&slave_list[slave_list_size], 0,
488 sizeof (struct Slave *) * LIST_GROW_STEP);
489 slave_list_size = new_size;
491 GNUNET_assert (NULL == slave_list[slave->host_id]);
492 slave_list[slave->host_id] = slave;
497 * Routes message to a host given its host_id
499 * @param host_id the id of the destination host
500 * @param msg the message to be routed
503 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
510 * The Link Controller forwarding task
512 * @param cls the LCFContext
513 * @param tc the Task context from scheduler
516 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
520 * Completion callback for host registrations while forwarding Link Controller messages
522 * @param cls the LCFContext
523 * @param emsg the error message; NULL if host registration is successful
526 lcf_proc_cc (void *cls, const char *emsg)
528 struct LCFContext *lcf = cls;
531 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
537 LOG (GNUNET_ERROR_TYPE_WARNING,
538 "Host registration failed with message: %s\n", emsg);
539 lcf->state = FINISHED;
540 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
543 lcf->state = DELEGATED_HOST_REGISTERED;
544 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
547 GNUNET_assert (0); /* Shouldn't reach here */
553 * The Link Controller forwarding task
555 * @param cls the LCFContext
556 * @param tc the Task context from scheduler
559 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
561 struct LCFContext *lcf = cls;
562 struct LCFContextQueue *lcfq;
564 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
569 GNUNET_TESTBED_is_host_registered_ (host_list[lcf->delegated_host_id],
570 lcf->gateway->controller))
573 GNUNET_TESTBED_register_host (lcf->gateway->controller,
574 host_list[lcf->delegated_host_id],
579 lcf->state = DELEGATED_HOST_REGISTERED;
580 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
583 case DELEGATED_HOST_REGISTERED:
584 GNUNET_TESTBED_controller_link_2 (lcf->gateway->controller,
585 host_list[lcf->delegated_host_id],
586 host_list[lcf->gateway->host_id],
587 lcf->sxcfg, lcf->sxcfg_size,
589 lcf->is_subordinate);
590 lcf->state = FINISHED;
593 GNUNET_assert (lcfq->lcf == lcf);
594 GNUNET_free (lcf->sxcfg);
596 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
598 if (NULL != lcfq_head)
600 GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
606 * Callback for event from slave controllers
608 * @param cls struct Slave *
609 * @param event information about the event
612 slave_event_callback(void *cls,
613 const struct GNUNET_TESTBED_EventInformation *event)
621 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
624 * @param client identification of the client
625 * @param message the actual message
628 handle_init (void *cls,
629 struct GNUNET_SERVER_Client *client,
630 const struct GNUNET_MessageHeader *message)
632 const struct GNUNET_TESTBED_InitMessage *msg;
633 struct GNUNET_TESTBED_Host *host;
635 if (NULL != master_context)
638 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
641 msg = (const struct GNUNET_TESTBED_InitMessage *) message;
642 master_context = GNUNET_malloc (sizeof (struct Context));
643 master_context->client = client;
644 master_context->host_id = ntohl (msg->host_id);
645 host = GNUNET_TESTBED_host_create_with_id (master_context->host_id,
647 host_list_add (host);
648 master_context->event_mask = GNUNET_ntohll (msg->event_mask);
649 GNUNET_SERVER_client_keep (client);
650 LOG_DEBUG ("Created master context with host ID: %u\n",
651 master_context->host_id);
652 GNUNET_SERVER_receive_done (client, GNUNET_OK);
657 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
660 * @param client identification of the client
661 * @param message the actual message
664 handle_add_host (void *cls,
665 struct GNUNET_SERVER_Client *client,
666 const struct GNUNET_MessageHeader *message)
668 struct GNUNET_TESTBED_Host *host;
669 const struct GNUNET_TESTBED_AddHostMessage *msg;
670 struct GNUNET_TESTBED_HostConfirmedMessage *reply;
675 uint16_t username_length;
676 uint16_t hostname_length;
679 msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
680 username_length = ntohs (msg->user_name_length);
681 username_length = (0 == username_length) ? 0 : username_length + 1;
682 username = (char *) &(msg[1]);
683 hostname = username + username_length;
684 if (ntohs (message->size) <=
685 (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length))
688 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
691 hostname_length = ntohs (message->size)
692 - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
693 if (strlen (hostname) != hostname_length - 1)
696 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
699 host_id = ntohl (msg->host_id);
700 LOG_DEBUG ("Received ADDHOST message\n");
701 LOG_DEBUG ("-------host id: %u\n", host_id);
702 if (NULL != hostname) LOG_DEBUG ("-------hostname: %s\n", hostname);
703 if (0 != username_length) LOG_DEBUG ("-------username: %s\n", username);
704 else LOG_DEBUG ("-------username: NULL\n");
705 LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
706 host = GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
707 ntohs (msg->ssh_port));
708 GNUNET_SERVER_receive_done (client, GNUNET_OK);
709 reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
710 if (GNUNET_OK != host_list_add (host))
712 /* We are unable to add a host */
713 emsg = "A host exists with given host-id";
714 LOG_DEBUG ("%s: %u", emsg, host_id);
715 GNUNET_TESTBED_host_destroy (host);
716 reply_size += strlen (emsg) + 1;
717 reply = GNUNET_malloc (reply_size);
718 memcpy (&reply[1], emsg, strlen (emsg) + 1);
721 reply = GNUNET_malloc (reply_size);
722 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM);
723 reply->header.size = htons (reply_size);
724 reply->host_id = htonl (host_id);
725 queue_message (client, (struct GNUNET_MessageHeader *) reply);
730 * Iterator over hash map entries.
733 * @param key current key code
734 * @param value value in the hash map
735 * @return GNUNET_YES if we should continue to
739 int ss_exists_iterator (void *cls,
740 const struct GNUNET_HashCode * key,
743 struct SharedService *queried_ss = cls;
744 struct SharedService *ss = value;
746 if (0 == strcmp (ss->name, queried_ss->name))
753 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
756 * @param client identification of the client
757 * @param message the actual message
760 handle_configure_shared_service (void *cls,
761 struct GNUNET_SERVER_Client *client,
762 const struct GNUNET_MessageHeader *message)
764 const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
765 struct SharedService *ss;
767 struct GNUNET_HashCode hash;
769 uint16_t service_name_size;
771 msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
772 msg_size = ntohs (message->size);
773 if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
776 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
779 service_name_size = msg_size -
780 sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
781 service_name = (char *) &msg[1];
782 if ('\0' != service_name[service_name_size - 1])
785 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
788 LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
789 service_name, ntohl (msg->num_peers));
790 if (ntohl (msg->host_id) != master_context->host_id)
792 route_message (ntohl (msg->host_id), message);
793 GNUNET_SERVER_receive_done (client, GNUNET_OK);
796 GNUNET_SERVER_receive_done (client, GNUNET_OK);
797 ss = GNUNET_malloc (sizeof (struct SharedService));
798 ss->name = strdup (service_name);
799 ss->num_shared = ntohl (msg->num_peers);
800 GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
802 GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
803 &ss_exists_iterator, ss))
805 LOG (GNUNET_ERROR_TYPE_WARNING,
806 "Service %s already configured as a shared service. "
807 "Ignoring service sharing request \n", ss->name);
808 GNUNET_free (ss->name);
812 GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
813 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
818 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
821 * @param client identification of the client
822 * @param message the actual message
825 handle_link_controllers (void *cls,
826 struct GNUNET_SERVER_Client *client,
827 const struct GNUNET_MessageHeader *message)
829 const struct GNUNET_TESTBED_ControllerLinkMessage *msg;
830 struct GNUNET_CONFIGURATION_Handle *cfg;
831 struct LCFContextQueue *lcfq;
833 struct Route *new_route;
837 uint32_t delegated_host_id;
838 uint32_t slave_host_id;
841 if (NULL == master_context)
844 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
847 msize = ntohs (message->size);
848 if (sizeof (struct GNUNET_TESTBED_ControllerLinkMessage) >= msize)
851 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
854 msg = (const struct GNUNET_TESTBED_ControllerLinkMessage *) message;
855 delegated_host_id = ntohl (msg->delegated_host_id);
856 if (delegated_host_id == master_context->host_id)
859 LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
860 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
863 if ((delegated_host_id >= host_list_size) ||
864 (NULL == host_list[delegated_host_id]))
866 LOG (GNUNET_ERROR_TYPE_WARNING, "Delegated host not registered with us\n");
867 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
870 slave_host_id = ntohl (msg->slave_host_id);
871 if ((slave_host_id >= host_list_size) || (NULL == host_list[slave_host_id]))
873 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host not registered with us\n");
874 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
877 if (slave_host_id == delegated_host_id)
879 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
880 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
883 msize -= sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
884 config_size = ntohs (msg->config_size);
886 if (slave_host_id == master_context->host_id) /* Link from us */
890 if ((delegated_host_id < slave_list_size) &&
891 (NULL != slave_list[delegated_host_id])) /* We have already added */
893 LOG (GNUNET_ERROR_TYPE_WARNING, "Host %u already connected\n",
895 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
898 config = GNUNET_malloc (config_size);
899 dest_size = (uLongf) config_size;
900 if (Z_OK != uncompress ((Bytef *) config, &dest_size,
901 (const Bytef *) &msg[1], (uLong) msize))
903 GNUNET_break (0); /* Compression error */
904 GNUNET_free (config);
905 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
908 if (config_size == dest_size)
910 LOG (GNUNET_ERROR_TYPE_WARNING, "Uncompressed config size mismatch\n");
911 GNUNET_free (config);
912 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
914 cfg = GNUNET_CONFIGURATION_create (); /* Free here or in lcfcontext */
915 if (GNUNET_OK != GNUNET_CONFIGURATION_deserialize (cfg, config, config_size,
918 GNUNET_break (0); /* Configuration parsing error */
919 GNUNET_free (config);
920 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
923 GNUNET_free (config);
924 if ((delegated_host_id < slave_list_size) &&
925 (NULL != slave_list[delegated_host_id]))
927 GNUNET_break (0); /* Configuration parsing error */
928 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
931 slave = GNUNET_malloc (sizeof (struct Slave));
932 slave->host_id = delegated_host_id;
933 slave_list_add (slave);
934 if (1 == msg->is_subordinate)
936 slave->controller_proc =
937 GNUNET_TESTBED_controller_start (host_list[delegated_host_id]);
940 GNUNET_TESTBED_controller_connect (cfg, host_list[delegated_host_id],
941 master_context->event_mask,
942 &slave_event_callback, slave);
943 GNUNET_CONFIGURATION_destroy (cfg);
944 new_route = GNUNET_malloc (sizeof (struct Route));
945 new_route->dest = delegated_host_id;
946 new_route->thru = master_context->host_id;
947 route_list_add (new_route);
948 GNUNET_SERVER_receive_done (client, GNUNET_OK);
952 /* Route the request */
953 if (slave_host_id >= route_list_size)
955 LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
956 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
959 while (NULL != (route = route_list[slave_host_id]))
961 if (route->thru == master_context->host_id)
963 slave_host_id = route->thru;
965 GNUNET_assert (NULL != route); /* because we add routes carefully */
966 GNUNET_assert (route->dest < slave_list_size);
967 GNUNET_assert (NULL != slave_list[route->dest]);
968 lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
969 lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
970 lcfq->lcf->delegated_host_id = delegated_host_id;
971 lcfq->lcf->is_subordinate =
972 (1 == msg->is_subordinate) ? GNUNET_YES : GNUNET_NO;
973 lcfq->lcf->state = INIT;
974 lcfq->lcf->gateway = slave_list[route->dest];
975 lcfq->lcf->sxcfg_size = msize;
976 lcfq->lcf->sxcfg = GNUNET_malloc (msize);
977 lcfq->lcf->scfg_size = config_size;
978 (void) memcpy (lcfq->lcf->sxcfg, &msg[1], msize);
979 if (NULL == lcfq_head)
981 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
982 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
983 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq);
986 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
987 GNUNET_SERVER_receive_done (client, GNUNET_OK);
988 new_route = GNUNET_malloc (sizeof (struct Route));
989 new_route->dest = delegated_host_id;
990 new_route->thru = route->dest;
991 route_list_add (new_route);
996 * Iterator over hash map entries.
999 * @param key current key code
1000 * @param value value in the hash map
1001 * @return GNUNET_YES if we should continue to
1006 ss_map_free_iterator (void *cls,
1007 const struct GNUNET_HashCode * key, void *value)
1009 struct SharedService *ss = value;
1011 GNUNET_assert (GNUNET_YES ==
1012 GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
1013 GNUNET_free (ss->name);
1020 * Task to clean up and shutdown nicely
1023 * @param tc the TaskContext from scheduler
1026 shutdown_task (void *cls,
1027 const struct GNUNET_SCHEDULER_TaskContext *tc)
1029 struct LCFContextQueue *lcfq;
1032 shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
1033 GNUNET_SCHEDULER_shutdown ();
1034 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
1035 (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
1037 GNUNET_CONTAINER_multihashmap_destroy (ss_map);
1040 GNUNET_DISK_file_close (fh);
1043 if (NULL != lcfq_head)
1045 if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
1047 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1048 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1050 if (NULL != lcfq_head->lcf->rhandle)
1051 GNUNET_TESTBED_cancel_registration (lcfq_head->lcf->rhandle);
1053 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1054 for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
1056 GNUNET_free (lcfq->lcf->sxcfg);
1057 GNUNET_free (lcfq->lcf);
1058 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
1061 /* Clear host list */
1062 for (id = 0; id < host_list_size; id++)
1063 if (NULL != host_list[id])
1064 GNUNET_TESTBED_host_destroy (host_list[id]);
1065 GNUNET_free_non_null (host_list);
1066 /* Clear route list */
1067 for (id = 0; id < route_list_size; id++)
1068 if (NULL != route_list[id])
1069 GNUNET_free (route_list[id]);
1070 GNUNET_free_non_null (route_list);
1071 /* Clear slave_list */
1072 for (id = 0; id < slave_list_size; id++)
1073 if (NULL != slave_list[id])
1075 GNUNET_assert (NULL != slave_list[id]->controller);
1076 GNUNET_TESTBED_controller_disconnect (slave_list[id]->controller);
1077 if (NULL != slave_list[id]->controller_proc)
1078 GNUNET_TESTBED_controller_stop (slave_list[id]->controller_proc);
1080 GNUNET_free_non_null (master_context);
1085 * Callback for client disconnect
1088 * @param client the client which has disconnected
1091 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
1093 if (NULL == master_context)
1095 if (client == master_context->client)
1097 LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
1098 GNUNET_SERVER_client_drop (client);
1099 /* should not be needed as we're terminated by failure to read
1100 from stdin, but if stdin fails for some reason, this shouldn't
1101 hurt for now --- might need to revise this later if we ever
1102 decide that master connections might be temporarily down
1104 GNUNET_SCHEDULER_shutdown ();
1112 * @param cls closure
1113 * @param server the initialized server
1114 * @param cfg configuration to use
1117 testbed_run (void *cls,
1118 struct GNUNET_SERVER_Handle *server,
1119 const struct GNUNET_CONFIGURATION_Handle *cfg)
1121 static const struct GNUNET_SERVER_MessageHandler message_handlers[] =
1123 {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT,
1124 sizeof (struct GNUNET_TESTBED_InitMessage)},
1125 {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST, 0},
1126 {&handle_configure_shared_service, NULL,
1127 GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE, 0},
1128 {&handle_link_controllers, NULL,
1129 GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS, 0},
1133 GNUNET_SERVER_add_handlers (server,
1135 GNUNET_SERVER_disconnect_notify (server,
1136 &client_disconnect_cb,
1138 ss_map = GNUNET_CONTAINER_multihashmap_create (5);
1139 fh = GNUNET_DISK_get_handle_from_native (stdin);
1142 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1147 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1151 LOG_DEBUG ("Testbed startup complete\n");
1156 * The starting point of execution
1158 int main (int argc, char *const *argv)
1162 GNUNET_SERVICE_run (argc,
1165 GNUNET_SERVICE_OPTION_NONE,