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;
133 * The controller process handle if we started the controller
135 struct GNUNET_TESTBED_ControllerProc *fcontroller_proc;
140 * States of LCFContext
145 * The Context has been initialized; Nothing has been done on it
150 * Delegated host has been registered at the forwarding controller
152 DELEGATED_HOST_REGISTERED,
155 * The slave host has been registred at the forwarding controller
157 SLAVE_HOST_REGISTERED,
160 * The context has been finished (may have error)
168 * Link controllers request forwarding context
175 struct GNUNET_CONFIGURATION_Handle *cfg;
178 * The handle of the controller this request has to be forwarded to
180 struct GNUNET_TESTBED_Controller *fcontroller;
183 * The host registration handle while registered hosts in this context
185 struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
188 * Should the delegated host be started by the slave host?
193 * The state of this context
195 enum LCFContextState state;
200 uint32_t delegated_host_id;
205 uint32_t slave_host_id;
211 * Structure of a queue entry in LCFContext request queue
213 struct LCFContextQueue
218 struct LCFContext *lcf;
223 struct LCFContextQueue *next;
228 struct LCFContextQueue *prev;
233 * The master context; generated with the first INIT message
235 static struct Context *master_context;
244 static struct GNUNET_DISK_FileHandle *fh;
247 * Current Transmit Handle; NULL if no notify transmit exists currently
249 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
256 * The head for the LCF queue
258 static struct LCFContextQueue *lcfq_head;
261 * The tail for the LCF queue
263 static struct LCFContextQueue *lcfq_tail;
266 * The message queue head
268 static struct MessageQueue *mq_head;
271 * The message queue tail
273 static struct MessageQueue *mq_tail;
278 static struct GNUNET_TESTBED_Host **host_list;
283 static struct Route **route_list;
286 * The hashmap of shared services
288 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
291 * The size of the host list
293 static uint32_t host_list_size;
296 * The size of the route list
298 static uint32_t route_list_size;
305 * The lcf_task handle
307 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
310 * The shutdown task handle
312 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
316 * Function called to notify a client about the connection begin ready to queue
317 * more data. "buf" will be NULL and "size" zero if the connection was closed
318 * for writing in the meantime.
321 * @param size number of bytes available in buf
322 * @param buf where the callee should write the message
323 * @return number of bytes written to buf
326 transmit_ready_notify (void *cls, size_t size, void *buf)
328 struct MessageQueue *mq_entry;
330 transmit_handle = NULL;
332 GNUNET_assert (NULL != mq_entry);
335 GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
336 size = ntohs (mq_entry->msg->size);
337 memcpy (buf, mq_entry->msg, size);
338 GNUNET_free (mq_entry->msg);
339 GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
340 GNUNET_free (mq_entry);
342 if (NULL != mq_entry)
344 GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
345 ntohs (mq_entry->msg->size),
346 GNUNET_TIME_UNIT_FOREVER_REL,
347 &transmit_ready_notify, NULL);
353 * Queues a message in send queue for sending to the service
355 * @param client the client to whom the queued message has to be sent
356 * @param msg the message to queue
359 queue_message (struct GNUNET_SERVER_Client *client,
360 struct GNUNET_MessageHeader *msg)
362 struct MessageQueue *mq_entry;
366 type = ntohs (msg->type);
367 size = ntohs (msg->size);
368 GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
369 (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
370 mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
372 mq_entry->client = client;
373 LOG_DEBUG ( "Queueing message of type %u, size %u for sending\n", type,
375 GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
376 if (NULL == transmit_handle)
378 GNUNET_SERVER_notify_transmit_ready (client, size,
379 GNUNET_TIME_UNIT_FOREVER_REL,
380 &transmit_ready_notify, NULL);
385 * Function to add a host to the current list of known hosts
387 * @param host the host to add
388 * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
392 host_list_add (struct GNUNET_TESTBED_Host *host)
396 host_id = GNUNET_TESTBED_host_get_id_ (host);
397 if (host_list_size <= host_id)
399 host_list = GNUNET_realloc (host_list,
400 sizeof (struct GNUNET_TESTBED_Host *)
402 host_list_size += (host_id + 10);
404 if (NULL != host_list[host_id])
406 LOG_DEBUG ("A host with id: %u already exists\n", host_id);
407 return GNUNET_SYSERR;
409 host_list[host_id] = host;
415 * Routes message to a host given its host_id
417 * @param host_id the id of the destination host
418 * @param msg the message to be routed
421 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
428 * The Link Controller forwarding task
430 * @param cls the LCFContext
431 * @param tc the Task context from scheduler
434 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
438 * Completion callback for host registrations while forwarding Link Controller messages
440 * @param cls the LCFContext
441 * @param emsg the error message; NULL if host registration is successful
444 lcf_proc_cc (void *cls, const char *emsg)
446 struct LCFContext *lcf = cls;
449 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
454 goto registration_error;
455 lcf->state = DELEGATED_HOST_REGISTERED;
456 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
458 case DELEGATED_HOST_REGISTERED:
460 goto registration_error;
461 lcf->state = SLAVE_HOST_REGISTERED;
462 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
465 GNUNET_assert (0); /* Shouldn't reach here */
470 LOG (GNUNET_ERROR_TYPE_WARNING,
471 "Host registration failed with message: %s\n", emsg);
472 lcf->state = FINISHED;
473 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
478 * The Link Controller forwarding task
480 * @param cls the LCFContext
481 * @param tc the Task context from scheduler
484 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
486 struct LCFContext *lcf = cls;
487 struct LCFContextQueue *lcfq;
489 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
494 GNUNET_TESTBED_is_host_registered_ (host_list[lcf->delegated_host_id],
498 GNUNET_TESTBED_register_host (lcf->fcontroller,
499 host_list[lcf->delegated_host_id],
504 lcf->state = DELEGATED_HOST_REGISTERED;
505 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
508 case DELEGATED_HOST_REGISTERED:
510 GNUNET_TESTBED_is_host_registered_ (host_list[lcf->slave_host_id],
514 GNUNET_TESTBED_register_host (lcf->fcontroller,
515 host_list[lcf->slave_host_id],
520 lcf->state = SLAVE_HOST_REGISTERED;
521 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
524 case SLAVE_HOST_REGISTERED:
525 GNUNET_TESTBED_controller_link (lcf->fcontroller,
526 host_list[lcf->delegated_host_id],
527 host_list[lcf->slave_host_id],
528 lcf->cfg, lcf->is_subordinate);
529 lcf->state = FINISHED;
532 GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg);
533 GNUNET_free (lcfq->lcf);
534 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
536 if (NULL != lcfq_head)
537 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
543 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
546 * @param client identification of the client
547 * @param message the actual message
550 handle_init (void *cls,
551 struct GNUNET_SERVER_Client *client,
552 const struct GNUNET_MessageHeader *message)
554 const struct GNUNET_TESTBED_InitMessage *msg;
555 struct GNUNET_TESTBED_Host *host;
557 if (NULL != master_context)
560 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
563 msg = (const struct GNUNET_TESTBED_InitMessage *) message;
564 master_context = GNUNET_malloc (sizeof (struct Context));
565 master_context->client = client;
566 master_context->host_id = ntohl (msg->host_id);
567 host = GNUNET_TESTBED_host_create_with_id (master_context->host_id,
569 host_list_add (host);
570 master_context->event_mask = GNUNET_ntohll (msg->event_mask);
571 GNUNET_SERVER_client_keep (client);
572 LOG_DEBUG ("Created master context with host ID: %u\n",
573 master_context->host_id);
574 GNUNET_SERVER_receive_done (client, GNUNET_OK);
579 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
582 * @param client identification of the client
583 * @param message the actual message
586 handle_add_host (void *cls,
587 struct GNUNET_SERVER_Client *client,
588 const struct GNUNET_MessageHeader *message)
590 struct GNUNET_TESTBED_Host *host;
591 const struct GNUNET_TESTBED_AddHostMessage *msg;
592 struct GNUNET_TESTBED_HostConfirmedMessage *reply;
597 uint16_t username_length;
598 uint16_t hostname_length;
601 msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
602 username_length = ntohs (msg->user_name_length);
603 username_length = (0 == username_length) ? 0 : username_length + 1;
604 username = (char *) &(msg[1]);
605 hostname = username + username_length;
606 if (ntohs (message->size) <=
607 (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length))
610 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
613 hostname_length = ntohs (message->size)
614 - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
615 if (strlen (hostname) != hostname_length)
618 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
621 host_id = ntohl (msg->host_id);
622 LOG_DEBUG ("Received ADDHOST message\n");
623 LOG_DEBUG ("-------host id: %u\n", host_id);
624 if (NULL != hostname) LOG_DEBUG ("-------hostname: %s\n", hostname);
625 if (NULL != username) LOG_DEBUG ("-------username: %s\n", username);
626 LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
627 host = GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
628 ntohs (msg->ssh_port));
629 GNUNET_SERVER_receive_done (client, GNUNET_OK);
630 reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
631 if (GNUNET_OK != host_list_add (host))
633 /* We are unable to add a host */
634 emsg = "A host exists with given host-id";
635 LOG_DEBUG ("%s: %u", emsg, host_id);
636 GNUNET_TESTBED_host_destroy (host);
637 reply_size += strlen (emsg) + 1;
638 reply = GNUNET_malloc (reply_size);
639 memcpy (&reply[1], emsg, strlen (emsg) + 1);
642 reply = GNUNET_malloc (reply_size);
643 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM);
644 reply->header.size = htons (reply_size);
645 reply->host_id = htonl (host_id);
646 queue_message (client, (struct GNUNET_MessageHeader *) reply);
651 * Iterator over hash map entries.
654 * @param key current key code
655 * @param value value in the hash map
656 * @return GNUNET_YES if we should continue to
660 int ss_exists_iterator (void *cls,
661 const struct GNUNET_HashCode * key,
664 struct SharedService *queried_ss = cls;
665 struct SharedService *ss = value;
667 if (0 == strcmp (ss->name, queried_ss->name))
674 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
677 * @param client identification of the client
678 * @param message the actual message
681 handle_configure_shared_service (void *cls,
682 struct GNUNET_SERVER_Client *client,
683 const struct GNUNET_MessageHeader *message)
685 const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
686 struct SharedService *ss;
688 struct GNUNET_HashCode hash;
690 uint16_t service_name_size;
692 msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
693 msg_size = ntohs (message->size);
694 if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
697 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
700 service_name_size = msg_size -
701 sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
702 service_name = (char *) &msg[1];
703 if ('\0' != service_name[service_name_size - 1])
706 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
709 LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
710 service_name, ntohl (msg->num_peers));
711 if (ntohl (msg->host_id) != master_context->host_id)
713 route_message (ntohl (msg->host_id), message);
714 GNUNET_SERVER_receive_done (client, GNUNET_OK);
717 GNUNET_SERVER_receive_done (client, GNUNET_OK);
718 ss = GNUNET_malloc (sizeof (struct SharedService));
719 ss->name = strdup (service_name);
720 ss->num_shared = ntohl (msg->num_peers);
721 GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
723 GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
724 &ss_exists_iterator, ss))
726 LOG (GNUNET_ERROR_TYPE_WARNING,
727 "Service %s already configured as a shared service. "
728 "Ignoring service sharing request \n", ss->name);
729 GNUNET_free (ss->name);
733 GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
734 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
739 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
742 * @param client identification of the client
743 * @param message the actual message
746 handle_link_controllers (void *cls,
747 struct GNUNET_SERVER_Client *client,
748 const struct GNUNET_MessageHeader *message)
750 const struct GNUNET_TESTBED_ControllerLinkMessage *msg;
751 struct GNUNET_CONFIGURATION_Handle *cfg;
752 struct LCFContextQueue *lcfq;
757 uint32_t delegated_host_id;
758 uint32_t slave_host_id;
761 msize = ntohs (message->size);
762 if (sizeof (struct GNUNET_TESTBED_ControllerLinkMessage) >= msize)
765 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
768 msg = (const struct GNUNET_TESTBED_ControllerLinkMessage *) message;
769 delegated_host_id = ntohl (msg->delegated_host_id);
770 if (delegated_host_id == master_context->host_id)
773 LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
774 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
777 if ((delegated_host_id >= host_list_size) ||
778 (NULL == host_list[delegated_host_id]))
780 LOG (GNUNET_ERROR_TYPE_WARNING, "Delegated host not registered with us\n");
781 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
784 slave_host_id = ntohl (msg->slave_host_id);
785 if ((slave_host_id >= host_list_size) || (NULL == host_list[slave_host_id]))
787 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host not registered with us\n");
788 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
792 config_size = ntohs (msg->config_size);
793 config = GNUNET_malloc (config_size);
794 dest_size = (uLongf) config_size;
795 msize -= sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
796 if (Z_OK != uncompress ((Bytef *) config, &dest_size,
797 (const Bytef *) &msg[1], (uLong) msize))
799 GNUNET_break (0); /* Compression error */
800 GNUNET_free (config);
801 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
804 GNUNET_assert (config_size == dest_size);
805 cfg = GNUNET_CONFIGURATION_create (); /* Free here or in lcfcontext */
806 if (GNUNET_OK != GNUNET_CONFIGURATION_deserialize (cfg, config, config_size,
809 GNUNET_break (0); /* Configuration parsing error */
810 GNUNET_break (config);
811 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
814 GNUNET_free (config);
816 /* If delegated host and slave host are not same we have to forward
817 towards delegated host */
818 if (slave_host_id != delegated_host_id)
820 if ((slave_host_id >= route_list_size) ||
821 (NULL == (route = route_list[slave_host_id])) ||
822 (NULL == route->fcontroller))
824 LOG (GNUNET_ERROR_TYPE_WARNING, "Not route towards slave host");
825 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
828 if (slave_host_id == route->next_hop) /* Slave directly connected */
830 /* Then make slave host and delegated host same so that slave
831 will startup directly link to the delegated host */
832 slave_host_id = delegated_host_id;
834 lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
835 lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
836 lcfq->lcf->delegated_host_id = delegated_host_id;
837 lcfq->lcf->slave_host_id = slave_host_id;
838 lcfq->lcf->is_subordinate =
839 (1 == msg->is_subordinate) ? GNUNET_YES : GNUNET_NO;
840 lcfq->lcf->state = INIT;
841 lcfq->lcf->fcontroller = route->fcontroller;
842 lcfq->lcf->cfg = cfg;
843 if (NULL == lcfq_head)
845 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
846 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
847 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq);
850 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
851 GNUNET_SERVER_receive_done (client, GNUNET_OK);
858 GNUNET_SERVER_receive_done (client, GNUNET_OK);
859 /* If we are not the slave controller then we have to route the request
860 towards the slave controller */
861 if (1 == msg->is_subordinate)
863 GNUNET_break (0); /* FIXME: Implement the slave controller
866 GNUNET_CONFIGURATION_destroy (cfg);
871 * Iterator over hash map entries.
874 * @param key current key code
875 * @param value value in the hash map
876 * @return GNUNET_YES if we should continue to
881 ss_map_free_iterator (void *cls,
882 const struct GNUNET_HashCode * key, void *value)
884 struct SharedService *ss = value;
886 GNUNET_assert (GNUNET_YES ==
887 GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
888 GNUNET_free (ss->name);
895 * Task to clean up and shutdown nicely
898 * @param tc the TaskContext from scheduler
901 shutdown_task (void *cls,
902 const struct GNUNET_SCHEDULER_TaskContext *tc)
904 struct LCFContextQueue *lcfq;
908 shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
909 GNUNET_SCHEDULER_shutdown ();
910 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
911 (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
913 GNUNET_CONTAINER_multihashmap_destroy (ss_map);
916 GNUNET_DISK_file_close (fh);
919 if (NULL != lcfq_head)
921 if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
923 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
924 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
926 if (NULL != lcfq_head->lcf->rhandle)
927 GNUNET_TESTBED_cancel_registration (lcfq_head->lcf->rhandle);
929 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
930 for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
932 GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg);
933 GNUNET_free (lcfq->lcf);
934 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
937 /* Clear host list */
938 for (host_id = 0; host_id < host_list_size; host_id++)
939 if (NULL != host_list[host_id])
940 GNUNET_TESTBED_host_destroy (host_list[host_id]);
941 GNUNET_free_non_null (host_list);
942 /* Clear route list */
943 for (route_id = 0; route_id < route_list_size; route_id++)
944 if (NULL != route_list[route_id])
946 if (NULL != route_list[route_id]->fcontroller)
947 GNUNET_TESTBED_controller_disconnect (route_list[route_id]->fcontroller);
948 if (NULL != route_list[route_id]->fcontroller_proc)
949 GNUNET_TESTBED_controller_stop (route_list[route_id]->fcontroller_proc);
950 GNUNET_free (route_list[route_id]);
952 GNUNET_free_non_null (route_list);
953 GNUNET_free_non_null (master_context);
958 * Callback for client disconnect
961 * @param client the client which has disconnected
964 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
966 if (NULL == master_context)
968 if (client == master_context->client)
970 LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
971 GNUNET_SERVER_client_drop (client);
972 /* should not be needed as we're terminated by failure to read
973 from stdin, but if stdin fails for some reason, this shouldn't
974 hurt for now --- might need to revise this later if we ever
975 decide that master connections might be temporarily down
977 GNUNET_SCHEDULER_shutdown ();
986 * @param server the initialized server
987 * @param cfg configuration to use
990 testbed_run (void *cls,
991 struct GNUNET_SERVER_Handle *server,
992 const struct GNUNET_CONFIGURATION_Handle *cfg)
994 static const struct GNUNET_SERVER_MessageHandler message_handlers[] =
996 {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT,
997 sizeof (struct GNUNET_TESTBED_InitMessage)},
998 {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST, 0},
999 {&handle_configure_shared_service, NULL,
1000 GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE, 0},
1001 {&handle_link_controllers, NULL,
1002 GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS, 0},
1006 GNUNET_SERVER_add_handlers (server,
1008 GNUNET_SERVER_disconnect_notify (server,
1009 &client_disconnect_cb,
1011 ss_map = GNUNET_CONTAINER_multihashmap_create (5);
1012 fh = GNUNET_DISK_get_handle_from_native (stdin);
1015 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1020 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1028 * The starting point of execution
1030 int main (int argc, char *const *argv)
1034 GNUNET_SERVICE_run (argc,
1037 GNUNET_SERVICE_OPTION_NONE,