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__)
51 * The client handle associated with this context
53 struct GNUNET_SERVER_Client *client;
56 * Event mask of event to be responded in this context
61 * Our host id according to this context
68 * The message queue for sending messages to clients
73 * The message to be sent
75 struct GNUNET_MessageHeader *msg;
78 * The client to send the message to
80 struct GNUNET_SERVER_Client *client;
83 * next pointer for DLL
85 struct MessageQueue *next;
88 * prev pointer for DLL
90 struct MessageQueue *prev;
95 * The structure for identifying a shared service
100 * The name of the shared service
105 * Number of shared peers per instance of the shared service
110 * Number of peers currently sharing the service
112 uint32_t num_sharing;
122 * The forwarding (next hop) host id
127 * The controller handle if we have started the controller at the next hop
130 struct GNUNET_TESTBED_Controller *fcontroller;
135 * States of LCFContext
140 * The Context has been initialized; Nothing has been done on it
145 * Delegated host has been registered at the forwarding controller
147 DELEGATED_HOST_REGISTERED,
150 * The slave host has been registred at the forwarding controller
152 SLAVE_HOST_REGISTERED,
155 * The context has been finished (may have error)
163 * Link controllers request forwarding context
170 struct GNUNET_CONFIGURATION_Handle *cfg;
173 * The handle of the controller this request has to be forwarded to
175 struct GNUNET_TESTBED_Controller *fcontroller;
178 * The host registration handle while registered hosts in this context
180 struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
183 * Should the delegated host be started by the slave host?
188 * The state of this context
190 enum LCFContextState state;
195 uint32_t delegated_host_id;
200 uint32_t slave_host_id;
206 * Structure of a queue entry in LCFContext request queue
208 struct LCFContextQueue
213 struct LCFContext *lcf;
218 struct LCFContextQueue *next;
223 struct LCFContextQueue *prev;
228 * The master context; generated with the first INIT message
230 static struct Context *master_context;
239 static struct GNUNET_DISK_FileHandle *fh;
242 * Current Transmit Handle; NULL if no notify transmit exists currently
244 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
251 * The head for the LCF queue
253 static struct LCFContextQueue *lcfq_head;
256 * The tail for the LCF queue
258 static struct LCFContextQueue *lcfq_tail;
261 * The message queue head
263 static struct MessageQueue *mq_head;
266 * The message queue tail
268 static struct MessageQueue *mq_tail;
273 static struct GNUNET_TESTBED_Host **host_list;
278 static struct Route **route_list;
281 * The hashmap of shared services
283 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
286 * The size of the host list
288 static uint32_t host_list_size;
291 * The size of the route list
293 static uint32_t route_list_size;
300 * The lcf_task handle
302 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
305 * The shutdown task handle
307 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
311 * Function called to notify a client about the connection begin ready to queue
312 * more data. "buf" will be NULL and "size" zero if the connection was closed
313 * for writing in the meantime.
316 * @param size number of bytes available in buf
317 * @param buf where the callee should write the message
318 * @return number of bytes written to buf
321 transmit_ready_notify (void *cls, size_t size, void *buf)
323 struct MessageQueue *mq_entry;
325 transmit_handle = NULL;
327 GNUNET_assert (NULL != mq_entry);
330 GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
331 size = ntohs (mq_entry->msg->size);
332 memcpy (buf, mq_entry->msg, size);
333 GNUNET_free (mq_entry->msg);
334 GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
335 GNUNET_free (mq_entry);
337 if (NULL != mq_entry)
339 GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
340 ntohs (mq_entry->msg->size),
341 GNUNET_TIME_UNIT_FOREVER_REL,
342 &transmit_ready_notify, NULL);
348 * Queues a message in send queue for sending to the service
350 * @param client the client to whom the queued message has to be sent
351 * @param msg the message to queue
354 queue_message (struct GNUNET_SERVER_Client *client,
355 struct GNUNET_MessageHeader *msg)
357 struct MessageQueue *mq_entry;
361 type = ntohs (msg->type);
362 size = ntohs (msg->size);
363 GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
364 (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
365 mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
367 mq_entry->client = client;
368 LOG_DEBUG ( "Queueing message of type %u, size %u for sending\n", type,
370 GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
371 if (NULL == transmit_handle)
373 GNUNET_SERVER_notify_transmit_ready (client, size,
374 GNUNET_TIME_UNIT_FOREVER_REL,
375 &transmit_ready_notify, NULL);
380 * Function to add a host to the current list of known hosts
382 * @param host the host to add
383 * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
387 host_list_add (struct GNUNET_TESTBED_Host *host)
391 host_id = GNUNET_TESTBED_host_get_id_ (host);
392 if (host_list_size <= host_id)
394 host_list = GNUNET_realloc (host_list,
395 sizeof (struct GNUNET_TESTBED_Host *)
397 host_list_size += (host_id + 10);
399 if (NULL != host_list[host_id])
401 LOG_DEBUG ("A host with id: %u already exists\n", host_id);
402 return GNUNET_SYSERR;
404 host_list[host_id] = host;
410 * Routes message to a host given its host_id
412 * @param host_id the id of the destination host
413 * @param msg the message to be routed
416 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
423 * The Link Controller forwarding task
425 * @param cls the LCFContext
426 * @param tc the Task context from scheduler
429 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
433 * Completion callback for host registrations while forwarding Link Controller messages
435 * @param cls the LCFContext
436 * @param emsg the error message; NULL if host registration is successful
439 lcf_proc_cc (void *cls, const char *emsg)
441 struct LCFContext *lcf = cls;
444 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
449 goto registration_error;
450 lcf->state = DELEGATED_HOST_REGISTERED;
451 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
453 case DELEGATED_HOST_REGISTERED:
455 goto registration_error;
456 lcf->state = SLAVE_HOST_REGISTERED;
457 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
460 GNUNET_assert (0); /* Shouldn't reach here */
465 LOG (GNUNET_ERROR_TYPE_WARNING,
466 "Host registration failed with message: %s\n", emsg);
467 lcf->state = FINISHED;
468 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
473 * The Link Controller forwarding task
475 * @param cls the LCFContext
476 * @param tc the Task context from scheduler
479 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
481 struct LCFContext *lcf = cls;
482 struct LCFContextQueue *lcfq;
484 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
489 GNUNET_TESTBED_is_host_registered_ (host_list[lcf->delegated_host_id],
493 GNUNET_TESTBED_register_host (lcf->fcontroller,
494 host_list[lcf->delegated_host_id],
499 lcf->state = DELEGATED_HOST_REGISTERED;
500 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
503 case DELEGATED_HOST_REGISTERED:
505 GNUNET_TESTBED_is_host_registered_ (host_list[lcf->slave_host_id],
509 GNUNET_TESTBED_register_host (lcf->fcontroller,
510 host_list[lcf->slave_host_id],
515 lcf->state = SLAVE_HOST_REGISTERED;
516 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
519 case SLAVE_HOST_REGISTERED:
520 GNUNET_TESTBED_controller_link (lcf->fcontroller,
521 host_list[lcf->delegated_host_id],
522 host_list[lcf->slave_host_id],
523 lcf->cfg, lcf->is_subordinate);
524 lcf->state = FINISHED;
528 GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg);
529 GNUNET_free (lcfq->lcf);
530 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
532 if (NULL != lcfq_head)
533 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
539 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
542 * @param client identification of the client
543 * @param message the actual message
546 handle_init (void *cls,
547 struct GNUNET_SERVER_Client *client,
548 const struct GNUNET_MessageHeader *message)
550 const struct GNUNET_TESTBED_InitMessage *msg;
551 struct GNUNET_TESTBED_Host *host;
553 if (NULL != master_context)
556 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
559 msg = (const struct GNUNET_TESTBED_InitMessage *) message;
560 master_context = GNUNET_malloc (sizeof (struct Context));
561 master_context->client = client;
562 master_context->host_id = ntohl (msg->host_id);
563 host = GNUNET_TESTBED_host_create_with_id (master_context->host_id,
565 host_list_add (host);
566 master_context->event_mask = GNUNET_ntohll (msg->event_mask);
567 GNUNET_SERVER_client_keep (client);
568 LOG_DEBUG ("Created master context with host ID: %u\n",
569 master_context->host_id);
570 GNUNET_SERVER_receive_done (client, GNUNET_OK);
575 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
578 * @param client identification of the client
579 * @param message the actual message
582 handle_add_host (void *cls,
583 struct GNUNET_SERVER_Client *client,
584 const struct GNUNET_MessageHeader *message)
586 struct GNUNET_TESTBED_Host *host;
587 const struct GNUNET_TESTBED_AddHostMessage *msg;
588 struct GNUNET_TESTBED_HostConfirmedMessage *reply;
593 uint16_t username_length;
594 uint16_t hostname_length;
597 msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
598 username_length = ntohs (msg->user_name_length);
599 username_length = (0 == username_length) ? 0 : username_length + 1;
600 username = (char *) &(msg[1]);
601 hostname = username + username_length;
602 if (ntohs (message->size) <=
603 (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length))
606 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
609 hostname_length = ntohs (message->size)
610 - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
611 if (strlen (hostname) != hostname_length)
614 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
617 host_id = ntohl (msg->host_id);
618 LOG_DEBUG ("Received ADDHOST message\n");
619 LOG_DEBUG ("-------host id: %u\n", host_id);
620 if (NULL != hostname) LOG_DEBUG ("-------hostname: %s\n", hostname);
621 if (NULL != username) LOG_DEBUG ("-------username: %s\n", username);
622 LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
623 host = GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
624 ntohs (msg->ssh_port));
625 GNUNET_SERVER_receive_done (client, GNUNET_OK);
626 reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
627 if (GNUNET_OK != host_list_add (host))
629 /* We are unable to add a host */
630 emsg = "A host exists with given host-id";
631 LOG_DEBUG ("%s: %u", emsg, host_id);
632 GNUNET_TESTBED_host_destroy (host);
633 reply_size += strlen (emsg) + 1;
634 reply = GNUNET_malloc (reply_size);
635 memcpy (&reply[1], emsg, strlen (emsg) + 1);
638 reply = GNUNET_malloc (reply_size);
639 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM);
640 reply->header.size = htons (reply_size);
641 reply->host_id = htonl (host_id);
642 queue_message (client, (struct GNUNET_MessageHeader *) reply);
647 * Iterator over hash map entries.
650 * @param key current key code
651 * @param value value in the hash map
652 * @return GNUNET_YES if we should continue to
656 int ss_exists_iterator (void *cls,
657 const struct GNUNET_HashCode * key,
660 struct SharedService *queried_ss = cls;
661 struct SharedService *ss = value;
663 if (0 == strcmp (ss->name, queried_ss->name))
670 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
673 * @param client identification of the client
674 * @param message the actual message
677 handle_configure_shared_service (void *cls,
678 struct GNUNET_SERVER_Client *client,
679 const struct GNUNET_MessageHeader *message)
681 const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
682 struct SharedService *ss;
684 struct GNUNET_HashCode hash;
686 uint16_t service_name_size;
688 msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
689 msg_size = ntohs (message->size);
690 if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
693 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
696 service_name_size = msg_size -
697 sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
698 service_name = (char *) &msg[1];
699 if ('\0' != service_name[service_name_size - 1])
702 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
705 LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
706 service_name, ntohl (msg->num_peers));
707 if (ntohl (msg->host_id) != master_context->host_id)
709 route_message (ntohl (msg->host_id), message);
710 GNUNET_SERVER_receive_done (client, GNUNET_OK);
713 GNUNET_SERVER_receive_done (client, GNUNET_OK);
714 ss = GNUNET_malloc (sizeof (struct SharedService));
715 ss->name = strdup (service_name);
716 ss->num_shared = ntohl (msg->num_peers);
717 GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
719 GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
720 &ss_exists_iterator, ss))
722 LOG (GNUNET_ERROR_TYPE_WARNING,
723 "Service %s already configured as a shared service. "
724 "Ignoring service sharing request \n", ss->name);
725 GNUNET_free (ss->name);
729 GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
730 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
735 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
738 * @param client identification of the client
739 * @param message the actual message
742 handle_link_controllers (void *cls,
743 struct GNUNET_SERVER_Client *client,
744 const struct GNUNET_MessageHeader *message)
746 const struct GNUNET_TESTBED_ControllerLinkMessage *msg;
747 struct GNUNET_CONFIGURATION_Handle *cfg;
748 struct LCFContextQueue *lcfq;
753 uint32_t delegated_host_id;
754 uint32_t slave_host_id;
757 msize = ntohs (message->size);
758 if (sizeof (struct GNUNET_TESTBED_ControllerLinkMessage) >= msize)
761 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
764 msg = (const struct GNUNET_TESTBED_ControllerLinkMessage *) message;
765 delegated_host_id = ntohl (msg->delegated_host_id);
766 if (delegated_host_id == master_context->host_id)
769 LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
770 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
773 if ((delegated_host_id >= host_list_size) ||
774 (NULL == host_list[delegated_host_id]))
776 LOG (GNUNET_ERROR_TYPE_WARNING, "Delegated host not registered with us\n");
777 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
780 slave_host_id = ntohl (msg->slave_host_id);
781 if ((slave_host_id >= host_list_size) || (NULL == host_list[slave_host_id]))
783 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host not registered with us\n");
784 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
788 config_size = ntohs (msg->config_size);
789 config = GNUNET_malloc (config_size);
790 dest_size = (uLongf) config_size;
791 msize -= sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
792 if (Z_OK != uncompress ((Bytef *) config, &dest_size,
793 (const Bytef *) &msg[1], (uLong) msize))
795 GNUNET_break (0); /* Compression error */
796 GNUNET_free (config);
797 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
800 GNUNET_assert (config_size == dest_size);
801 cfg = GNUNET_CONFIGURATION_create ();
802 if (GNUNET_OK != GNUNET_CONFIGURATION_deserialize (cfg, config, config_size,
805 GNUNET_break (0); /* Configuration parsing error */
806 GNUNET_break (config);
807 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
810 GNUNET_free (config);
812 /* If delegated host and slave host are not same we have to forward
813 towards delegated host */
814 if (slave_host_id != delegated_host_id)
816 if ((slave_host_id >= route_list_size) ||
817 (NULL == (route = route_list[slave_host_id])) ||
818 (NULL == route->fcontroller))
820 LOG (GNUNET_ERROR_TYPE_WARNING, "Not route towards slave host");
821 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
824 if (slave_host_id == route->next_hop) /* Slave directly connected */
826 /* Then make slave host and delegated host same so that slave
827 will startup directly link to the delegated host */
828 slave_host_id = delegated_host_id;
830 lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
831 lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
832 lcfq->lcf->delegated_host_id = delegated_host_id;
833 lcfq->lcf->slave_host_id = slave_host_id;
834 lcfq->lcf->is_subordinate =
835 (1 == msg->is_subordinate) ? GNUNET_YES : GNUNET_NO;
836 lcfq->lcf->state = INIT;
837 lcfq->lcf->fcontroller = route->fcontroller;
838 lcfq->lcf->cfg = cfg;
839 if (NULL == lcfq_head)
841 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
842 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
843 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq);
846 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
847 GNUNET_SERVER_receive_done (client, GNUNET_OK);
850 GNUNET_SERVER_receive_done (client, GNUNET_OK);
851 /* If we are not the slave controller then we have to route the request
852 towards the slave controller */
853 if (1 == msg->is_subordinate)
855 GNUNET_break (0); /* FIXME: Implement the slave controller
858 GNUNET_CONFIGURATION_destroy (cfg);
863 * Iterator over hash map entries.
866 * @param key current key code
867 * @param value value in the hash map
868 * @return GNUNET_YES if we should continue to
873 ss_map_free_iterator (void *cls,
874 const struct GNUNET_HashCode * key, void *value)
876 struct SharedService *ss = value;
878 GNUNET_assert (GNUNET_YES ==
879 GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
880 GNUNET_free (ss->name);
887 * Task to clean up and shutdown nicely
890 * @param tc the TaskContext from scheduler
893 shutdown_task (void *cls,
894 const struct GNUNET_SCHEDULER_TaskContext *tc)
899 shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
900 GNUNET_SCHEDULER_shutdown ();
901 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
902 (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
904 GNUNET_CONTAINER_multihashmap_destroy (ss_map);
907 GNUNET_DISK_file_close (fh);
910 /* Clear host list */
911 for (host_id = 0; host_id < host_list_size; host_id++)
912 if (NULL != host_list[host_id])
913 GNUNET_TESTBED_host_destroy (host_list[host_id]);
914 GNUNET_free_non_null (host_list);
915 /* Clear route list */
916 for (route_id = 0; route_id < route_list_size; route_id++)
917 if (NULL != route_list[route_id])
919 if (NULL != route_list[route_id]->fcontroller)
920 GNUNET_TESTBED_controller_stop (route_list[route_id]->fcontroller);
921 GNUNET_free (route_list[route_id]);
923 GNUNET_free_non_null (route_list);
924 GNUNET_free_non_null (master_context);
929 * Callback for client disconnect
932 * @param client the client which has disconnected
935 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
937 if (NULL == master_context)
939 if (client == master_context->client)
941 LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
942 GNUNET_SERVER_client_drop (client);
943 /* should not be needed as we're terminated by failure to read
944 from stdin, but if stdin fails for some reason, this shouldn't
945 hurt for now --- might need to revise this later if we ever
946 decide that master connections might be temporarily down
948 GNUNET_SCHEDULER_shutdown ();
957 * @param server the initialized server
958 * @param cfg configuration to use
961 testbed_run (void *cls,
962 struct GNUNET_SERVER_Handle *server,
963 const struct GNUNET_CONFIGURATION_Handle *cfg)
965 static const struct GNUNET_SERVER_MessageHandler message_handlers[] =
967 {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT,
968 sizeof (struct GNUNET_TESTBED_InitMessage)},
969 {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST, 0},
970 {&handle_configure_shared_service, NULL,
971 GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE, 0},
972 {&handle_link_controllers, NULL,
973 GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS, 0},
977 GNUNET_SERVER_add_handlers (server,
979 GNUNET_SERVER_disconnect_notify (server,
980 &client_disconnect_cb,
982 ss_map = GNUNET_CONTAINER_multihashmap_create (5);
983 fh = GNUNET_DISK_get_handle_from_native (stdin);
986 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
991 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
999 * The starting point of execution
1001 int main (int argc, char *const *argv)
1005 GNUNET_SERVICE_run (argc,
1008 GNUNET_SERVICE_OPTION_NONE,