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"
30 #include "gnunet_transport_service.h"
31 #include "gnunet_core_service.h"
32 #include "gnunet_hello_lib.h"
35 #include "gnunet_testbed_service.h"
37 #include "testbed_api.h"
38 #include "testbed_api_hosts.h"
39 #include "gnunet_testing_lib-new.h"
44 #define LOG(kind,...) \
45 GNUNET_log (kind, __VA_ARGS__)
50 #define LOG_DEBUG(...) \
51 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
54 * By how much should the arrays lists grow
56 #define LIST_GROW_STEP 10
59 * Default timeout for operations which may take some time
61 #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
64 * The main context information associated with the client which started us
69 * The client handle associated with this context
71 struct GNUNET_SERVER_Client *client;
74 * The network address of the master controller
79 * The TESTING system handle for starting peers locally
81 struct GNUNET_TESTING_System *system;
84 * Event mask of event to be responded in this context
89 * Our host id according to this context
96 * The message queue for sending messages to clients
101 * The message to be sent
103 struct GNUNET_MessageHeader *msg;
106 * The client to send the message to
108 struct GNUNET_SERVER_Client *client;
111 * next pointer for DLL
113 struct MessageQueue *next;
116 * prev pointer for DLL
118 struct MessageQueue *prev;
123 * The structure for identifying a shared service
128 * The name of the shared service
133 * Number of shared peers per instance of the shared service
138 * Number of peers currently sharing the service
140 uint32_t num_sharing;
155 * The destination host is reachable thru
162 * Context information used while linking controllers
164 struct LinkControllersContext;
168 * Structure representing a connected(directly-linked) controller
173 * The controller process handle if we had started the controller
175 struct GNUNET_TESTBED_ControllerProc *controller_proc;
178 * The controller handle
180 struct GNUNET_TESTBED_Controller *controller;
183 * The configuration of the slave. Cannot be NULL
185 struct GNUNET_CONFIGURATION_Handle *cfg;
188 * handle to lcc which is associated with this slave startup. Should be set to
189 * NULL when the slave has successfully started up
191 struct LinkControllersContext *lcc;
194 * The id of the host this controller is running on
201 * States of LCFContext
206 * The Context has been initialized; Nothing has been done on it
211 * Delegated host has been registered at the forwarding controller
213 DELEGATED_HOST_REGISTERED,
216 * The slave host has been registred at the forwarding controller
218 SLAVE_HOST_REGISTERED,
221 * The context has been finished (may have error)
228 * Link controllers request forwarding context
233 * The gateway which will pass the link message to delegated host
235 struct Slave *gateway;
238 * The controller link message that has to be forwarded to
240 struct GNUNET_TESTBED_ControllerLinkMessage *msg;
243 * The client which has asked to perform this operation
245 struct GNUNET_SERVER_Client *client;
248 * The host registration handle while registered hosts in this context
250 struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
253 * The id of the operation which created this context
255 uint64_t operation_id;
258 * The state of this context
260 enum LCFContextState state;
265 uint32_t delegated_host_id;
270 uint32_t slave_host_id;
276 * Structure of a queue entry in LCFContext request queue
278 struct LCFContextQueue
283 struct LCFContext *lcf;
288 struct LCFContextQueue *next;
293 struct LCFContextQueue *prev;
307 * The peer handle from testing API
309 struct GNUNET_TESTING_Peer *peer;
312 * The modified (by GNUNET_TESTING_peer_configure) configuration this
313 * peer is configured with
315 struct GNUNET_CONFIGURATION_Handle *cfg;
318 * Is the peer running
327 * The controller this peer is started through
329 struct GNUNET_TESTBED_Controller *controller;
336 * Is this peer locally created?
341 * Our local reference id for this peer
349 * Context information for connecting 2 peers in overlay
351 struct OverlayConnectContext
354 * The client which has requested for overlay connection
356 struct GNUNET_SERVER_Client *client;
359 * the peer which has to connect to the other peer
364 * Transport handle of the first peer to get its HELLO
366 struct GNUNET_TRANSPORT_Handle *p1th;
369 * Transport handle of other peer to offer first peer's HELLO
371 struct GNUNET_TRANSPORT_Handle *p2th;
374 * Core handles of the first peer; used to notify when second peer connects to it
376 struct GNUNET_CORE_Handle *ch;
379 * HELLO of the other peer
381 struct GNUNET_MessageHeader *hello;
384 * Get hello handle to acquire HELLO of first peer
386 struct GNUNET_TRANSPORT_GetHelloHandle *ghh;
389 * The error message we send if this overlay connect operation has timed out
394 * Operation context for suboperations
396 struct OperationContext *opc;
399 * Controller of peer 2; NULL if the peer is local
401 struct GNUNET_TESTBED_Controller *peer2_controller;
404 * The peer identity of the first peer
406 struct GNUNET_PeerIdentity peer_identity;
409 * The peer identity of the other peer
411 struct GNUNET_PeerIdentity other_peer_identity;
414 * The id of the operation responsible for creating this context
419 * The id of the task for sending HELLO of peer 2 to peer 1 and ask peer 1 to
422 GNUNET_SCHEDULER_TaskIdentifier send_hello_task;
425 * The id of the overlay connect timeout task
427 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
437 uint32_t other_peer_id;
440 * Number of times we tried to send hello; used to increase delay in offering
448 * Context information for RequestOverlayConnect
449 * operations. RequestOverlayConnect is used when peers A, B reside on different
450 * hosts and the host controller for peer B is asked by the host controller of
451 * peer A to make peer B connect to peer A
453 struct RequestOverlayConnectContext
456 * The transport handle of peer B
458 struct GNUNET_TRANSPORT_Handle *th;
463 struct GNUNET_MessageHeader *hello;
466 * The peer identity of peer A
468 struct GNUNET_PeerIdentity a_id;
471 * Task for offering HELLO of A to B and doing try_connect
473 GNUNET_SCHEDULER_TaskIdentifier attempt_connect_task_id;
476 * Task to timeout RequestOverlayConnect
478 GNUNET_SCHEDULER_TaskIdentifier timeout_rocc_task_id;
481 * Number of times we tried to send hello; used to increase delay in offering
490 * Context information for operations forwarded to subcontrollers
492 struct ForwardedOperationContext
495 * The generated operation context
497 struct OperationContext *opc;
500 * The client to which we have to reply
502 struct GNUNET_SERVER_Client *client;
510 * Task ID for the timeout task
512 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
515 * The id of the operation that has been forwarded
517 uint64_t operation_id;
523 * Context information used while linking controllers
525 struct LinkControllersContext
528 * The client which initiated the link controller operation
530 struct GNUNET_SERVER_Client *client;
533 * The ID of the operation
535 uint64_t operation_id;
542 * The master context; generated with the first INIT message
544 static struct Context *master_context;
547 * Our hostname; we give this to all the peers we start
549 static char *hostname;
556 * Current Transmit Handle; NULL if no notify transmit exists currently
558 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
565 * The head for the LCF queue
567 static struct LCFContextQueue *lcfq_head;
570 * The tail for the LCF queue
572 static struct LCFContextQueue *lcfq_tail;
575 * The message queue head
577 static struct MessageQueue *mq_head;
580 * The message queue tail
582 static struct MessageQueue *mq_tail;
587 static struct GNUNET_TESTBED_Host **host_list;
592 static struct Route **route_list;
595 * A list of directly linked neighbours
597 static struct Slave **slave_list;
600 * A list of peers we know about
602 static struct Peer **peer_list;
605 * The hashmap of shared services
607 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
610 * The size of the host list
612 static uint32_t host_list_size;
615 * The size of the route list
617 static uint32_t route_list_size;
620 * The size of directly linked neighbours list
622 static uint32_t slave_list_size;
625 * The size of the peer list
627 static uint32_t peer_list_size;
634 * The lcf_task handle
636 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
639 * The shutdown task handle
641 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
645 * Function called to notify a client about the connection begin ready to queue
646 * more data. "buf" will be NULL and "size" zero if the connection was closed
647 * for writing in the meantime.
650 * @param size number of bytes available in buf
651 * @param buf where the callee should write the message
652 * @return number of bytes written to buf
655 transmit_ready_notify (void *cls, size_t size, void *buf)
657 struct MessageQueue *mq_entry;
659 transmit_handle = NULL;
661 GNUNET_assert (NULL != mq_entry);
664 GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
665 size = ntohs (mq_entry->msg->size);
666 memcpy (buf, mq_entry->msg, size);
667 GNUNET_free (mq_entry->msg);
668 GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
669 GNUNET_free (mq_entry);
671 if (NULL != mq_entry)
673 GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
674 ntohs (mq_entry->msg->size),
675 GNUNET_TIME_UNIT_FOREVER_REL,
676 &transmit_ready_notify, NULL);
682 * Queues a message in send queue for sending to the service
684 * @param client the client to whom the queued message has to be sent
685 * @param msg the message to queue
688 queue_message (struct GNUNET_SERVER_Client *client,
689 struct GNUNET_MessageHeader *msg)
691 struct MessageQueue *mq_entry;
695 type = ntohs (msg->type);
696 size = ntohs (msg->size);
697 GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
698 (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
699 mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
701 mq_entry->client = client;
702 LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
704 GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
705 if (NULL == transmit_handle)
707 GNUNET_SERVER_notify_transmit_ready (client, size,
708 GNUNET_TIME_UNIT_FOREVER_REL,
709 &transmit_ready_notify, NULL);
714 * Similar to GNUNET_realloc; however clears tail part of newly allocated memory
716 * @param ptr the memory block to realloc
717 * @param size the size of ptr
718 * @param new_size the size to which ptr has to be realloc'ed
719 * @return the newly reallocated memory block
722 TESTBED_realloc (void *ptr, size_t size, size_t new_size)
724 ptr = GNUNET_realloc (ptr, new_size);
726 (void) memset (ptr + size, 0, new_size - size);
732 * Function to add a host to the current list of known hosts
734 * @param host the host to add
735 * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
739 host_list_add (struct GNUNET_TESTBED_Host *host)
744 host_id = GNUNET_TESTBED_host_get_id_ (host);
745 orig_size = host_list_size;
746 if (host_list_size <= host_id)
748 while (host_list_size <= host_id)
749 host_list_size += LIST_GROW_STEP;
751 TESTBED_realloc (host_list,
752 sizeof (struct GNUNET_TESTBED_Host *) * orig_size,
753 sizeof (struct GNUNET_TESTBED_Host *)
756 if (NULL != host_list[host_id])
758 LOG_DEBUG ("A host with id: %u already exists\n", host_id);
759 return GNUNET_SYSERR;
761 host_list[host_id] = host;
767 * Adds a route to the route list
769 * @param route the route to add
772 route_list_add (struct Route *route)
776 orig_size = route_list_size;
777 if (route->dest >= route_list_size)
779 while (route->dest >= route_list_size)
780 route_list_size += LIST_GROW_STEP;
782 TESTBED_realloc (route_list,
783 sizeof (struct Route *) * orig_size,
784 sizeof (struct Route *) * route_list_size);
786 GNUNET_assert (NULL == route_list[route->dest]);
787 route_list[route->dest] = route;
792 * Adds a slave to the slave array
794 * @param slave the slave controller to add
797 slave_list_add (struct Slave *slave)
799 if (slave->host_id >= slave_list_size)
802 TESTBED_realloc (slave_list, sizeof (struct Slave *) * slave_list_size,
803 sizeof (struct Slave *) * (slave_list_size +
805 slave_list_size += LIST_GROW_STEP;
807 GNUNET_assert (NULL == slave_list[slave->host_id]);
808 slave_list[slave->host_id] = slave;
813 * Adds a peer to the peer array
815 * @param peer the peer to add
818 peer_list_add (struct Peer *peer)
822 orig_size = peer_list_size;
823 if (peer->id >= peer_list_size)
825 while (peer->id >= peer_list_size)
826 peer_list_size += LIST_GROW_STEP;
828 TESTBED_realloc (peer_list, sizeof (struct Peer *) * orig_size,
829 sizeof (struct Peer *) * peer_list_size);
831 GNUNET_assert (NULL == peer_list[peer->id]);
832 peer_list[peer->id] = peer;
837 * Removes a the give peer from the peer array
839 * @param peer the peer to be removed
842 peer_list_remove (struct Peer *peer)
847 peer_list[peer->id] = NULL;
848 orig_size = peer_list_size;
849 while (peer_list_size >= LIST_GROW_STEP)
851 for (id = peer_list_size - 1;
852 (id >= peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX); id--)
853 if (NULL != peer_list[id])
855 if (id != ((peer_list_size - LIST_GROW_STEP) - 1))
857 peer_list_size -= LIST_GROW_STEP;
859 if (orig_size == peer_list_size)
862 GNUNET_realloc (peer_list, sizeof (struct Peer *) * peer_list_size);
867 * Finds the route with directly connected host as destination through which
868 * the destination host can be reached
870 * @param host_id the id of the destination host
871 * @return the route with directly connected destination host; NULL if no route
874 static struct Route *
875 find_dest_route (uint32_t host_id)
879 while (NULL != (route = route_list[host_id]))
881 if (route->thru == master_context->host_id)
883 host_id = route->thru;
890 * Routes message to a host given its host_id
892 * @param host_id the id of the destination host
893 * @param msg the message to be routed
896 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
903 * Send operation failure message to client
905 * @param client the client to which the failure message has to be sent to
906 * @param operation_id the id of the failed operation
907 * @param emsg the error message; can be NULL
910 send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
911 uint64_t operation_id, const char *emsg)
913 struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
917 msize = sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
918 emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
920 msg = GNUNET_malloc (msize);
921 msg->header.size = htons (msize);
922 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OPERATIONFAILEVENT);
923 msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
924 msg->operation_id = GNUNET_htonll (operation_id);
926 memcpy (&msg[1], emsg, emsg_len);
927 queue_message (client, &msg->header);
932 * Function to send generic operation success message to given client
934 * @param client the client to send the message to
935 * @param operation_id the id of the operation which was successful
938 send_operation_success_msg (struct GNUNET_SERVER_Client *client,
939 uint64_t operation_id)
941 struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
944 msize = sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage);
945 msg = GNUNET_malloc (msize);
946 msg->header.size = htons (msize);
947 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GENERICOPSUCCESS);
948 msg->operation_id = GNUNET_htonll (operation_id);
949 msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
950 queue_message (client, &msg->header);
955 * The Link Controller forwarding task
957 * @param cls the LCFContext
958 * @param tc the Task context from scheduler
961 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
965 * Completion callback for host registrations while forwarding Link Controller messages
967 * @param cls the LCFContext
968 * @param emsg the error message; NULL if host registration is successful
971 lcf_proc_cc (void *cls, const char *emsg)
973 struct LCFContext *lcf = cls;
976 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
981 goto registration_error;
982 lcf->state = DELEGATED_HOST_REGISTERED;
983 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
985 case DELEGATED_HOST_REGISTERED:
987 goto registration_error;
988 lcf->state = SLAVE_HOST_REGISTERED;
989 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
992 GNUNET_assert (0); /* Shouldn't reach here */
997 LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
999 lcf->state = FINISHED;
1000 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1005 * Callback to be called when forwarded link controllers operation is
1006 * successfull. We have to relay the reply msg back to the client
1008 * @param cls ForwardedOperationContext
1009 * @param msg the peer create success message
1012 forwarded_operation_reply_relay (void *cls,
1013 const struct GNUNET_MessageHeader *msg)
1015 struct ForwardedOperationContext *fopc = cls;
1016 struct GNUNET_MessageHeader *dup_msg;
1019 msize = ntohs (msg->size);
1020 LOG_DEBUG ("Relaying message with type: %u, size: %u\n", ntohs (msg->type),
1022 dup_msg = GNUNET_malloc (msize);
1023 (void) memcpy (dup_msg, msg, msize);
1024 queue_message (fopc->client, dup_msg);
1025 GNUNET_SERVER_client_drop (fopc->client);
1026 GNUNET_SCHEDULER_cancel (fopc->timeout_task);
1032 * Task to free resources when forwarded link controllers has been timedout
1034 * @param cls the ForwardedOperationContext
1035 * @param tc the task context from scheduler
1038 forwarded_operation_timeout (void *cls,
1039 const struct GNUNET_SCHEDULER_TaskContext *tc)
1041 struct ForwardedOperationContext *fopc = cls;
1043 GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
1044 send_operation_fail_msg (fopc->client, fopc->operation_id, "Timeout");
1045 GNUNET_SERVER_client_drop (fopc->client);
1051 * The Link Controller forwarding task
1053 * @param cls the LCFContext
1054 * @param tc the Task context from scheduler
1057 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1059 struct LCFContext *lcf = cls;
1060 struct LCFContextQueue *lcfq;
1061 struct ForwardedOperationContext *fopc;
1063 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1068 GNUNET_TESTBED_is_host_registered_ (host_list[lcf->delegated_host_id],
1069 lcf->gateway->controller))
1072 GNUNET_TESTBED_register_host (lcf->gateway->controller,
1073 host_list[lcf->delegated_host_id],
1078 lcf->state = DELEGATED_HOST_REGISTERED;
1079 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1082 case DELEGATED_HOST_REGISTERED:
1084 GNUNET_TESTBED_is_host_registered_ (host_list[lcf->slave_host_id],
1085 lcf->gateway->controller))
1088 GNUNET_TESTBED_register_host (lcf->gateway->controller,
1089 host_list[lcf->slave_host_id],
1094 lcf->state = SLAVE_HOST_REGISTERED;
1095 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1098 case SLAVE_HOST_REGISTERED:
1099 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1100 fopc->client = lcf->client;
1101 fopc->operation_id = lcf->operation_id;
1103 GNUNET_TESTBED_forward_operation_msg_ (lcf->gateway->controller,
1106 &forwarded_operation_reply_relay,
1108 fopc->timeout_task =
1109 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
1111 lcf->state = FINISHED;
1112 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1116 GNUNET_assert (lcfq->lcf == lcf);
1117 GNUNET_free (lcf->msg);
1119 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
1121 if (NULL != lcfq_head)
1123 GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
1129 * Callback for event from slave controllers
1131 * @param cls struct Slave *
1132 * @param event information about the event
1135 slave_event_callback (void *cls,
1136 const struct GNUNET_TESTBED_EventInformation *event)
1143 * Callback to signal successfull startup of the controller process
1145 * @param cls the handle to the slave whose status is to be found here
1146 * @param cfg the configuration with which the controller has been started;
1147 * NULL if status is not GNUNET_OK
1148 * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
1149 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
1152 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
1155 struct Slave *slave = cls;
1156 struct LinkControllersContext *lcc;
1159 if (GNUNET_SYSERR == status)
1161 slave->controller_proc = NULL;
1162 slave_list[slave->host_id] = NULL;
1163 if (NULL != slave->cfg)
1164 GNUNET_CONFIGURATION_destroy (slave->cfg);
1165 GNUNET_free (slave);
1167 LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
1168 GNUNET_SCHEDULER_shutdown (); /* We too shutdown */
1172 GNUNET_TESTBED_controller_connect (cfg, host_list[slave->host_id],
1173 master_context->event_mask,
1174 &slave_event_callback, slave);
1175 if (NULL != slave->controller)
1177 send_operation_success_msg (lcc->client, lcc->operation_id);
1178 slave->cfg = GNUNET_CONFIGURATION_dup (cfg);
1182 send_operation_fail_msg (lcc->client, lcc->operation_id,
1183 "Could not connect to delegated controller");
1184 GNUNET_TESTBED_controller_stop (slave->controller_proc);
1185 slave_list[slave->host_id] = NULL;
1186 GNUNET_free (slave);
1193 if (NULL != lcc->client)
1195 GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
1196 GNUNET_SERVER_client_drop (lcc->client);
1207 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
1210 * @param client identification of the client
1211 * @param message the actual message
1214 handle_init (void *cls, struct GNUNET_SERVER_Client *client,
1215 const struct GNUNET_MessageHeader *message)
1217 const struct GNUNET_TESTBED_InitMessage *msg;
1218 struct GNUNET_TESTBED_Host *host;
1219 const char *controller_hostname;
1222 if (NULL != master_context)
1224 LOG_DEBUG ("We are being connected to laterally\n");
1225 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1228 msg = (const struct GNUNET_TESTBED_InitMessage *) message;
1229 msize = ntohs (message->size);
1230 if (msize <= sizeof (struct GNUNET_TESTBED_InitMessage))
1233 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1236 msize -= sizeof (struct GNUNET_TESTBED_InitMessage);
1237 controller_hostname = (const char *) &msg[1];
1238 if ('\0' != controller_hostname[msize - 1])
1241 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1244 master_context = GNUNET_malloc (sizeof (struct Context));
1245 master_context->client = client;
1246 master_context->host_id = ntohl (msg->host_id);
1247 master_context->master_ip = GNUNET_strdup (controller_hostname);
1248 LOG_DEBUG ("Master Controller IP: %s\n", master_context->master_ip);
1249 master_context->system =
1250 GNUNET_TESTING_system_create ("testbed", master_context->master_ip, hostname);
1252 GNUNET_TESTBED_host_create_with_id (master_context->host_id, NULL, NULL,
1254 host_list_add (host);
1255 master_context->event_mask = GNUNET_ntohll (msg->event_mask);
1256 GNUNET_SERVER_client_keep (client);
1257 LOG_DEBUG ("Created master context with host ID: %u\n",
1258 master_context->host_id);
1259 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1264 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1267 * @param client identification of the client
1268 * @param message the actual message
1271 handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
1272 const struct GNUNET_MessageHeader *message)
1274 struct GNUNET_TESTBED_Host *host;
1275 const struct GNUNET_TESTBED_AddHostMessage *msg;
1276 struct GNUNET_TESTBED_HostConfirmedMessage *reply;
1281 uint16_t username_length;
1282 uint16_t hostname_length;
1283 uint16_t reply_size;
1286 msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
1287 msize = ntohs (msg->header.size);
1288 username = (char *) &(msg[1]);
1289 username_length = ntohs (msg->user_name_length);
1290 GNUNET_assert (msize > (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length + 1)); /* msg must contain hostname */
1291 if (0 != username_length)
1292 GNUNET_assert ('\0' == username[username_length]);
1293 username_length = (0 == username_length) ? 0 : username_length + 1;
1294 hostname = username + username_length;
1296 msize - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
1297 GNUNET_assert ('\0' == hostname[hostname_length - 1]);
1298 GNUNET_assert (strlen (hostname) == hostname_length - 1);
1299 host_id = ntohl (msg->host_id);
1300 LOG_DEBUG ("Received ADDHOST message\n");
1301 LOG_DEBUG ("-------host id: %u\n", host_id);
1302 LOG_DEBUG ("-------hostname: %s\n", hostname);
1303 if (0 != username_length)
1304 LOG_DEBUG ("-------username: %s\n", username);
1307 LOG_DEBUG ("-------username: NULL\n");
1310 LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
1312 GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
1313 ntohs (msg->ssh_port));
1314 GNUNET_assert (NULL != host);
1315 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1316 reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
1317 if (GNUNET_OK != host_list_add (host))
1319 /* We are unable to add a host */
1320 emsg = "A host exists with given host-id";
1321 LOG_DEBUG ("%s: %u", emsg, host_id);
1322 GNUNET_TESTBED_host_destroy (host);
1323 reply_size += strlen (emsg) + 1;
1324 reply = GNUNET_malloc (reply_size);
1325 memcpy (&reply[1], emsg, strlen (emsg) + 1);
1328 reply = GNUNET_malloc (reply_size);
1329 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM);
1330 reply->header.size = htons (reply_size);
1331 reply->host_id = htonl (host_id);
1332 queue_message (client, &reply->header);
1337 * Iterator over hash map entries.
1339 * @param cls closure
1340 * @param key current key code
1341 * @param value value in the hash map
1342 * @return GNUNET_YES if we should continue to
1347 ss_exists_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
1349 struct SharedService *queried_ss = cls;
1350 struct SharedService *ss = value;
1352 if (0 == strcmp (ss->name, queried_ss->name))
1360 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1363 * @param client identification of the client
1364 * @param message the actual message
1367 handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client,
1368 const struct GNUNET_MessageHeader *message)
1370 const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1371 struct SharedService *ss;
1373 struct GNUNET_HashCode hash;
1375 uint16_t service_name_size;
1377 msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
1378 msg_size = ntohs (message->size);
1379 if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
1382 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1386 msg_size - sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
1387 service_name = (char *) &msg[1];
1388 if ('\0' != service_name[service_name_size - 1])
1391 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1394 LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
1395 service_name, ntohl (msg->num_peers));
1396 if (ntohl (msg->host_id) != master_context->host_id)
1398 route_message (ntohl (msg->host_id), message);
1399 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1402 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1403 ss = GNUNET_malloc (sizeof (struct SharedService));
1404 ss->name = strdup (service_name);
1405 ss->num_shared = ntohl (msg->num_peers);
1406 GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
1407 if (GNUNET_SYSERR ==
1408 GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
1409 &ss_exists_iterator, ss))
1411 LOG (GNUNET_ERROR_TYPE_WARNING,
1412 "Service %s already configured as a shared service. "
1413 "Ignoring service sharing request \n", ss->name);
1414 GNUNET_free (ss->name);
1418 GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
1419 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1424 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1427 * @param client identification of the client
1428 * @param message the actual message
1431 handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
1432 const struct GNUNET_MessageHeader *message)
1434 const struct GNUNET_TESTBED_ControllerLinkMessage *msg;
1435 struct GNUNET_CONFIGURATION_Handle *cfg;
1436 struct LCFContextQueue *lcfq;
1437 struct Route *route;
1438 struct Route *new_route;
1442 uint32_t delegated_host_id;
1443 uint32_t slave_host_id;
1446 if (NULL == master_context)
1449 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1452 msize = ntohs (message->size);
1453 if (sizeof (struct GNUNET_TESTBED_ControllerLinkMessage) >= msize)
1456 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1459 msg = (const struct GNUNET_TESTBED_ControllerLinkMessage *) message;
1460 delegated_host_id = ntohl (msg->delegated_host_id);
1461 if (delegated_host_id == master_context->host_id)
1464 LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
1465 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1468 if ((delegated_host_id >= host_list_size) ||
1469 (NULL == host_list[delegated_host_id]))
1471 LOG (GNUNET_ERROR_TYPE_WARNING,
1472 "Delegated host %u not registered with us\n", delegated_host_id);
1473 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1476 slave_host_id = ntohl (msg->slave_host_id);
1477 if ((slave_host_id >= host_list_size) || (NULL == host_list[slave_host_id]))
1479 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host not registered with us\n");
1480 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1483 if (slave_host_id == delegated_host_id)
1485 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
1486 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1490 if (slave_host_id == master_context->host_id) /* Link from us */
1492 struct Slave *slave;
1493 struct LinkControllersContext *lcc;
1495 msize -= sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
1496 config_size = ntohs (msg->config_size);
1497 if ((delegated_host_id < slave_list_size) && (NULL != slave_list[delegated_host_id])) /* We have already added */
1499 LOG (GNUNET_ERROR_TYPE_WARNING, "Host %u already connected\n",
1501 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1504 config = GNUNET_malloc (config_size);
1505 dest_size = (uLongf) config_size;
1507 uncompress ((Bytef *) config, &dest_size, (const Bytef *) &msg[1],
1510 GNUNET_break (0); /* Compression error */
1511 GNUNET_free (config);
1512 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1515 if (config_size != dest_size)
1517 LOG (GNUNET_ERROR_TYPE_WARNING, "Uncompressed config size mismatch\n");
1518 GNUNET_free (config);
1519 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1522 cfg = GNUNET_CONFIGURATION_create (); /* Free here or in lcfcontext */
1524 GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
1526 GNUNET_break (0); /* Configuration parsing error */
1527 GNUNET_free (config);
1528 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1531 GNUNET_free (config);
1532 if ((delegated_host_id < slave_list_size) &&
1533 (NULL != slave_list[delegated_host_id]))
1535 GNUNET_break (0); /* Configuration parsing error */
1536 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1539 slave = GNUNET_malloc (sizeof (struct Slave));
1540 slave->host_id = delegated_host_id;
1541 slave_list_add (slave);
1542 if (1 != msg->is_subordinate)
1545 GNUNET_TESTBED_controller_connect (cfg, host_list[slave->host_id],
1546 master_context->event_mask,
1547 &slave_event_callback, slave);
1549 if (NULL != slave->controller)
1550 send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
1552 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1553 "Could not connect to delegated controller");
1554 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1557 lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
1558 lcc->operation_id = GNUNET_ntohll (msg->operation_id);
1559 GNUNET_SERVER_client_keep (client);
1560 lcc->client = client;
1562 slave->controller_proc =
1563 GNUNET_TESTBED_controller_start (master_context->master_ip,
1564 host_list[slave->host_id], cfg,
1565 &slave_status_callback, slave);
1566 GNUNET_CONFIGURATION_destroy (cfg);
1567 new_route = GNUNET_malloc (sizeof (struct Route));
1568 new_route->dest = delegated_host_id;
1569 new_route->thru = master_context->host_id;
1570 route_list_add (new_route);
1574 /* Route the request */
1575 if (slave_host_id >= route_list_size)
1577 LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1578 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1581 lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
1582 lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
1583 lcfq->lcf->delegated_host_id = delegated_host_id;
1584 lcfq->lcf->slave_host_id = slave_host_id;
1585 route = find_dest_route (slave_host_id);
1586 GNUNET_assert (NULL != route); /* because we add routes carefully */
1587 GNUNET_assert (route->dest < slave_list_size);
1588 GNUNET_assert (NULL != slave_list[route->dest]);
1589 lcfq->lcf->state = INIT;
1590 lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id);
1591 lcfq->lcf->gateway = slave_list[route->dest];
1592 lcfq->lcf->msg = GNUNET_malloc (msize);
1593 (void) memcpy (lcfq->lcf->msg, msg, msize);
1594 GNUNET_SERVER_client_keep (client);
1595 lcfq->lcf->client = client;
1596 if (NULL == lcfq_head)
1598 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1599 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1600 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
1603 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1604 /* FIXME: Adding a new route should happen after the controllers are linked
1606 if (1 != msg->is_subordinate)
1608 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1611 if ((delegated_host_id < route_list_size)
1612 && (NULL != route_list[delegated_host_id]))
1614 GNUNET_break_op (0); /* Are you trying to link delegated host twice
1615 with is subordinate flag set to GNUNET_YES? */
1616 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1619 new_route = GNUNET_malloc (sizeof (struct Route));
1620 new_route->dest = delegated_host_id;
1621 new_route->thru = route->dest;
1622 route_list_add (new_route);
1623 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1628 * The task to be executed if the forwarded peer create operation has been
1631 * @param cls the FowardedOperationContext
1632 * @param tc the TaskContext from the scheduler
1635 peer_create_forward_timeout (void *cls,
1636 const struct GNUNET_SCHEDULER_TaskContext *tc)
1638 struct ForwardedOperationContext *fo_ctxt = cls;
1640 /* send error msg to client */
1641 send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id, "Timedout");
1642 GNUNET_SERVER_client_drop (fo_ctxt->client);
1643 GNUNET_TESTBED_forward_operation_msg_cancel_ (fo_ctxt->opc);
1644 GNUNET_free (fo_ctxt);
1649 * Callback to be called when forwarded peer create operation is
1650 * successfull. We have to relay the reply msg back to the client
1652 * @param cls ForwardedOperationContext
1653 * @param msg the peer create success message
1656 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
1658 struct ForwardedOperationContext *fo_ctxt = cls;
1659 const struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *success_msg;
1660 struct GNUNET_MessageHeader *dup_msg;
1664 GNUNET_SCHEDULER_cancel (fo_ctxt->timeout_task);
1665 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS)
1668 (const struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *) msg;
1669 peer = GNUNET_malloc (sizeof (struct Peer));
1670 peer->is_remote = GNUNET_YES;
1671 peer->id = ntohl (success_msg->peer_id);
1672 GNUNET_assert (NULL != fo_ctxt->cls);
1673 peer->details.remote.controller = fo_ctxt->cls;
1674 peer_list_add (peer);
1676 msize = ntohs (msg->size);
1677 dup_msg = GNUNET_malloc (msize);
1678 (void) memcpy (dup_msg, msg, msize);
1679 queue_message (fo_ctxt->client, dup_msg);
1680 GNUNET_SERVER_client_drop (fo_ctxt->client);
1681 GNUNET_free (fo_ctxt);
1687 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
1690 * @param client identification of the client
1691 * @param message the actual message
1694 handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
1695 const struct GNUNET_MessageHeader *message)
1697 const struct GNUNET_TESTBED_PeerCreateMessage *msg;
1698 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
1699 struct GNUNET_CONFIGURATION_Handle *cfg;
1700 struct ForwardedOperationContext *fo_ctxt;
1701 struct Route *route;
1706 uint32_t config_size;
1712 msize = ntohs (message->size);
1713 if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
1715 GNUNET_break (0); /* We need configuration */
1716 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1719 msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
1720 host_id = ntohl (msg->host_id);
1721 peer_id = ntohl (msg->peer_id);
1722 if (UINT32_MAX == peer_id)
1724 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1725 "Cannot create peer with given ID");
1726 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1729 if (host_id == master_context->host_id)
1733 /* We are responsible for this peer */
1734 msize -= sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
1735 config_size = ntohl (msg->config_size);
1736 config = GNUNET_malloc (config_size);
1737 dest_size = config_size;
1740 uncompress ((Bytef *) config, (uLongf *) & dest_size,
1741 (const Bytef *) &msg[1], (uLong) msize)))
1743 GNUNET_break (0); /* uncompression error */
1744 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1747 if (config_size != dest_size)
1749 GNUNET_break (0); /* Uncompressed config size mismatch */
1750 GNUNET_free (config);
1751 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1754 cfg = GNUNET_CONFIGURATION_create ();
1756 GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
1758 GNUNET_break (0); /* Configuration parsing error */
1759 GNUNET_free (config);
1760 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1763 GNUNET_free (config);
1764 peer = GNUNET_malloc (sizeof (struct Peer));
1765 peer->is_remote = GNUNET_NO;
1766 peer->details.local.cfg = cfg;
1768 LOG_DEBUG ("Creating peer with id: %u\n", peer->id);
1769 peer->details.local.peer =
1770 GNUNET_TESTING_peer_configure (master_context->system,
1771 peer->details.local.cfg, peer->id,
1772 NULL /* Peer id */ ,
1774 if (NULL == peer->details.local.peer)
1776 LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
1780 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1783 peer->details.local.is_running = GNUNET_NO;
1784 peer_list_add (peer);
1786 GNUNET_malloc (sizeof
1787 (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1788 reply->header.size =
1789 htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1790 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS);
1791 reply->peer_id = msg->peer_id;
1792 reply->operation_id = msg->operation_id;
1793 queue_message (client, &reply->header);
1794 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1798 /* Forward peer create request */
1799 route = find_dest_route (host_id);
1803 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1806 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1807 GNUNET_SERVER_client_keep (client);
1808 fo_ctxt->client = client;
1809 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
1810 fo_ctxt->cls = slave_list[route->dest]->controller;
1812 GNUNET_TESTBED_forward_operation_msg_ (slave_list
1813 [route->dest]->controller,
1814 fo_ctxt->operation_id,
1816 peer_create_success_cb, fo_ctxt);
1817 fo_ctxt->timeout_task =
1818 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &peer_create_forward_timeout,
1821 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1826 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1829 * @param client identification of the client
1830 * @param message the actual message
1833 handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
1834 const struct GNUNET_MessageHeader *message)
1836 const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
1837 struct ForwardedOperationContext *fopc;
1841 msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
1842 peer_id = ntohl (msg->peer_id);
1843 LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
1844 peer_id, GNUNET_ntohll (msg->operation_id));
1845 if ((peer_list_size <= peer_id) || (NULL == peer_list[peer_id]))
1847 LOG (GNUNET_ERROR_TYPE_ERROR,
1848 "Asked to destroy a non existent peer with id: %u\n", peer_id);
1849 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1850 "Peer doesn't exist");
1851 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1854 peer = peer_list[peer_id];
1855 if (GNUNET_YES == peer->is_remote)
1857 /* Forward the destory message to sub controller */
1858 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1859 GNUNET_SERVER_client_keep (client);
1860 fopc->client = client;
1861 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1863 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.controller,
1864 fopc->operation_id, &msg->header,
1865 &forwarded_operation_reply_relay,
1867 fopc->timeout_task =
1868 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
1870 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1873 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1874 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1875 peer_list_remove (peer);
1877 send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
1878 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1883 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1886 * @param client identification of the client
1887 * @param message the actual message
1890 handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
1891 const struct GNUNET_MessageHeader *message)
1893 const struct GNUNET_TESTBED_PeerStartMessage *msg;
1894 struct GNUNET_TESTBED_PeerEventMessage *reply;
1895 struct ForwardedOperationContext *fopc;
1899 msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
1900 peer_id = ntohl (msg->peer_id);
1901 if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
1904 LOG (GNUNET_ERROR_TYPE_ERROR,
1905 "Asked to start a non existent peer with id: %u\n", peer_id);
1906 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1909 peer = peer_list[peer_id];
1910 if (GNUNET_YES == peer->is_remote)
1912 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1913 GNUNET_SERVER_client_keep (client);
1914 fopc->client = client;
1915 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1917 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.controller,
1918 fopc->operation_id, &msg->header,
1919 &forwarded_operation_reply_relay,
1921 fopc->timeout_task =
1922 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
1924 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1927 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
1929 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1931 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1934 peer->details.local.is_running = GNUNET_YES;
1935 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1936 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT);
1937 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1938 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
1939 reply->host_id = htonl (master_context->host_id);
1940 reply->peer_id = msg->peer_id;
1941 reply->operation_id = msg->operation_id;
1942 queue_message (client, &reply->header);
1943 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1948 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1951 * @param client identification of the client
1952 * @param message the actual message
1955 handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
1956 const struct GNUNET_MessageHeader *message)
1958 const struct GNUNET_TESTBED_PeerStopMessage *msg;
1959 struct GNUNET_TESTBED_PeerEventMessage *reply;
1960 struct ForwardedOperationContext *fopc;
1964 msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
1965 peer_id = ntohl (msg->peer_id);
1966 if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
1968 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1970 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1973 peer = peer_list[peer_id];
1974 if (GNUNET_YES == peer->is_remote)
1976 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1977 GNUNET_SERVER_client_keep (client);
1978 fopc->client = client;
1979 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1981 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.controller,
1982 fopc->operation_id, &msg->header,
1983 &forwarded_operation_reply_relay,
1985 fopc->timeout_task =
1986 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
1988 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1991 if (GNUNET_OK != GNUNET_TESTING_peer_stop (peer->details.local.peer))
1993 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1994 "Peer not running");
1995 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1998 peer->details.local.is_running = GNUNET_NO;
1999 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2000 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT);
2001 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2002 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
2003 reply->host_id = htonl (master_context->host_id);
2004 reply->peer_id = msg->peer_id;
2005 reply->operation_id = msg->operation_id;
2006 queue_message (client, &reply->header);
2007 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2012 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
2015 * @param client identification of the client
2016 * @param message the actual message
2019 handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
2020 const struct GNUNET_MessageHeader *message)
2022 const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
2023 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
2032 msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
2033 peer_id = ntohl (msg->peer_id);
2034 if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
2036 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2038 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2041 peer = peer_list[peer_id];
2042 if (GNUNET_YES == peer->is_remote)
2044 struct ForwardedOperationContext *fopc;
2046 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2047 GNUNET_SERVER_client_keep (client);
2048 fopc->client = client;
2049 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
2051 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.controller,
2052 fopc->operation_id, &msg->header,
2053 &forwarded_operation_reply_relay,
2055 fopc->timeout_task =
2056 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2058 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2062 GNUNET_CONFIGURATION_serialize (peer_list[peer_id]->details.local.cfg,
2064 xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
2065 GNUNET_free (config);
2068 sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
2069 reply = GNUNET_realloc (xconfig, msize);
2070 (void) memmove (&reply[1], reply, xc_size);
2071 reply->header.size = htons (msize);
2072 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG);
2073 reply->peer_id = msg->peer_id;
2074 reply->operation_id = msg->operation_id;
2075 GNUNET_TESTING_peer_get_identity (peer_list[peer_id]->details.local.peer,
2076 &reply->peer_identity);
2077 reply->config_size = htons ((uint16_t) c_size);
2078 queue_message (client, &reply->header);
2079 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2084 * Task for cleaing up overlay connect context structure
2086 * @param cls the overlay connect context
2087 * @param tc the task context
2090 occ_cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2092 struct OverlayConnectContext *occ = cls;
2094 LOG_DEBUG ("Cleaning up occ\n");
2095 GNUNET_free_non_null (occ->emsg);
2096 GNUNET_free_non_null (occ->hello);
2097 GNUNET_SERVER_client_drop (occ->client);
2098 if (NULL != occ->opc)
2099 GNUNET_TESTBED_forward_operation_msg_cancel_ (occ->opc);
2100 if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
2101 GNUNET_SCHEDULER_cancel (occ->send_hello_task);
2102 if (NULL != occ->ch)
2103 GNUNET_CORE_disconnect (occ->ch);
2104 if (NULL != occ->ghh)
2105 GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
2106 if (NULL != occ->p1th)
2107 GNUNET_TRANSPORT_disconnect (occ->p1th);
2108 if (NULL != occ->p2th)
2109 GNUNET_TRANSPORT_disconnect (occ->p2th);
2115 * Task which will be run when overlay connect request has been timed out
2117 * @param cls the OverlayConnectContext
2118 * @param tc the TaskContext
2121 timeout_overlay_connect (void *cls,
2122 const struct GNUNET_SCHEDULER_TaskContext *tc)
2124 struct OverlayConnectContext *occ = cls;
2126 occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2127 send_operation_fail_msg (occ->client, occ->op_id, occ->emsg);
2128 occ_cleanup (occ, tc);
2134 * Function called to notify transport users that another
2135 * peer connected to us.
2137 * @param cls closure
2138 * @param new_peer the peer that connected
2139 * @param ats performance data
2140 * @param ats_count number of entries in ats (excluding 0-termination)
2143 overlay_connect_notify (void *cls, const struct GNUNET_PeerIdentity *new_peer,
2144 const struct GNUNET_ATS_Information *ats,
2145 unsigned int ats_count)
2147 struct OverlayConnectContext *occ = cls;
2148 struct GNUNET_TESTBED_ConnectionEventMessage *msg;
2150 char *other_peer_str;
2152 LOG_DEBUG ("Overlay connect notify\n");
2154 memcmp (new_peer, &occ->peer_identity,
2155 sizeof (struct GNUNET_PeerIdentity)))
2157 new_peer_str = GNUNET_strdup (GNUNET_i2s (new_peer));
2158 other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
2160 memcmp (new_peer, &occ->other_peer_identity,
2161 sizeof (struct GNUNET_PeerIdentity)))
2163 LOG_DEBUG ("Unexpected peer %4s connected when expecting peer %4s\n",
2164 new_peer_str, other_peer_str);
2165 GNUNET_free (new_peer_str);
2166 GNUNET_free (other_peer_str);
2169 GNUNET_free (new_peer_str);
2170 LOG_DEBUG ("Peer %4s connected to peer %4s\n", other_peer_str,
2171 GNUNET_i2s (&occ->peer_identity));
2172 GNUNET_free (other_peer_str);
2173 if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
2175 GNUNET_SCHEDULER_cancel (occ->send_hello_task);
2176 occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
2178 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
2179 GNUNET_SCHEDULER_cancel (occ->timeout_task);
2180 occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2181 GNUNET_free_non_null (occ->emsg);
2183 if (NULL != occ->p2th)
2184 GNUNET_TRANSPORT_disconnect (occ->p2th);
2186 LOG_DEBUG ("Peers connected - Sending overlay connect success\n");
2187 msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
2189 htons (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
2190 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONEVENT);
2191 msg->event_type = htonl (GNUNET_TESTBED_ET_CONNECT);
2192 msg->peer1 = htonl (occ->peer_id);
2193 msg->peer2 = htonl (occ->other_peer_id);
2194 msg->operation_id = GNUNET_htonll (occ->op_id);
2195 queue_message (occ->client, &msg->header);
2196 GNUNET_SCHEDULER_add_now (&occ_cleanup, occ);
2201 * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
2204 * @param cls the OverlayConnectContext
2205 * @param tc the TaskContext from scheduler
2208 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2210 struct OverlayConnectContext *occ = cls;
2211 char *other_peer_str;
2213 occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
2214 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2216 GNUNET_assert (NULL != occ->hello);
2217 other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
2218 if (NULL != occ->peer2_controller)
2220 struct GNUNET_TESTBED_RequestConnectMessage *msg;
2222 uint16_t hello_size;
2224 LOG_DEBUG ("Offering HELLO of %s to %s via Remote Overlay Request\n",
2225 GNUNET_i2s (&occ->peer_identity), other_peer_str);
2226 hello_size = ntohs (occ->hello->size);
2227 msize = sizeof (struct GNUNET_TESTBED_RequestConnectMessage) + hello_size;
2228 msg = GNUNET_malloc (msize);
2229 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT);
2230 msg->header.size = htons (msize);
2231 msg->peer = htonl (occ->other_peer_id);
2232 msg->operation_id = GNUNET_htonll (occ->op_id);
2233 (void) memcpy (&msg->peer_identity, &occ->peer_identity,
2234 sizeof (struct GNUNET_PeerIdentity));
2235 memcpy (msg->hello, occ->hello, hello_size);
2236 GNUNET_TESTBED_queue_message_ (occ->peer2_controller, &msg->header);
2240 LOG_DEBUG ("Offering HELLO of %s to %s\n",
2241 GNUNET_i2s (&occ->peer_identity), other_peer_str);
2242 GNUNET_TRANSPORT_offer_hello (occ->p2th, occ->hello, NULL, NULL);
2243 GNUNET_TRANSPORT_try_connect (occ->p2th, &occ->peer_identity);
2244 occ->send_hello_task =
2245 GNUNET_SCHEDULER_add_delayed
2246 (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
2247 100 * (pow (2, occ->retries++))),
2250 GNUNET_free (other_peer_str);
2254 * Test for checking whether HELLO message is empty
2256 * @param cls empty flag to set
2257 * @param address the HELLO
2258 * @param expiration expiration of the HELLO
2262 test_address (void *cls, const struct GNUNET_HELLO_Address *address,
2263 struct GNUNET_TIME_Absolute expiration)
2273 * Function called whenever there is an update to the HELLO of peers in the
2274 * OverlayConnectClosure. If we have a valid HELLO, we connect to the peer 2's
2275 * transport and offer peer 1's HELLO and ask peer 2 to connect to peer 1
2277 * @param cls closure
2278 * @param hello our updated HELLO
2281 hello_update_cb (void *cls, const struct GNUNET_MessageHeader *hello)
2283 struct OverlayConnectContext *occ = cls;
2287 msize = ntohs (hello->size);
2289 (void) GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *)
2290 hello, GNUNET_NO, &test_address,
2292 if (GNUNET_YES == empty)
2294 LOG_DEBUG ("HELLO of %s is empty\n", GNUNET_i2s (&occ->peer_identity));
2297 LOG_DEBUG ("Received HELLO of %s\n", GNUNET_i2s (&occ->peer_identity));
2298 occ->hello = GNUNET_malloc (msize);
2299 memcpy (occ->hello, hello, msize);
2300 GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
2302 GNUNET_TRANSPORT_disconnect (occ->p1th);
2304 GNUNET_free_non_null (occ->emsg);
2305 if (NULL == occ->peer2_controller)
2308 GNUNET_TRANSPORT_connect (peer_list[occ->other_peer_id]->details.local.cfg,
2309 &occ->other_peer_identity, NULL, NULL, NULL,
2311 if (NULL == occ->p2th)
2313 GNUNET_asprintf (&occ->emsg, "Cannot connect to TRANSPORT of %s\n",
2314 GNUNET_i2s (&occ->other_peer_identity));
2315 GNUNET_SCHEDULER_cancel (occ->timeout_task);
2316 occ->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
2320 occ->emsg = GNUNET_strdup ("Timeout while offering HELLO to other peer");
2321 occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
2326 * Function called after GNUNET_CORE_connect has succeeded (or failed
2327 * for good). Note that the private key of the peer is intentionally
2328 * not exposed here; if you need it, your process should try to read
2329 * the private key file directly (which should work if you are
2332 * @param cls closure
2333 * @param server handle to the server, NULL if we failed
2334 * @param my_identity ID of this peer, NULL if we failed
2337 core_startup_cb (void *cls, struct GNUNET_CORE_Handle *server,
2338 const struct GNUNET_PeerIdentity *my_identity)
2340 struct OverlayConnectContext *occ = cls;
2342 GNUNET_free_non_null (occ->emsg);
2343 occ->emsg = GNUNET_strdup ("Failed to connect to CORE\n");
2344 if ((NULL == server) || (NULL == my_identity))
2346 GNUNET_free (occ->emsg);
2349 memcpy (&occ->peer_identity, my_identity,
2350 sizeof (struct GNUNET_PeerIdentity));
2352 GNUNET_TRANSPORT_connect (occ->peer->details.local.cfg,
2353 &occ->peer_identity, NULL, NULL, NULL, NULL);
2354 if (NULL == occ->p1th)
2356 GNUNET_asprintf (&occ->emsg, "Cannot connect to TRANSPORT of peers %4s",
2357 GNUNET_i2s (&occ->peer_identity));
2360 LOG_DEBUG ("Acquiring HELLO of peer %s\n", GNUNET_i2s (&occ->peer_identity));
2361 occ->emsg = GNUNET_strdup ("Timeout while acquiring HELLO message");
2362 occ->ghh = GNUNET_TRANSPORT_get_hello (occ->p1th, &hello_update_cb, occ);
2366 GNUNET_SCHEDULER_cancel (occ->timeout_task);
2367 occ->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
2373 * Callback to be called when forwarded get peer config operation as part of
2374 * overlay connect is successfull. Connection to Peer 1's core is made and is
2375 * checked for new connection from peer 2
2377 * @param cls ForwardedOperationContext
2378 * @param msg the peer create success message
2381 overlay_connect_get_config (void *cls, const struct GNUNET_MessageHeader *msg)
2383 struct OverlayConnectContext *occ = cls;
2384 const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *cmsg;
2385 const struct GNUNET_CORE_MessageHandler no_handlers[] = {
2390 if (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG != ntohs (msg->type))
2392 cmsg = (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *)
2394 memcpy (&occ->other_peer_identity, &cmsg->peer_identity,
2395 sizeof (struct GNUNET_PeerIdentity));
2396 GNUNET_free_non_null (occ->emsg);
2397 occ->emsg = GNUNET_strdup ("Timeout while connecting to CORE");
2399 GNUNET_CORE_connect (occ->peer->details.local.cfg, occ, &core_startup_cb,
2400 &overlay_connect_notify, NULL, NULL, GNUNET_NO, NULL,
2401 GNUNET_NO, no_handlers);
2402 if (NULL == occ->ch)
2407 GNUNET_SCHEDULER_cancel (occ->timeout_task);
2409 GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
2414 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT messages
2417 * @param client identification of the client
2418 * @param message the actual message
2421 handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
2422 const struct GNUNET_MessageHeader *message)
2424 const struct GNUNET_TESTBED_OverlayConnectMessage *msg;
2425 struct OverlayConnectContext *occ;
2426 const struct GNUNET_CORE_MessageHandler no_handlers[] = {
2430 uint64_t operation_id;
2434 msg = (const struct GNUNET_TESTBED_OverlayConnectMessage *) message;
2435 p1 = ntohl (msg->peer1);
2436 p2 = ntohl (msg->peer2);
2437 GNUNET_assert (p1 < peer_list_size);
2438 GNUNET_assert (NULL != peer_list[p1]);
2439 peer = peer_list[p1];
2440 operation_id = GNUNET_ntohll (msg->operation_id);
2441 if (GNUNET_YES == peer->is_remote)
2443 struct ForwardedOperationContext *fopc;
2445 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2446 GNUNET_SERVER_client_keep (client);
2447 fopc->client = client;
2448 fopc->operation_id = operation_id;
2449 LOG_DEBUG ("Forwarding overlay connect\n");
2451 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.controller,
2452 operation_id, message,
2453 &forwarded_operation_reply_relay,
2455 fopc->timeout_task =
2456 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2458 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2461 occ = GNUNET_malloc (sizeof (struct OverlayConnectContext));
2462 GNUNET_SERVER_client_keep (client);
2463 occ->client = client;
2465 occ->other_peer_id = p2;
2466 occ->peer = peer_list[p1];
2467 occ->op_id = GNUNET_ntohll (msg->operation_id);
2468 if ((p2 >= peer_list_size) || (NULL == peer_list[p2]))
2470 uint32_t peer2_host_id;
2472 peer2_host_id = ntohl (msg->peer2_host_id);
2473 if ((peer2_host_id >= slave_list_size)
2474 || (NULL ==slave_list[peer2_host_id]))
2476 struct GNUNET_TESTBED_NeedControllerConfig *reply;
2479 reply = GNUNET_malloc (sizeof (struct
2480 GNUNET_TESTBED_NeedControllerConfig));
2481 reply->header.size = htons (sizeof (struct
2482 GNUNET_TESTBED_NeedControllerConfig));
2483 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_NEEDCONTROLLERCONFIG);
2484 reply->controller_host_id = msg->peer2_host_id;
2485 reply->operation_id = msg->operation_id;
2486 queue_message (client, &reply->header);
2487 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2492 occ->peer2_controller = slave_list[peer2_host_id]->controller;
2493 if (NULL == occ->peer2_controller)
2495 GNUNET_break (0); /* What's going on? */
2496 GNUNET_SERVER_client_drop (client);
2498 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2505 if (GNUNET_YES == peer_list[occ->other_peer_id]->is_remote)
2506 occ->peer2_controller = peer_list[occ->other_peer_id]->details.remote.controller;
2508 /* Get the identity of the second peer */
2509 if (NULL != occ->peer2_controller)
2511 struct GNUNET_TESTBED_PeerGetConfigurationMessage cmsg;
2514 htons (sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
2515 cmsg.header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG);
2516 cmsg.peer_id = msg->peer2;
2517 cmsg.operation_id = msg->operation_id;
2519 GNUNET_TESTBED_forward_operation_msg_ (occ->peer2_controller,
2520 occ->op_id, &cmsg.header,
2521 &overlay_connect_get_config,
2524 GNUNET_strdup ("Timeout while getting peer identity of peer B\n");
2526 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2527 (GNUNET_TIME_UNIT_SECONDS, 30),
2528 &timeout_overlay_connect, occ);
2529 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2532 GNUNET_TESTING_peer_get_identity (peer_list[occ->other_peer_id]->details.local.peer,
2533 &occ->other_peer_identity);
2534 /* Connect to the core of 1st peer and wait for the 2nd peer to connect */
2535 occ->emsg = GNUNET_strdup ("Timeout while connecting to CORE");
2537 GNUNET_CORE_connect (occ->peer->details.local.cfg, occ, &core_startup_cb,
2538 &overlay_connect_notify, NULL, NULL, GNUNET_NO, NULL,
2539 GNUNET_NO, no_handlers);
2540 if (NULL == occ->ch)
2542 GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
2545 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2546 (GNUNET_TIME_UNIT_SECONDS, 30),
2547 &timeout_overlay_connect, occ);
2548 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2553 * Function to cleanup RequestOverlayConnectContext and any associated tasks
2556 * @param rocc the RequestOverlayConnectContext
2559 cleanup_rocc (struct RequestOverlayConnectContext *rocc)
2561 if (GNUNET_SCHEDULER_NO_TASK != rocc->attempt_connect_task_id)
2562 GNUNET_SCHEDULER_cancel (rocc->attempt_connect_task_id);
2563 if (GNUNET_SCHEDULER_NO_TASK != rocc->timeout_rocc_task_id)
2564 GNUNET_SCHEDULER_cancel (rocc->timeout_rocc_task_id);
2565 GNUNET_TRANSPORT_disconnect (rocc->th);
2566 GNUNET_free_non_null (rocc->hello);
2572 * Task to timeout rocc and cleanit up
2574 * @param cls the RequestOverlayConnectContext
2575 * @param tc the TaskContext from scheduler
2578 timeout_rocc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2580 struct RequestOverlayConnectContext *rocc = cls;
2582 rocc->timeout_rocc_task_id = GNUNET_SCHEDULER_NO_TASK;
2583 cleanup_rocc (rocc);
2588 * Function called to notify transport users that another
2589 * peer connected to us.
2591 * @param cls closure
2592 * @param new_peer the peer that connected
2593 * @param ats performance data
2594 * @param ats_count number of entries in ats (excluding 0-termination)
2597 transport_connect_notify (void *cls, const struct GNUNET_PeerIdentity *new_peer,
2598 const struct GNUNET_ATS_Information * ats,
2601 struct RequestOverlayConnectContext *rocc = cls;
2603 LOG_DEBUG ("Request Overlay connect notify\n");
2604 if (0 != memcmp (new_peer, &rocc->a_id, sizeof (struct GNUNET_PeerIdentity)))
2606 LOG_DEBUG ("Peer %4s connected\n", GNUNET_i2s (&rocc->a_id));
2607 cleanup_rocc (rocc);
2612 * Task to offer the HELLO message to the peer and ask it to connect to the peer
2613 * whose identity is in RequestOverlayConnectContext
2615 * @param cls the RequestOverlayConnectContext
2616 * @param tc the TaskContext from scheduler
2619 attempt_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2621 struct RequestOverlayConnectContext *rocc = cls;
2623 rocc->attempt_connect_task_id = GNUNET_SCHEDULER_NO_TASK;
2624 GNUNET_TRANSPORT_offer_hello (rocc->th, rocc->hello, NULL, NULL);
2625 GNUNET_TRANSPORT_try_connect (rocc->th, &rocc->a_id);
2626 rocc->attempt_connect_task_id =
2627 GNUNET_SCHEDULER_add_delayed
2628 (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
2629 100 * (pow (2, rocc->retries++))),
2630 &attempt_connect_task, rocc);
2635 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT messages
2638 * @param client identification of the client
2639 * @param message the actual message
2642 handle_overlay_request_connect (void *cls, struct GNUNET_SERVER_Client *client,
2643 const struct GNUNET_MessageHeader *message)
2645 const struct GNUNET_TESTBED_RequestConnectMessage *msg;
2646 struct RequestOverlayConnectContext *rocc;
2652 msize = ntohs (message->size);
2653 if (sizeof (struct GNUNET_TESTBED_RequestConnectMessage) >= msize)
2656 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2659 msg = (const struct GNUNET_TESTBED_RequestConnectMessage *) message;
2660 if ((NULL == msg->hello) ||
2661 (GNUNET_MESSAGE_TYPE_HELLO != ntohs (msg->hello->type)))
2664 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2667 hsize = ntohs (msg->hello->size);
2668 if ((sizeof (struct GNUNET_TESTBED_RequestConnectMessage) + hsize) != msize)
2671 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2674 peer_id = ntohl (msg->peer);
2675 if ((peer_id >= peer_list_size) || (NULL == (peer = peer_list[peer_id])))
2677 GNUNET_break_op (0);
2678 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2681 if (GNUNET_YES == peer->is_remote)
2683 struct GNUNET_MessageHeader *msg2;
2685 msg2 = GNUNET_malloc (msize);
2686 (void) memcpy (msg2, message, msize);
2687 GNUNET_TESTBED_queue_message_ (peer->details.remote.controller, msg2);
2688 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2691 rocc = GNUNET_malloc (sizeof (struct RequestOverlayConnectContext));
2692 rocc->th = GNUNET_TRANSPORT_connect (peer->details.local.cfg, NULL, rocc,
2693 NULL, &transport_connect_notify, NULL);
2694 if (NULL == rocc->th)
2698 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2701 memcpy (&rocc->a_id, &msg->peer_identity,
2702 sizeof (struct GNUNET_PeerIdentity));
2703 rocc->hello = GNUNET_malloc (hsize);
2704 memcpy (rocc->hello, msg->hello, hsize);
2705 rocc->attempt_connect_task_id =
2706 GNUNET_SCHEDULER_add_now (&attempt_connect_task, rocc);
2707 rocc->timeout_rocc_task_id =
2708 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_rocc_task, rocc);
2709 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2714 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
2717 * @param client identification of the client
2718 * @param message the actual message
2721 handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
2722 const struct GNUNET_MessageHeader *message)
2724 struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
2725 struct Slave *slave;
2726 struct GNUNET_TESTBED_SlaveConfiguration *reply;
2730 size_t xconfig_size;
2735 msg = (struct GNUNET_TESTBED_SlaveGetConfigurationMessage *) message;
2736 slave_id = ntohl (msg->slave_id);
2737 op_id = GNUNET_ntohll (msg->operation_id);
2738 if ((slave_list_size <= slave_id) || (NULL == slave_list[slave_id]))
2740 send_operation_fail_msg (client, op_id, "Slave not found");
2741 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2744 slave = slave_list[slave_id];
2745 if (NULL == slave->cfg)
2747 send_operation_fail_msg (client, op_id,
2748 "Configuration not found (slave not started by me)");
2749 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2752 config = GNUNET_CONFIGURATION_serialize (slave->cfg, &config_size);
2753 xconfig_size = GNUNET_TESTBED_compress_config_ (config, config_size,
2755 GNUNET_free (config);
2756 reply_size = xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
2757 GNUNET_break (reply_size <= UINT16_MAX);
2758 GNUNET_break (config_size <= UINT16_MAX);
2759 reply = GNUNET_realloc (xconfig, reply_size);
2760 (void) memmove (&reply[1], reply, xconfig_size);
2761 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG);
2762 reply->header.size = htons ((uint16_t) reply_size);
2763 reply->slave_id = msg->slave_id;
2764 reply->operation_id = msg->operation_id;
2765 reply->config_size = htons ((uint16_t) config_size);
2766 queue_message (client, &reply->header);
2767 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2772 * Iterator over hash map entries.
2774 * @param cls closure
2775 * @param key current key code
2776 * @param value value in the hash map
2777 * @return GNUNET_YES if we should continue to
2782 ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
2784 struct SharedService *ss = value;
2786 GNUNET_assert (GNUNET_YES ==
2787 GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
2788 GNUNET_free (ss->name);
2795 * Task to clean up and shutdown nicely
2798 * @param tc the TaskContext from scheduler
2801 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2803 struct LCFContextQueue *lcfq;
2806 shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
2807 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
2808 (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
2810 GNUNET_CONTAINER_multihashmap_destroy (ss_map);
2811 if (NULL != lcfq_head)
2813 if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
2815 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
2816 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
2818 if (NULL != lcfq_head->lcf->rhandle)
2819 GNUNET_TESTBED_cancel_registration (lcfq_head->lcf->rhandle);
2821 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
2822 for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
2824 GNUNET_free (lcfq->lcf->msg);
2825 GNUNET_free (lcfq->lcf);
2826 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
2829 /* Clear peer list */
2830 for (id = 0; id < peer_list_size; id++)
2831 if (NULL != peer_list[id])
2833 if (GNUNET_NO == peer_list[id]->is_remote)
2835 if (GNUNET_YES == peer_list[id]->details.local.is_running)
2836 GNUNET_TESTING_peer_stop (peer_list[id]->details.local.peer);
2837 GNUNET_TESTING_peer_destroy (peer_list[id]->details.local.peer);
2838 GNUNET_CONFIGURATION_destroy (peer_list[id]->details.local.cfg);
2840 GNUNET_free (peer_list[id]);
2842 GNUNET_free_non_null (peer_list);
2843 /* Clear host list */
2844 for (id = 0; id < host_list_size; id++)
2845 if (NULL != host_list[id])
2846 GNUNET_TESTBED_host_destroy (host_list[id]);
2847 GNUNET_free_non_null (host_list);
2848 /* Clear route list */
2849 for (id = 0; id < route_list_size; id++)
2850 if (NULL != route_list[id])
2851 GNUNET_free (route_list[id]);
2852 GNUNET_free_non_null (route_list);
2853 /* Clear slave_list */
2854 for (id = 0; id < slave_list_size; id++)
2855 if (NULL != slave_list[id])
2857 if (NULL != slave_list[id]->cfg)
2858 GNUNET_CONFIGURATION_destroy (slave_list[id]->cfg);
2859 if (NULL != slave_list[id]->controller)
2860 GNUNET_TESTBED_controller_disconnect (slave_list[id]->controller);
2861 if (NULL != slave_list[id]->controller_proc)
2862 GNUNET_TESTBED_controller_stop (slave_list[id]->controller_proc);
2863 GNUNET_free (slave_list[id]);
2865 GNUNET_free_non_null (slave_list);
2866 if (NULL != master_context)
2868 GNUNET_free_non_null (master_context->master_ip);
2869 if (NULL != master_context->system)
2870 GNUNET_TESTING_system_destroy (master_context->system, GNUNET_YES);
2871 GNUNET_free (master_context);
2872 master_context = NULL;
2874 GNUNET_free_non_null (hostname);
2879 * Callback for client disconnect
2882 * @param client the client which has disconnected
2885 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
2887 if (NULL == master_context)
2889 if (client == master_context->client)
2891 LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
2892 GNUNET_SERVER_client_drop (client);
2893 /* should not be needed as we're terminated by failure to read
2894 * from stdin, but if stdin fails for some reason, this shouldn't
2895 * hurt for now --- might need to revise this later if we ever
2896 * decide that master connections might be temporarily down
2897 * for some reason */
2898 //GNUNET_SCHEDULER_shutdown ();
2906 * @param cls closure
2907 * @param server the initialized server
2908 * @param cfg configuration to use
2911 testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
2912 const struct GNUNET_CONFIGURATION_Handle *cfg)
2914 static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
2915 {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT, 0},
2916 {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST, 0},
2917 {&handle_configure_shared_service, NULL,
2918 GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE, 0},
2919 {&handle_link_controllers, NULL,
2920 GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS, 0},
2921 {&handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER, 0},
2922 {&handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER,
2923 sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
2924 {&handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STARTPEER,
2925 sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
2926 {&handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOPPEER,
2927 sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
2928 {&handle_peer_get_config, NULL, GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG,
2929 sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
2930 {&handle_overlay_connect, NULL, GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT,
2931 sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
2932 {&handle_overlay_request_connect, NULL, GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT,
2934 {handle_slave_get_config, NULL, GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG,
2935 sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
2939 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string
2940 (cfg, "testbed", "HOSTNAME", &hostname));
2941 GNUNET_SERVER_add_handlers (server, message_handlers);
2942 GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
2943 ss_map = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
2945 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2946 &shutdown_task, NULL);
2947 LOG_DEBUG ("Testbed startup complete\n");
2952 * The starting point of execution
2955 main (int argc, char *const *argv)
2957 //sleep (15); /* Debugging */
2958 return (GNUNET_OK ==
2959 GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
2960 &testbed_run, NULL)) ? 0 : 1;
2963 /* end of gnunet-service-testbed.c */