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.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, 15)
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 * Our host id according to this context
91 * The message queue for sending messages to clients
96 * The message to be sent
98 struct GNUNET_MessageHeader *msg;
101 * The client to send the message to
103 struct GNUNET_SERVER_Client *client;
106 * next pointer for DLL
108 struct MessageQueue *next;
111 * prev pointer for DLL
113 struct MessageQueue *prev;
118 * The structure for identifying a shared service
123 * The name of the shared service
128 * Number of shared peers per instance of the shared service
133 * Number of peers currently sharing the service
135 uint32_t num_sharing;
150 * The destination host is reachable thru
157 * Context information used while linking controllers
159 struct LinkControllersContext;
163 * A DLL of host registrations to be made
165 struct HostRegistration
168 * next registration in the DLL
170 struct HostRegistration *next;
173 * previous registration in the DLL
175 struct HostRegistration *prev;
178 * The callback to call after this registration's status is available
180 GNUNET_TESTBED_HostRegistrationCompletion cb;
183 * The closure for the above callback
188 * The host that has to be registered
190 struct GNUNET_TESTBED_Host *host;
195 * This context information will be created for each host that is registered at
196 * slave controllers during overlay connects.
198 struct RegisteredHostContext
201 * The host which is being registered
203 struct GNUNET_TESTBED_Host *reg_host;
206 * The host of the controller which has to connect to the above rhost
208 struct GNUNET_TESTBED_Host *host;
211 * The gateway to which this operation is forwarded to
213 struct Slave *gateway;
216 * The gateway through which peer2's controller can be reached
218 struct Slave *gateway2;
221 * Handle for sub-operations
223 struct GNUNET_TESTBED_Operation *sub_op;
226 * The client which initiated the link controller operation
228 struct GNUNET_SERVER_Client *client;
231 * Head of the ForwardedOverlayConnectContext DLL
233 struct ForwardedOverlayConnectContext *focc_dll_head;
236 * Tail of the ForwardedOverlayConnectContext DLL
238 struct ForwardedOverlayConnectContext *focc_dll_tail;
241 * Enumeration of states for this context
251 * State where we attempt to get peer2's controller configuration
256 * State where we attempt to link the controller of peer 1 to the controller
262 * State where we attempt to do the overlay connection again
272 * Structure representing a connected(directly-linked) controller
277 * The controller process handle if we had started the controller
279 struct GNUNET_TESTBED_ControllerProc *controller_proc;
282 * The controller handle
284 struct GNUNET_TESTBED_Controller *controller;
287 * The configuration of the slave. Cannot be NULL
289 struct GNUNET_CONFIGURATION_Handle *cfg;
292 * handle to lcc which is associated with this slave startup. Should be set to
293 * NULL when the slave has successfully started up
295 struct LinkControllersContext *lcc;
298 * Head of the host registration DLL
300 struct HostRegistration *hr_dll_head;
303 * Tail of the host registration DLL
305 struct HostRegistration *hr_dll_tail;
308 * The current host registration handle
310 struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
313 * Hashmap to hold Registered host contexts
315 struct GNUNET_CONTAINER_MultiHashMap *reghost_map;
318 * The id of the host this controller is running on
326 * States of LCFContext
331 * The Context has been initialized; Nothing has been done on it
336 * Delegated host has been registered at the forwarding controller
338 DELEGATED_HOST_REGISTERED,
341 * The slave host has been registred at the forwarding controller
343 SLAVE_HOST_REGISTERED,
346 * The context has been finished (may have error)
353 * Link controllers request forwarding context
358 * The gateway which will pass the link message to delegated host
360 struct Slave *gateway;
363 * The controller link message that has to be forwarded to
365 struct GNUNET_TESTBED_ControllerLinkMessage *msg;
368 * The client which has asked to perform this operation
370 struct GNUNET_SERVER_Client *client;
373 * Handle for operations which are forwarded while linking controllers
375 struct ForwardedOperationContext *fopc;
378 * The id of the operation which created this context
380 uint64_t operation_id;
383 * The state of this context
385 enum LCFContextState state;
390 uint32_t delegated_host_id;
395 uint32_t slave_host_id;
401 * Structure of a queue entry in LCFContext request queue
403 struct LCFContextQueue
408 struct LCFContext *lcf;
413 struct LCFContextQueue *next;
418 struct LCFContextQueue *prev;
434 * The peer handle from testing API
436 struct GNUNET_TESTING_Peer *peer;
439 * The modified (by GNUNET_TESTING_peer_configure) configuration this
440 * peer is configured with
442 struct GNUNET_CONFIGURATION_Handle *cfg;
445 * Is the peer running
454 * The slave this peer is started through
459 * The id of the remote host this peer is running on
461 uint32_t remote_host_id;
468 * Is this peer locally created?
473 * Our local reference id for this peer
478 * References to peers are using in forwarded overlay contexts and remote
479 * overlay connect contexts. A peer can only be destroyed after all such
480 * contexts are destroyed. For this, we maintain a reference counter. When we
481 * use a peer in any such context, we increment this counter. We decrement it
482 * when we are destroying these contexts
484 uint32_t reference_cnt;
487 * While destroying a peer, due to the fact that there could be references to
488 * this peer, we delay the peer destroy to a further time. We do this by using
489 * this flag to destroy the peer while destroying a context in which this peer
490 * has been used. When the flag is set to 1 and reference_cnt = 0 we destroy
493 uint32_t destroy_flag;
499 * Context information for transport try connect
501 struct TryConnectContext
504 * The identity of the peer to which the transport has to attempt a connection
506 struct GNUNET_PeerIdentity *pid;
509 * The transport handle
511 struct GNUNET_TRANSPORT_Handle *th;
514 * the try connect handle
516 struct GNUNET_TRANSPORT_TryConnectHandle *tch;
521 GNUNET_SCHEDULER_TaskIdentifier task;
524 * The id of the operation which is resposible for this context
529 * The number of times we attempted to connect
531 unsigned int retries;
537 * Context information for connecting 2 peers in overlay
539 struct OverlayConnectContext
542 * The next pointer for maintaining a DLL
544 struct OverlayConnectContext *next;
547 * The prev pointer for maintaining a DLL
549 struct OverlayConnectContext *prev;
552 * The client which has requested for overlay connection
554 struct GNUNET_SERVER_Client *client;
557 * the peer which has to connect to the other peer
562 * Transport handle of the first peer to get its HELLO
564 struct GNUNET_TRANSPORT_Handle *p1th;
567 * Core handles of the first peer; used to notify when second peer connects to it
569 struct GNUNET_CORE_Handle *ch;
572 * HELLO of the other peer
574 struct GNUNET_MessageHeader *hello;
577 * Get hello handle to acquire HELLO of first peer
579 struct GNUNET_TRANSPORT_GetHelloHandle *ghh;
582 * The handle for offering HELLO
584 struct GNUNET_TRANSPORT_OfferHelloHandle *ohh;
587 * The error message we send if this overlay connect operation has timed out
592 * Operation context for suboperations
594 struct OperationContext *opc;
597 * Controller of peer 2; NULL if the peer is local
599 struct GNUNET_TESTBED_Controller *peer2_controller;
602 * The transport try connect context
604 struct TryConnectContext tcc;
607 * The peer identity of the first peer
609 struct GNUNET_PeerIdentity peer_identity;
612 * The peer identity of the other peer
614 struct GNUNET_PeerIdentity other_peer_identity;
617 * The id of the operation responsible for creating this context
622 * The id of the task for sending HELLO of peer 2 to peer 1 and ask peer 1 to
625 GNUNET_SCHEDULER_TaskIdentifier send_hello_task;
628 * The id of the overlay connect timeout task
630 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
633 * The id of the cleanup task
635 GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
645 uint32_t other_peer_id;
651 * Context information for RequestOverlayConnect
652 * operations. RequestOverlayConnect is used when peers A, B reside on different
653 * hosts and the host controller for peer B is asked by the host controller of
654 * peer A to make peer B connect to peer A
656 struct RequestOverlayConnectContext
659 * the next pointer for DLL
661 struct RequestOverlayConnectContext *next;
664 * the prev pointer for DLL
666 struct RequestOverlayConnectContext *prev;
669 * The peer handle of peer B
676 struct GNUNET_MessageHeader *hello;
679 * The handle for offering HELLO
681 struct GNUNET_TRANSPORT_OfferHelloHandle *ohh;
684 * The transport try connect context
686 struct TryConnectContext tcc;
689 * The peer identity of peer A
691 struct GNUNET_PeerIdentity a_id;
694 * Task for offering HELLO of A to B and doing try_connect
696 GNUNET_SCHEDULER_TaskIdentifier attempt_connect_task_id;
699 * Task to timeout RequestOverlayConnect
701 GNUNET_SCHEDULER_TaskIdentifier timeout_rocc_task_id;
704 * The id of the operation responsible for creating this context
711 * Context information for operations forwarded to subcontrollers
713 struct ForwardedOperationContext
716 * The next pointer for DLL
718 struct ForwardedOperationContext *next;
721 * The prev pointer for DLL
723 struct ForwardedOperationContext *prev;
726 * The generated operation context
728 struct OperationContext *opc;
731 * The client to which we have to reply
733 struct GNUNET_SERVER_Client *client;
741 * Task ID for the timeout task
743 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
746 * The id of the operation that has been forwarded
748 uint64_t operation_id;
751 * The type of the operation which is forwarded
753 enum OperationType type;
759 * Context information used while linking controllers
761 struct LinkControllersContext
764 * The client which initiated the link controller operation
766 struct GNUNET_SERVER_Client *client;
769 * The ID of the operation
771 uint64_t operation_id;
777 * Context information to used during operations which forward the overlay
780 struct ForwardedOverlayConnectContext
783 * next ForwardedOverlayConnectContext in the DLL
785 struct ForwardedOverlayConnectContext *next;
788 * previous ForwardedOverlayConnectContext in the DLL
790 struct ForwardedOverlayConnectContext *prev;
793 * A copy of the original overlay connect message
795 struct GNUNET_MessageHeader *orig_msg;
798 * The id of the operation which created this context information
800 uint64_t operation_id;
813 * Id of the host where peer2 is running
815 uint32_t peer2_host_id;
822 struct HelloCacheEntry
825 * DLL next ptr for least recently used hello cache entries
827 struct HelloCacheEntry *next;
830 * DLL prev ptr for least recently used hello cache entries
832 struct HelloCacheEntry *prev;
835 * The key for this entry
837 struct GNUNET_HashCode key;
842 struct GNUNET_MessageHeader *hello;
847 * The master context; generated with the first INIT message
849 static struct Context *master_context;
852 * Our hostname; we give this to all the peers we start
854 static char *hostname;
864 static struct GNUNET_CONFIGURATION_Handle *our_config;
867 * Current Transmit Handle; NULL if no notify transmit exists currently
869 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
876 * The head for the LCF queue
878 static struct LCFContextQueue *lcfq_head;
881 * The tail for the LCF queue
883 static struct LCFContextQueue *lcfq_tail;
886 * The message queue head
888 static struct MessageQueue *mq_head;
891 * The message queue tail
893 static struct MessageQueue *mq_tail;
896 * DLL head for OverlayConnectContext DLL - to be used to clean up during shutdown
898 static struct OverlayConnectContext *occq_head;
901 * DLL tail for OverlayConnectContext DLL
903 static struct OverlayConnectContext *occq_tail;
906 * DLL head for RequectOverlayConnectContext DLL - to be used to clean up during
909 static struct RequestOverlayConnectContext *roccq_head;
912 * DLL tail for RequectOverlayConnectContext DLL
914 static struct RequestOverlayConnectContext *roccq_tail;
917 * DLL head for forwarded operation contexts
919 static struct ForwardedOperationContext *fopcq_head;
922 * DLL tail for forwarded operation contexts
924 static struct ForwardedOperationContext *fopcq_tail;
927 * DLL head for least recently used hello cache entries; least recently used
928 * cache items are at the head
930 static struct HelloCacheEntry *lru_hcache_head;
933 * DLL tail for least recently used hello cache entries; recently used cache
934 * items are at the tail
936 static struct HelloCacheEntry *lru_hcache_tail;
941 static struct GNUNET_TESTBED_Host **host_list;
946 static struct Route **route_list;
949 * A list of directly linked neighbours
951 static struct Slave **slave_list;
954 * A list of peers we know about
956 static struct Peer **peer_list;
959 * The hashmap of shared services
961 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
964 * Hashmap to maintain HELLO cache
966 static struct GNUNET_CONTAINER_MultiHashMap *hello_cache;
969 * The event mask for the events we listen from sub-controllers
971 static uint64_t event_mask;
974 * The size of the host list
976 static unsigned int host_list_size;
979 * The size of the route list
981 static unsigned int route_list_size;
984 * The size of directly linked neighbours list
986 static unsigned int slave_list_size;
989 * The size of the peer list
991 static unsigned int peer_list_size;
994 * The size of hello cache
996 static unsigned int hello_cache_size;
1003 * The lcf_task handle
1005 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
1008 * The shutdown task handle
1010 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
1014 * Looks up in the hello cache and returns the HELLO of the given peer
1016 * @param id the peer identity of the peer whose HELLO has to be looked up
1017 * @return the HELLO message; NULL if not found
1019 static const struct GNUNET_MessageHeader *
1020 hello_cache_lookup (const struct GNUNET_PeerIdentity *id)
1022 struct HelloCacheEntry *entry;
1024 if (NULL == hello_cache)
1026 entry = GNUNET_CONTAINER_multihashmap_get (hello_cache, &id->hashPubKey);
1029 GNUNET_CONTAINER_DLL_remove (lru_hcache_head, lru_hcache_tail, entry);
1030 GNUNET_CONTAINER_DLL_insert_tail (lru_hcache_head, lru_hcache_tail, entry);
1031 return entry->hello;
1036 * Removes the given hello cache centry from hello cache and frees its resources
1038 * @param entry the entry to remove
1041 hello_cache_remove (struct HelloCacheEntry *entry)
1043 GNUNET_CONTAINER_DLL_remove (lru_hcache_head, lru_hcache_tail, entry);
1044 GNUNET_assert (GNUNET_YES ==
1045 GNUNET_CONTAINER_multihashmap_remove (hello_cache,
1048 GNUNET_free (entry->hello);
1049 GNUNET_free (entry);
1054 * Caches the HELLO of the given peer. Updates the HELLO if it was already
1057 * @param id the peer identity of the peer whose HELLO has to be cached
1058 * @param hello the HELLO message
1061 hello_cache_add (const struct GNUNET_PeerIdentity *id,
1062 const struct GNUNET_MessageHeader *hello)
1064 struct HelloCacheEntry *entry;
1066 if (NULL == hello_cache)
1068 entry = GNUNET_CONTAINER_multihashmap_get (hello_cache, &id->hashPubKey);
1071 entry = GNUNET_malloc (sizeof (struct HelloCacheEntry));
1072 memcpy (&entry->key, &id->hashPubKey, sizeof (struct GNUNET_HashCode));
1073 if (GNUNET_CONTAINER_multihashmap_size (hello_cache) == hello_cache_size)
1075 GNUNET_assert (NULL != lru_hcache_head);
1076 hello_cache_remove (lru_hcache_head);
1078 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put
1082 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
1086 GNUNET_CONTAINER_DLL_remove (lru_hcache_head, lru_hcache_tail, entry);
1087 GNUNET_free (entry->hello);
1089 entry->hello = GNUNET_copy_message (hello);
1090 GNUNET_CONTAINER_DLL_insert_tail (lru_hcache_head, lru_hcache_tail, entry);
1095 * Function called to notify a client about the connection begin ready to queue
1096 * more data. "buf" will be NULL and "size" zero if the connection was closed
1097 * for writing in the meantime.
1100 * @param size number of bytes available in buf
1101 * @param buf where the callee should write the message
1102 * @return number of bytes written to buf
1105 transmit_ready_notify (void *cls, size_t size, void *buf)
1107 struct MessageQueue *mq_entry;
1109 transmit_handle = NULL;
1111 GNUNET_assert (NULL != mq_entry);
1114 GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
1115 size = ntohs (mq_entry->msg->size);
1116 memcpy (buf, mq_entry->msg, size);
1117 GNUNET_free (mq_entry->msg);
1118 GNUNET_SERVER_client_drop (mq_entry->client);
1119 GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
1120 GNUNET_free (mq_entry);
1122 if (NULL != mq_entry)
1124 GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
1125 ntohs (mq_entry->msg->size),
1126 GNUNET_TIME_UNIT_FOREVER_REL,
1127 &transmit_ready_notify, NULL);
1133 * Queues a message in send queue for sending to the service
1135 * @param client the client to whom the queued message has to be sent
1136 * @param msg the message to queue
1139 queue_message (struct GNUNET_SERVER_Client *client,
1140 struct GNUNET_MessageHeader *msg)
1142 struct MessageQueue *mq_entry;
1146 type = ntohs (msg->type);
1147 size = ntohs (msg->size);
1148 GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
1149 (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
1150 mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
1151 mq_entry->msg = msg;
1152 mq_entry->client = client;
1153 GNUNET_SERVER_client_keep (client);
1154 LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
1156 GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
1157 if (NULL == transmit_handle)
1159 GNUNET_SERVER_notify_transmit_ready (client, size,
1160 GNUNET_TIME_UNIT_FOREVER_REL,
1161 &transmit_ready_notify, NULL);
1166 * Similar to GNUNET_array_grow(); however instead of calling GNUNET_array_grow()
1167 * several times we call it only once. The array is also made to grow in steps
1168 * of LIST_GROW_STEP.
1170 * @param ptr the array pointer to grow
1171 * @param size the size of array
1172 * @param accommodate_size the size which the array has to accommdate; after
1173 * this call the array will be big enough to accommdate sizes upto
1176 #define array_grow_large_enough(ptr, size, accommodate_size) \
1179 unsigned int growth_size; \
1180 GNUNET_assert (size <= accommodate_size); \
1181 growth_size = size; \
1182 while (growth_size <= accommodate_size) \
1183 growth_size += LIST_GROW_STEP; \
1184 GNUNET_array_grow (ptr, size, growth_size); \
1185 GNUNET_assert (size > accommodate_size); \
1190 * Function to add a host to the current list of known hosts
1192 * @param host the host to add
1193 * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
1197 host_list_add (struct GNUNET_TESTBED_Host *host)
1201 host_id = GNUNET_TESTBED_host_get_id_ (host);
1202 if (host_list_size <= host_id)
1203 array_grow_large_enough (host_list, host_list_size, host_id);
1204 if (NULL != host_list[host_id])
1206 LOG_DEBUG ("A host with id: %u already exists\n", host_id);
1207 return GNUNET_SYSERR;
1209 host_list[host_id] = host;
1215 * Adds a route to the route list
1217 * @param route the route to add
1220 route_list_add (struct Route *route)
1222 if (route->dest >= route_list_size)
1223 array_grow_large_enough (route_list, route_list_size, route->dest);
1224 GNUNET_assert (NULL == route_list[route->dest]);
1225 route_list[route->dest] = route;
1230 * Adds a slave to the slave array
1232 * @param slave the slave controller to add
1235 slave_list_add (struct Slave *slave)
1237 if (slave->host_id >= slave_list_size)
1238 array_grow_large_enough (slave_list, slave_list_size, slave->host_id);
1239 GNUNET_assert (NULL == slave_list[slave->host_id]);
1240 slave_list[slave->host_id] = slave;
1245 * Adds a peer to the peer array
1247 * @param peer the peer to add
1250 peer_list_add (struct Peer *peer)
1252 if (peer->id >= peer_list_size)
1253 array_grow_large_enough (peer_list, peer_list_size, peer->id);
1254 GNUNET_assert (NULL == peer_list[peer->id]);
1255 peer_list[peer->id] = peer;
1260 * Removes a the give peer from the peer array
1262 * @param peer the peer to be removed
1265 peer_list_remove (struct Peer *peer)
1267 unsigned int orig_size;
1270 peer_list[peer->id] = NULL;
1271 orig_size = peer_list_size;
1272 while (peer_list_size >= LIST_GROW_STEP)
1274 for (id = peer_list_size - 1;
1275 (id >= peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX); id--)
1276 if (NULL != peer_list[id])
1278 if (id != ((peer_list_size - LIST_GROW_STEP) - 1))
1280 peer_list_size -= LIST_GROW_STEP;
1282 if (orig_size == peer_list_size)
1285 GNUNET_realloc (peer_list, sizeof (struct Peer *) * peer_list_size);
1290 * Finds the route with directly connected host as destination through which
1291 * the destination host can be reached
1293 * @param host_id the id of the destination host
1294 * @return the route with directly connected destination host; NULL if no route
1297 static struct Route *
1298 find_dest_route (uint32_t host_id)
1300 struct Route *route;
1302 if (route_list_size <= host_id)
1304 while (NULL != (route = route_list[host_id]))
1306 if (route->thru == master_context->host_id)
1308 host_id = route->thru;
1315 * Routes message to a host given its host_id
1317 * @param host_id the id of the destination host
1318 * @param msg the message to be routed
1321 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
1328 * Send operation failure message to client
1330 * @param client the client to which the failure message has to be sent to
1331 * @param operation_id the id of the failed operation
1332 * @param emsg the error message; can be NULL
1335 send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
1336 uint64_t operation_id, const char *emsg)
1338 struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
1342 msize = sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
1343 emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
1345 msg = GNUNET_malloc (msize);
1346 msg->header.size = htons (msize);
1347 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OPERATIONFAILEVENT);
1348 msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
1349 msg->operation_id = GNUNET_htonll (operation_id);
1351 memcpy (&msg[1], emsg, emsg_len);
1352 queue_message (client, &msg->header);
1357 * Function to send generic operation success message to given client
1359 * @param client the client to send the message to
1360 * @param operation_id the id of the operation which was successful
1363 send_operation_success_msg (struct GNUNET_SERVER_Client *client,
1364 uint64_t operation_id)
1366 struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
1369 msize = sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage);
1370 msg = GNUNET_malloc (msize);
1371 msg->header.size = htons (msize);
1372 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GENERICOPSUCCESS);
1373 msg->operation_id = GNUNET_htonll (operation_id);
1374 msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
1375 queue_message (client, &msg->header);
1380 * Callback which will be called to after a host registration succeeded or failed
1382 * @param cls the handle to the slave at which the registration is completed
1383 * @param emsg the error message; NULL if host registration is successful
1386 hr_completion (void *cls, const char *emsg);
1390 * Attempts to register the next host in the host registration queue
1392 * @param slave the slave controller whose host registration queue is checked
1393 * for host registrations
1396 register_next_host (struct Slave *slave)
1398 struct HostRegistration *hr;
1400 hr = slave->hr_dll_head;
1401 GNUNET_assert (NULL != hr);
1402 GNUNET_assert (NULL == slave->rhandle);
1403 LOG (GNUNET_ERROR_TYPE_DEBUG,
1404 "Registering host %u at %u\n",
1405 GNUNET_TESTBED_host_get_id_ (hr->host),
1406 GNUNET_TESTBED_host_get_id_ (host_list[slave->host_id]));
1407 slave->rhandle = GNUNET_TESTBED_register_host (slave->controller,
1415 * Callback which will be called to after a host registration succeeded or failed
1417 * @param cls the handle to the slave at which the registration is completed
1418 * @param emsg the error message; NULL if host registration is successful
1421 hr_completion (void *cls, const char *emsg)
1423 struct Slave *slave = cls;
1424 struct HostRegistration *hr;
1426 slave->rhandle = NULL;
1427 hr = slave->hr_dll_head;
1428 GNUNET_assert (NULL != hr);
1429 LOG (GNUNET_ERROR_TYPE_DEBUG,
1430 "Registering host %u at %u successful\n",
1431 GNUNET_TESTBED_host_get_id_ (hr->host),
1432 GNUNET_TESTBED_host_get_id_ (host_list[slave->host_id]));
1433 GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head,
1437 hr->cb (hr->cb_cls, emsg);
1439 if (NULL != slave->hr_dll_head)
1440 register_next_host (slave);
1445 * Adds a host registration's request to a slave's registration queue
1447 * @param slave the slave controller at which the given host has to be
1449 * @param cb the host registration completion callback
1450 * @param cb_cls the closure for the host registration completion callback
1451 * @param host the host which has to be registered
1454 queue_host_registration (struct Slave *slave,
1455 GNUNET_TESTBED_HostRegistrationCompletion cb,
1457 struct GNUNET_TESTBED_Host *host)
1459 struct HostRegistration *hr;
1462 LOG (GNUNET_ERROR_TYPE_DEBUG,
1463 "Queueing host registration for host %u at %u\n",
1464 GNUNET_TESTBED_host_get_id_ (host),
1465 GNUNET_TESTBED_host_get_id_ (host_list[slave->host_id]));
1466 hr = GNUNET_malloc (sizeof (struct HostRegistration));
1468 hr->cb_cls = cb_cls;
1470 call_register = (NULL == slave->hr_dll_head) ? GNUNET_YES : GNUNET_NO;
1471 GNUNET_CONTAINER_DLL_insert_tail (slave->hr_dll_head,
1474 if (GNUNET_YES == call_register)
1475 register_next_host (slave);
1480 * The Link Controller forwarding task
1482 * @param cls the LCFContext
1483 * @param tc the Task context from scheduler
1486 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1490 * Completion callback for host registrations while forwarding Link Controller messages
1492 * @param cls the LCFContext
1493 * @param emsg the error message; NULL if host registration is successful
1496 lcf_proc_cc (void *cls, const char *emsg)
1498 struct LCFContext *lcf = cls;
1500 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1505 goto registration_error;
1506 lcf->state = DELEGATED_HOST_REGISTERED;
1507 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1509 case DELEGATED_HOST_REGISTERED:
1511 goto registration_error;
1512 lcf->state = SLAVE_HOST_REGISTERED;
1513 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1516 GNUNET_assert (0); /* Shouldn't reach here */
1521 LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
1523 lcf->state = FINISHED;
1524 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1529 * Callback to relay the reply msg of a forwarded operation back to the client
1531 * @param cls ForwardedOperationContext
1532 * @param msg the message to relay
1535 forwarded_operation_reply_relay (void *cls,
1536 const struct GNUNET_MessageHeader *msg)
1538 struct ForwardedOperationContext *fopc = cls;
1539 struct GNUNET_MessageHeader *dup_msg;
1542 msize = ntohs (msg->size);
1543 LOG_DEBUG ("Relaying message with type: %u, size: %u\n", ntohs (msg->type),
1545 dup_msg = GNUNET_copy_message (msg);
1546 queue_message (fopc->client, dup_msg);
1547 GNUNET_SERVER_client_drop (fopc->client);
1548 GNUNET_SCHEDULER_cancel (fopc->timeout_task);
1549 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
1555 * Task to free resources when forwarded operation has been timedout
1557 * @param cls the ForwardedOperationContext
1558 * @param tc the task context from scheduler
1561 forwarded_operation_timeout (void *cls,
1562 const struct GNUNET_SCHEDULER_TaskContext *tc)
1564 struct ForwardedOperationContext *fopc = cls;
1566 GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
1567 LOG (GNUNET_ERROR_TYPE_WARNING, "A forwarded operation has timed out\n");
1568 send_operation_fail_msg (fopc->client, fopc->operation_id, "Timeout");
1569 GNUNET_SERVER_client_drop (fopc->client);
1570 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
1576 * The Link Controller forwarding task
1578 * @param cls the LCFContext
1579 * @param tc the Task context from scheduler
1582 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1586 * Callback to be called when forwarded link controllers operation is
1587 * successfull. We have to relay the reply msg back to the client
1589 * @param cls the LCFContext
1590 * @param msg the message to relay
1593 lcf_forwarded_operation_reply_relay (void *cls,
1594 const struct GNUNET_MessageHeader *msg)
1596 struct LCFContext *lcf = cls;
1598 GNUNET_assert (NULL != lcf->fopc);
1599 forwarded_operation_reply_relay (lcf->fopc, msg);
1601 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1602 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1607 * Task to free resources when forwarded link controllers has been timedout
1609 * @param cls the LCFContext
1610 * @param tc the task context from scheduler
1613 lcf_forwarded_operation_timeout (void *cls,
1614 const struct GNUNET_SCHEDULER_TaskContext *tc)
1616 struct LCFContext *lcf = cls;
1618 GNUNET_assert (NULL != lcf->fopc);
1619 lcf->fopc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1620 forwarded_operation_timeout (lcf->fopc, tc);
1622 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1623 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1628 * The Link Controller forwarding task
1630 * @param cls the LCFContext
1631 * @param tc the Task context from scheduler
1634 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1636 struct LCFContext *lcf = cls;
1637 struct LCFContextQueue *lcfq;
1639 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1644 GNUNET_TESTBED_is_host_registered_ (host_list[lcf->delegated_host_id],
1645 lcf->gateway->controller))
1647 queue_host_registration (lcf->gateway,
1649 host_list[lcf->delegated_host_id]);
1653 lcf->state = DELEGATED_HOST_REGISTERED;
1654 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1657 case DELEGATED_HOST_REGISTERED:
1659 GNUNET_TESTBED_is_host_registered_ (host_list[lcf->slave_host_id],
1660 lcf->gateway->controller))
1662 queue_host_registration (lcf->gateway,
1664 host_list[lcf->slave_host_id]);
1668 lcf->state = SLAVE_HOST_REGISTERED;
1669 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1672 case SLAVE_HOST_REGISTERED:
1673 lcf->fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1674 lcf->fopc->client = lcf->client;
1675 lcf->fopc->operation_id = lcf->operation_id;
1676 lcf->fopc->type = OP_LINK_CONTROLLERS;
1678 GNUNET_TESTBED_forward_operation_msg_ (lcf->gateway->controller,
1681 &lcf_forwarded_operation_reply_relay,
1683 lcf->fopc->timeout_task =
1684 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &lcf_forwarded_operation_timeout,
1686 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, lcf->fopc);
1687 lcf->state = FINISHED;
1691 GNUNET_assert (lcfq->lcf == lcf);
1692 GNUNET_free (lcf->msg);
1694 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
1696 if (NULL != lcfq_head)
1698 GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
1704 * Cleans up ForwardedOverlayConnectContext
1706 * @param focc the ForwardedOverlayConnectContext to cleanup
1709 cleanup_focc (struct ForwardedOverlayConnectContext *focc)
1711 GNUNET_free_non_null (focc->orig_msg);
1717 * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext
1719 * @param rhc the RegisteredHostContext
1722 process_next_focc (struct RegisteredHostContext *rhc);
1726 * Timeout task for cancelling a forwarded overlay connect connect
1728 * @param cls the ForwardedOverlayConnectContext
1729 * @param tc the task context from the scheduler
1732 forwarded_overlay_connect_timeout (void *cls,
1733 const struct GNUNET_SCHEDULER_TaskContext
1736 struct ForwardedOperationContext *fopc = cls;
1737 struct RegisteredHostContext *rhc;
1738 struct ForwardedOverlayConnectContext *focc;
1741 focc = rhc->focc_dll_head;
1742 GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
1743 cleanup_focc (focc);
1744 LOG_DEBUG ("Overlay linking between peers %u and %u failed\n",
1745 focc->peer1, focc->peer2);
1746 forwarded_operation_timeout (cls, tc);
1747 if (NULL != rhc->focc_dll_head)
1748 process_next_focc (rhc);
1753 * Callback to be called when forwarded overlay connection operation has a reply
1754 * from the sub-controller successfull. We have to relay the reply msg back to
1757 * @param cls ForwardedOperationContext
1758 * @param msg the peer create success message
1761 forwarded_overlay_connect_listener (void *cls,
1762 const struct GNUNET_MessageHeader *msg)
1764 struct ForwardedOperationContext *fopc = cls;
1765 struct RegisteredHostContext *rhc;
1766 struct ForwardedOverlayConnectContext *focc;
1769 forwarded_operation_reply_relay (cls, msg);
1770 focc = rhc->focc_dll_head;
1771 GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
1772 cleanup_focc (focc);
1773 if (NULL != rhc->focc_dll_head)
1774 process_next_focc (rhc);
1779 * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext
1781 * @param rhc the RegisteredHostContext
1784 process_next_focc (struct RegisteredHostContext *rhc)
1786 struct ForwardedOperationContext *fopc;
1787 struct ForwardedOverlayConnectContext *focc;
1789 focc = rhc->focc_dll_head;
1790 GNUNET_assert (NULL != focc);
1791 GNUNET_assert (RHC_OL_CONNECT == rhc->state);
1792 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1793 GNUNET_SERVER_client_keep (rhc->client);
1794 fopc->client = rhc->client;
1795 fopc->operation_id = focc->operation_id;
1797 fopc->type = OP_OVERLAY_CONNECT;
1799 GNUNET_TESTBED_forward_operation_msg_ (rhc->gateway->controller,
1800 focc->operation_id, focc->orig_msg,
1801 &forwarded_overlay_connect_listener,
1803 GNUNET_free (focc->orig_msg);
1804 focc->orig_msg = NULL;
1805 fopc->timeout_task =
1806 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_overlay_connect_timeout,
1808 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1813 * Callback for event from slave controllers
1815 * @param cls struct Slave *
1816 * @param event information about the event
1819 slave_event_callback (void *cls,
1820 const struct GNUNET_TESTBED_EventInformation *event)
1822 struct RegisteredHostContext *rhc;
1823 struct GNUNET_CONFIGURATION_Handle *cfg;
1824 struct GNUNET_TESTBED_Operation *old_op;
1826 /* We currently only get here when working on RegisteredHostContexts */
1827 GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
1828 rhc = event->details.operation_finished.op_cls;
1829 GNUNET_assert (rhc->sub_op == event->details.operation_finished.operation);
1833 cfg = event->details.operation_finished.generic;
1834 old_op = rhc->sub_op;
1835 rhc->state = RHC_LINK;
1837 GNUNET_TESTBED_controller_link (rhc,
1838 rhc->gateway->controller,
1843 GNUNET_TESTBED_operation_done (old_op);
1846 LOG_DEBUG ("OL: Linking controllers successfull\n");
1847 GNUNET_TESTBED_operation_done (rhc->sub_op);
1849 rhc->state = RHC_OL_CONNECT;
1850 process_next_focc (rhc);
1859 * Callback to signal successfull startup of the controller process
1861 * @param cls the handle to the slave whose status is to be found here
1862 * @param cfg the configuration with which the controller has been started;
1863 * NULL if status is not GNUNET_OK
1864 * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
1865 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
1868 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
1871 struct Slave *slave = cls;
1872 struct LinkControllersContext *lcc;
1875 if (GNUNET_SYSERR == status)
1877 slave->controller_proc = NULL;
1878 slave_list[slave->host_id] = NULL;
1879 if (NULL != slave->cfg)
1880 GNUNET_CONFIGURATION_destroy (slave->cfg);
1881 GNUNET_free (slave);
1883 LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
1884 GNUNET_SCHEDULER_shutdown (); /* We too shutdown */
1888 GNUNET_TESTBED_controller_connect (cfg, host_list[slave->host_id],
1890 &slave_event_callback, slave);
1891 if (NULL != slave->controller)
1893 send_operation_success_msg (lcc->client, lcc->operation_id);
1894 slave->cfg = GNUNET_CONFIGURATION_dup (cfg);
1898 send_operation_fail_msg (lcc->client, lcc->operation_id,
1899 "Could not connect to delegated controller");
1900 GNUNET_TESTBED_controller_stop (slave->controller_proc);
1901 slave_list[slave->host_id] = NULL;
1902 GNUNET_free (slave);
1909 if (NULL != lcc->client)
1911 GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
1912 GNUNET_SERVER_client_drop (lcc->client);
1923 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
1926 * @param client identification of the client
1927 * @param message the actual message
1930 handle_init (void *cls, struct GNUNET_SERVER_Client *client,
1931 const struct GNUNET_MessageHeader *message)
1933 const struct GNUNET_TESTBED_InitMessage *msg;
1934 struct GNUNET_TESTBED_Host *host;
1935 const char *controller_hostname;
1938 if (NULL != master_context)
1940 LOG_DEBUG ("We are being connected to laterally\n");
1941 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1944 msg = (const struct GNUNET_TESTBED_InitMessage *) message;
1945 msize = ntohs (message->size);
1946 if (msize <= sizeof (struct GNUNET_TESTBED_InitMessage))
1949 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1952 msize -= sizeof (struct GNUNET_TESTBED_InitMessage);
1953 controller_hostname = (const char *) &msg[1];
1954 if ('\0' != controller_hostname[msize - 1])
1957 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1960 master_context = GNUNET_malloc (sizeof (struct Context));
1961 GNUNET_SERVER_client_keep (client);
1962 master_context->client = client;
1963 master_context->host_id = ntohl (msg->host_id);
1964 master_context->master_ip = GNUNET_strdup (controller_hostname);
1965 LOG_DEBUG ("Our IP: %s\n", master_context->master_ip);
1966 master_context->system =
1967 GNUNET_TESTING_system_create ("testbed", master_context->master_ip, hostname);
1969 GNUNET_TESTBED_host_create_with_id (master_context->host_id,
1970 master_context->master_ip,
1973 host_list_add (host);
1974 LOG_DEBUG ("Created master context with host ID: %u\n",
1975 master_context->host_id);
1976 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1981 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1984 * @param client identification of the client
1985 * @param message the actual message
1988 handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
1989 const struct GNUNET_MessageHeader *message)
1991 struct GNUNET_TESTBED_Host *host;
1992 const struct GNUNET_TESTBED_AddHostMessage *msg;
1993 struct GNUNET_TESTBED_HostConfirmedMessage *reply;
1998 uint16_t username_length;
1999 uint16_t hostname_length;
2000 uint16_t reply_size;
2003 msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
2004 msize = ntohs (msg->header.size);
2005 username = (char *) &msg[1];
2006 username_length = ntohs (msg->user_name_length);
2007 if (0 != username_length)
2009 /* msg must contain hostname */
2010 GNUNET_assert (msize > (sizeof (struct GNUNET_TESTBED_AddHostMessage) +
2011 username_length + 1));
2012 if (0 != username_length)
2013 GNUNET_assert ('\0' == username[username_length - 1]);
2014 hostname = username + username_length;
2016 msize - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
2017 GNUNET_assert ('\0' == hostname[hostname_length - 1]);
2018 GNUNET_assert (strlen (hostname) == hostname_length - 1);
2019 host_id = ntohl (msg->host_id);
2020 LOG_DEBUG ("Received ADDHOST %u message\n", host_id);
2021 LOG_DEBUG ("-------host id: %u\n", host_id);
2022 LOG_DEBUG ("-------hostname: %s\n", hostname);
2023 if (0 != username_length)
2024 LOG_DEBUG ("-------username: %s\n", username);
2027 LOG_DEBUG ("-------username: NULL\n");
2030 LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
2032 GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
2033 ntohs (msg->ssh_port));
2034 GNUNET_assert (NULL != host);
2035 reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
2036 if (GNUNET_OK != host_list_add (host))
2038 /* We are unable to add a host */
2039 emsg = "A host exists with given host-id";
2040 LOG_DEBUG ("%s: %u", emsg, host_id);
2041 GNUNET_TESTBED_host_destroy (host);
2042 reply_size += strlen (emsg) + 1;
2043 reply = GNUNET_malloc (reply_size);
2044 memcpy (&reply[1], emsg, strlen (emsg) + 1);
2048 LOG_DEBUG ("Added host %u at %u\n",
2049 host_id, master_context->host_id);
2050 reply = GNUNET_malloc (reply_size);
2052 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM);
2053 reply->header.size = htons (reply_size);
2054 reply->host_id = htonl (host_id);
2055 queue_message (client, &reply->header);
2056 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2061 * Iterator over hash map entries.
2063 * @param cls closure
2064 * @param key current key code
2065 * @param value value in the hash map
2066 * @return GNUNET_YES if we should continue to
2071 ss_exists_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
2073 struct SharedService *queried_ss = cls;
2074 struct SharedService *ss = value;
2076 if (0 == strcmp (ss->name, queried_ss->name))
2084 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
2087 * @param client identification of the client
2088 * @param message the actual message
2091 handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client,
2092 const struct GNUNET_MessageHeader *message)
2094 const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
2095 struct SharedService *ss;
2097 struct GNUNET_HashCode hash;
2099 uint16_t service_name_size;
2101 msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
2102 msg_size = ntohs (message->size);
2103 if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
2106 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2110 msg_size - sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
2111 service_name = (char *) &msg[1];
2112 if ('\0' != service_name[service_name_size - 1])
2115 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2118 LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
2119 service_name, ntohl (msg->num_peers));
2120 if (ntohl (msg->host_id) != master_context->host_id)
2122 route_message (ntohl (msg->host_id), message);
2123 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2126 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2127 ss = GNUNET_malloc (sizeof (struct SharedService));
2128 ss->name = strdup (service_name);
2129 ss->num_shared = ntohl (msg->num_peers);
2130 GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
2131 if (GNUNET_SYSERR ==
2132 GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
2133 &ss_exists_iterator, ss))
2135 LOG (GNUNET_ERROR_TYPE_WARNING,
2136 "Service %s already configured as a shared service. "
2137 "Ignoring service sharing request \n", ss->name);
2138 GNUNET_free (ss->name);
2142 GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
2143 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2148 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
2151 * @param client identification of the client
2152 * @param message the actual message
2155 handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
2156 const struct GNUNET_MessageHeader *message)
2158 const struct GNUNET_TESTBED_ControllerLinkMessage *msg;
2159 struct GNUNET_CONFIGURATION_Handle *cfg;
2160 struct LCFContextQueue *lcfq;
2161 struct Route *route;
2162 struct Route *new_route;
2166 uint32_t delegated_host_id;
2167 uint32_t slave_host_id;
2170 if (NULL == master_context)
2173 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2176 msize = ntohs (message->size);
2177 if (sizeof (struct GNUNET_TESTBED_ControllerLinkMessage) >= msize)
2180 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2183 msg = (const struct GNUNET_TESTBED_ControllerLinkMessage *) message;
2184 delegated_host_id = ntohl (msg->delegated_host_id);
2185 if (delegated_host_id == master_context->host_id)
2188 LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
2189 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2192 if ((delegated_host_id >= host_list_size) ||
2193 (NULL == host_list[delegated_host_id]))
2195 LOG (GNUNET_ERROR_TYPE_WARNING,
2196 "Delegated host %u not registered with us\n", delegated_host_id);
2197 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2200 slave_host_id = ntohl (msg->slave_host_id);
2201 if ((slave_host_id >= host_list_size) || (NULL == host_list[slave_host_id]))
2203 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
2205 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2208 if (slave_host_id == delegated_host_id)
2210 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
2211 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2215 if (slave_host_id == master_context->host_id) /* Link from us */
2217 struct Slave *slave;
2218 struct LinkControllersContext *lcc;
2220 msize -= sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
2221 config_size = ntohs (msg->config_size);
2222 if ((delegated_host_id < slave_list_size) && (NULL != slave_list[delegated_host_id])) /* We have already added */
2224 LOG (GNUNET_ERROR_TYPE_WARNING, "Host %u already connected\n",
2226 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2229 config = GNUNET_malloc (config_size);
2230 dest_size = (uLongf) config_size;
2232 uncompress ((Bytef *) config, &dest_size, (const Bytef *) &msg[1],
2235 GNUNET_break (0); /* Compression error */
2236 GNUNET_free (config);
2237 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2240 if (config_size != dest_size)
2242 LOG (GNUNET_ERROR_TYPE_WARNING, "Uncompressed config size mismatch\n");
2243 GNUNET_free (config);
2244 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2247 cfg = GNUNET_CONFIGURATION_create (); /* Free here or in lcfcontext */
2249 GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
2251 GNUNET_break (0); /* Configuration parsing error */
2252 GNUNET_free (config);
2253 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2256 GNUNET_free (config);
2257 if ((delegated_host_id < slave_list_size) &&
2258 (NULL != slave_list[delegated_host_id]))
2260 GNUNET_break (0); /* Configuration parsing error */
2261 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2264 slave = GNUNET_malloc (sizeof (struct Slave));
2265 slave->host_id = delegated_host_id;
2266 slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
2267 slave_list_add (slave);
2268 if (1 != msg->is_subordinate)
2271 GNUNET_TESTBED_controller_connect (cfg, host_list[slave->host_id],
2273 &slave_event_callback, slave);
2275 if (NULL != slave->controller)
2276 send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
2278 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2279 "Could not connect to delegated controller");
2280 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2283 lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
2284 lcc->operation_id = GNUNET_ntohll (msg->operation_id);
2285 GNUNET_SERVER_client_keep (client);
2286 lcc->client = client;
2288 slave->controller_proc =
2289 GNUNET_TESTBED_controller_start (master_context->master_ip,
2290 host_list[slave->host_id], cfg,
2291 &slave_status_callback, slave);
2292 GNUNET_CONFIGURATION_destroy (cfg);
2293 new_route = GNUNET_malloc (sizeof (struct Route));
2294 new_route->dest = delegated_host_id;
2295 new_route->thru = master_context->host_id;
2296 route_list_add (new_route);
2300 /* Route the request */
2301 if (slave_host_id >= route_list_size)
2303 LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
2304 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2307 lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
2308 lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
2309 lcfq->lcf->delegated_host_id = delegated_host_id;
2310 lcfq->lcf->slave_host_id = slave_host_id;
2311 route = find_dest_route (slave_host_id);
2312 GNUNET_assert (NULL != route); /* because we add routes carefully */
2313 GNUNET_assert (route->dest < slave_list_size);
2314 GNUNET_assert (NULL != slave_list[route->dest]);
2315 lcfq->lcf->state = INIT;
2316 lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id);
2317 lcfq->lcf->gateway = slave_list[route->dest];
2318 lcfq->lcf->msg = GNUNET_malloc (msize);
2319 (void) memcpy (lcfq->lcf->msg, msg, msize);
2320 GNUNET_SERVER_client_keep (client);
2321 lcfq->lcf->client = client;
2322 if (NULL == lcfq_head)
2324 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
2325 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
2326 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
2329 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
2330 /* FIXME: Adding a new route should happen after the controllers are linked
2332 if (1 != msg->is_subordinate)
2334 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2337 if ((delegated_host_id < route_list_size)
2338 && (NULL != route_list[delegated_host_id]))
2340 GNUNET_break_op (0); /* Are you trying to link delegated host twice
2341 with is subordinate flag set to GNUNET_YES? */
2342 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2345 new_route = GNUNET_malloc (sizeof (struct Route));
2346 new_route->dest = delegated_host_id;
2347 new_route->thru = route->dest;
2348 route_list_add (new_route);
2349 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2354 * The task to be executed if the forwarded peer create operation has been
2357 * @param cls the FowardedOperationContext
2358 * @param tc the TaskContext from the scheduler
2361 peer_create_forward_timeout (void *cls,
2362 const struct GNUNET_SCHEDULER_TaskContext *tc)
2364 struct ForwardedOperationContext *fopc = cls;
2366 GNUNET_free (fopc->cls);
2367 forwarded_operation_timeout (fopc, tc);
2372 * Callback to be called when forwarded peer create operation is successfull. We
2373 * have to relay the reply msg back to the client
2375 * @param cls ForwardedOperationContext
2376 * @param msg the peer create success message
2379 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
2381 struct ForwardedOperationContext *fopc = cls;
2382 struct Peer *remote_peer;
2384 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS)
2386 GNUNET_assert (NULL != fopc->cls);
2387 remote_peer = fopc->cls;
2388 peer_list_add (remote_peer);
2390 forwarded_operation_reply_relay (fopc, msg);
2395 * Function to destroy a peer
2397 * @param peer the peer structure to destroy
2400 destroy_peer (struct Peer *peer)
2402 GNUNET_break (0 == peer->reference_cnt);
2403 if (GNUNET_YES == peer->is_remote)
2405 peer_list_remove (peer);
2409 if (GNUNET_YES == peer->details.local.is_running)
2411 GNUNET_TESTING_peer_stop (peer->details.local.peer);
2412 peer->details.local.is_running = GNUNET_NO;
2414 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
2415 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
2416 peer_list_remove (peer);
2422 * Callback to be called when forwarded peer destroy operation is successfull. We
2423 * have to relay the reply msg back to the client
2425 * @param cls ForwardedOperationContext
2426 * @param msg the peer create success message
2429 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
2431 struct ForwardedOperationContext *fopc = cls;
2432 struct Peer *remote_peer;
2434 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERICOPSUCCESS == ntohs (msg->type))
2436 remote_peer = fopc->cls;
2437 GNUNET_assert (NULL != remote_peer);
2438 remote_peer->destroy_flag = GNUNET_YES;
2439 if (0 == remote_peer->reference_cnt)
2440 destroy_peer (remote_peer);
2442 forwarded_operation_reply_relay (fopc, msg);
2448 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
2451 * @param client identification of the client
2452 * @param message the actual message
2455 handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
2456 const struct GNUNET_MessageHeader *message)
2458 const struct GNUNET_TESTBED_PeerCreateMessage *msg;
2459 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
2460 struct GNUNET_CONFIGURATION_Handle *cfg;
2461 struct ForwardedOperationContext *fo_ctxt;
2462 struct Route *route;
2467 uint32_t config_size;
2473 msize = ntohs (message->size);
2474 if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
2476 GNUNET_break (0); /* We need configuration */
2477 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2480 msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
2481 host_id = ntohl (msg->host_id);
2482 peer_id = ntohl (msg->peer_id);
2483 if (UINT32_MAX == peer_id)
2485 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2486 "Cannot create peer with given ID");
2487 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2490 if (host_id == master_context->host_id)
2494 /* We are responsible for this peer */
2495 msize -= sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
2496 config_size = ntohl (msg->config_size);
2497 config = GNUNET_malloc (config_size);
2498 dest_size = config_size;
2501 uncompress ((Bytef *) config, (uLongf *) & dest_size,
2502 (const Bytef *) &msg[1], (uLong) msize)))
2504 GNUNET_break (0); /* uncompression error */
2505 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2508 if (config_size != dest_size)
2510 GNUNET_break (0); /* Uncompressed config size mismatch */
2511 GNUNET_free (config);
2512 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2515 cfg = GNUNET_CONFIGURATION_create ();
2517 GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
2519 GNUNET_break (0); /* Configuration parsing error */
2520 GNUNET_free (config);
2521 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2524 GNUNET_free (config);
2525 GNUNET_CONFIGURATION_set_value_number (cfg,
2528 (unsigned long long) peer_id);
2529 peer = GNUNET_malloc (sizeof (struct Peer));
2530 peer->is_remote = GNUNET_NO;
2531 peer->details.local.cfg = cfg;
2533 LOG_DEBUG ("Creating peer with id: %u\n",
2534 (unsigned int) peer->id);
2535 peer->details.local.peer =
2536 GNUNET_TESTING_peer_configure (master_context->system,
2537 peer->details.local.cfg, peer->id,
2538 NULL /* Peer id */ ,
2540 if (NULL == peer->details.local.peer)
2542 LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
2546 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2549 peer->details.local.is_running = GNUNET_NO;
2550 peer_list_add (peer);
2552 GNUNET_malloc (sizeof
2553 (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
2554 reply->header.size =
2555 htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
2556 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS);
2557 reply->peer_id = msg->peer_id;
2558 reply->operation_id = msg->operation_id;
2559 queue_message (client, &reply->header);
2560 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2564 /* Forward peer create request */
2565 route = find_dest_route (host_id);
2569 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2573 peer = GNUNET_malloc (sizeof (struct Peer));
2574 peer->is_remote = GNUNET_YES;
2576 peer->details.remote.slave = slave_list[route->dest];
2577 peer->details.remote.remote_host_id = host_id;
2578 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2579 GNUNET_SERVER_client_keep (client);
2580 fo_ctxt->client = client;
2581 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
2582 fo_ctxt->cls = peer; //slave_list[route->dest]->controller;
2583 fo_ctxt->type = OP_PEER_CREATE;
2585 GNUNET_TESTBED_forward_operation_msg_ (slave_list [route->dest]->controller,
2586 fo_ctxt->operation_id,
2588 peer_create_success_cb, fo_ctxt);
2589 fo_ctxt->timeout_task =
2590 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &peer_create_forward_timeout,
2592 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
2593 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2598 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
2601 * @param client identification of the client
2602 * @param message the actual message
2605 handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
2606 const struct GNUNET_MessageHeader *message)
2608 const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
2609 struct ForwardedOperationContext *fopc;
2613 msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
2614 peer_id = ntohl (msg->peer_id);
2615 LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
2616 peer_id, GNUNET_ntohll (msg->operation_id));
2617 if ((peer_list_size <= peer_id) || (NULL == peer_list[peer_id]))
2619 LOG (GNUNET_ERROR_TYPE_ERROR,
2620 "Asked to destroy a non existent peer with id: %u\n", peer_id);
2621 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2622 "Peer doesn't exist");
2623 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2626 peer = peer_list[peer_id];
2627 if (GNUNET_YES == peer->is_remote)
2629 /* Forward the destory message to sub controller */
2630 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2631 GNUNET_SERVER_client_keep (client);
2632 fopc->client = client;
2634 fopc->type = OP_PEER_DESTROY;
2635 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
2637 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.slave->controller,
2638 fopc->operation_id, &msg->header,
2639 &peer_destroy_success_cb,
2641 fopc->timeout_task =
2642 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2644 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
2645 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2648 peer->destroy_flag = GNUNET_YES;
2649 if (0 == peer->reference_cnt)
2650 destroy_peer (peer);
2652 LOG (GNUNET_ERROR_TYPE_DEBUG,
2653 "Delaying peer destroy as peer is currently in use\n");
2654 send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
2655 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2660 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
2663 * @param client identification of the client
2664 * @param message the actual message
2667 handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
2668 const struct GNUNET_MessageHeader *message)
2670 const struct GNUNET_TESTBED_PeerStartMessage *msg;
2671 struct GNUNET_TESTBED_PeerEventMessage *reply;
2672 struct ForwardedOperationContext *fopc;
2676 msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
2677 peer_id = ntohl (msg->peer_id);
2678 if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
2681 LOG (GNUNET_ERROR_TYPE_ERROR,
2682 "Asked to start a non existent peer with id: %u\n", peer_id);
2683 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2686 peer = peer_list[peer_id];
2687 if (GNUNET_YES == peer->is_remote)
2689 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2690 GNUNET_SERVER_client_keep (client);
2691 fopc->client = client;
2692 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
2693 fopc->type = OP_PEER_START;
2695 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.slave->controller,
2696 fopc->operation_id, &msg->header,
2697 &forwarded_operation_reply_relay,
2699 fopc->timeout_task =
2700 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2702 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
2703 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2706 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
2708 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2710 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2713 peer->details.local.is_running = GNUNET_YES;
2714 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2715 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT);
2716 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2717 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
2718 reply->host_id = htonl (master_context->host_id);
2719 reply->peer_id = msg->peer_id;
2720 reply->operation_id = msg->operation_id;
2721 queue_message (client, &reply->header);
2722 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2727 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
2730 * @param client identification of the client
2731 * @param message the actual message
2734 handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
2735 const struct GNUNET_MessageHeader *message)
2737 const struct GNUNET_TESTBED_PeerStopMessage *msg;
2738 struct GNUNET_TESTBED_PeerEventMessage *reply;
2739 struct ForwardedOperationContext *fopc;
2743 msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
2744 peer_id = ntohl (msg->peer_id);
2745 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PEER_STOP for peer %u\n", peer_id);
2746 if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
2748 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2750 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2753 peer = peer_list[peer_id];
2754 if (GNUNET_YES == peer->is_remote)
2756 LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n", peer_id);
2757 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2758 GNUNET_SERVER_client_keep (client);
2759 fopc->client = client;
2760 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
2761 fopc->type = OP_PEER_STOP;
2763 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.slave->controller,
2764 fopc->operation_id, &msg->header,
2765 &forwarded_operation_reply_relay,
2767 fopc->timeout_task =
2768 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2770 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
2771 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2774 if (GNUNET_OK != GNUNET_TESTING_peer_stop (peer->details.local.peer))
2776 LOG (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %u failed\n", peer_id);
2777 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2778 "Peer not running");
2779 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2782 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer %u successfully stopped\n", peer_id);
2783 peer->details.local.is_running = GNUNET_NO;
2784 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2785 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT);
2786 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2787 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
2788 reply->host_id = htonl (master_context->host_id);
2789 reply->peer_id = msg->peer_id;
2790 reply->operation_id = msg->operation_id;
2791 queue_message (client, &reply->header);
2792 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2797 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
2800 * @param client identification of the client
2801 * @param message the actual message
2804 handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
2805 const struct GNUNET_MessageHeader *message)
2807 const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
2808 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
2817 msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
2818 peer_id = ntohl (msg->peer_id);
2819 if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
2821 send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2823 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2826 peer = peer_list[peer_id];
2827 if (GNUNET_YES == peer->is_remote)
2829 struct ForwardedOperationContext *fopc;
2831 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", peer_id);
2832 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2833 GNUNET_SERVER_client_keep (client);
2834 fopc->client = client;
2835 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
2836 fopc->type = OP_PEER_INFO;
2838 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.slave->controller,
2839 fopc->operation_id, &msg->header,
2840 &forwarded_operation_reply_relay,
2842 fopc->timeout_task =
2843 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2845 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
2846 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2849 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", peer_id);
2851 GNUNET_CONFIGURATION_serialize (peer_list[peer_id]->details.local.cfg,
2853 xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
2854 GNUNET_free (config);
2857 sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
2858 reply = GNUNET_realloc (xconfig, msize);
2859 (void) memmove (&reply[1], reply, xc_size);
2860 reply->header.size = htons (msize);
2861 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG);
2862 reply->peer_id = msg->peer_id;
2863 reply->operation_id = msg->operation_id;
2864 GNUNET_TESTING_peer_get_identity (peer_list[peer_id]->details.local.peer,
2865 &reply->peer_identity);
2866 reply->config_size = htons ((uint16_t) c_size);
2867 queue_message (client, &reply->header);
2868 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2873 * Cleanup overlay connect context structure
2875 * @param occ the overlay connect context
2878 cleanup_occ (struct OverlayConnectContext *occ)
2880 LOG_DEBUG ("0x%llx: Cleaning up occ\n", occ->op_id);
2881 GNUNET_free_non_null (occ->emsg);
2882 GNUNET_free_non_null (occ->hello);
2883 GNUNET_SERVER_client_drop (occ->client);
2884 if (NULL != occ->opc)
2885 GNUNET_TESTBED_forward_operation_msg_cancel_ (occ->opc);
2886 if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
2887 GNUNET_SCHEDULER_cancel (occ->send_hello_task);
2888 if (GNUNET_SCHEDULER_NO_TASK != occ->cleanup_task)
2889 GNUNET_SCHEDULER_cancel (occ->cleanup_task);
2890 if (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task)
2891 GNUNET_SCHEDULER_cancel (occ->timeout_task);
2892 if (NULL != occ->ch)
2894 GNUNET_CORE_disconnect (occ->ch);
2895 occ->peer->reference_cnt--;
2897 if (NULL != occ->ghh)
2898 GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
2899 if (NULL != occ->ohh)
2900 GNUNET_TRANSPORT_offer_hello_cancel (occ->ohh);
2901 if (GNUNET_SCHEDULER_NO_TASK != occ->tcc.task)
2902 GNUNET_SCHEDULER_cancel (occ->tcc.task);
2903 if (NULL != occ->tcc.tch)
2904 GNUNET_TRANSPORT_try_connect_cancel (occ->tcc.tch);
2905 if (NULL != occ->p1th)
2907 GNUNET_TRANSPORT_disconnect (occ->p1th);
2908 occ->peer->reference_cnt--;
2910 if (NULL != occ->tcc.th)
2912 GNUNET_TRANSPORT_disconnect (occ->tcc.th);
2913 peer_list[occ->other_peer_id]->reference_cnt--;
2915 if ((GNUNET_YES == occ->peer->destroy_flag)
2916 && (0 == occ->peer->reference_cnt))
2917 destroy_peer (occ->peer);
2918 if ((NULL == occ->peer2_controller)
2919 && (GNUNET_YES == peer_list[occ->other_peer_id]->destroy_flag)
2920 && (0 == peer_list[occ->other_peer_id]->reference_cnt))
2921 destroy_peer (peer_list[occ->other_peer_id]);
2922 GNUNET_CONTAINER_DLL_remove (occq_head, occq_tail, occ);
2928 * Task for cleaing up overlay connect context structure
2930 * @param cls the overlay connect context
2931 * @param tc the task context
2934 do_cleanup_occ (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2936 struct OverlayConnectContext *occ = cls;
2938 occ->cleanup_task = GNUNET_SCHEDULER_NO_TASK;
2944 * Task which will be run when overlay connect request has been timed out
2946 * @param cls the OverlayConnectContext
2947 * @param tc the TaskContext
2950 timeout_overlay_connect (void *cls,
2951 const struct GNUNET_SCHEDULER_TaskContext *tc)
2953 struct OverlayConnectContext *occ = cls;
2955 occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2956 LOG (GNUNET_ERROR_TYPE_WARNING,
2957 "0x%llx: Timeout while connecting peers %u and %u\n",
2958 occ->op_id, occ->peer_id, occ->other_peer_id);
2959 send_operation_fail_msg (occ->client, occ->op_id, occ->emsg);
2966 * Function called to notify transport users that another
2967 * peer connected to us.
2969 * @param cls closure
2970 * @param new_peer the peer that connected
2971 * @param ats performance data
2972 * @param ats_count number of entries in ats (excluding 0-termination)
2975 overlay_connect_notify (void *cls, const struct GNUNET_PeerIdentity *new_peer,
2976 const struct GNUNET_ATS_Information *ats,
2977 unsigned int ats_count)
2979 struct OverlayConnectContext *occ = cls;
2980 struct GNUNET_TESTBED_ConnectionEventMessage *msg;
2982 char *other_peer_str;
2984 //LOG_DEBUG ("Overlay connect notify\n");
2986 memcmp (new_peer, &occ->peer_identity,
2987 sizeof (struct GNUNET_PeerIdentity)))
2989 new_peer_str = GNUNET_strdup (GNUNET_i2s (new_peer));
2990 other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
2992 memcmp (new_peer, &occ->other_peer_identity,
2993 sizeof (struct GNUNET_PeerIdentity)))
2995 /* LOG_DEBUG ("Unexpected peer %4s connected when expecting peer %4s\n", */
2996 /* new_peer_str, other_peer_str); */
2997 GNUNET_free (new_peer_str);
2998 GNUNET_free (other_peer_str);
3001 GNUNET_free (new_peer_str);
3002 LOG_DEBUG ("0x%llx: Peer %4s connected to peer %4s\n", occ->op_id,
3003 other_peer_str, GNUNET_i2s (&occ->peer_identity));
3004 GNUNET_free (other_peer_str);
3005 if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
3007 GNUNET_SCHEDULER_cancel (occ->send_hello_task);
3008 occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
3010 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
3011 GNUNET_SCHEDULER_cancel (occ->timeout_task);
3012 occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3013 if (GNUNET_SCHEDULER_NO_TASK != occ->tcc.task)
3015 GNUNET_SCHEDULER_cancel (occ->tcc.task);
3016 occ->tcc.task = GNUNET_SCHEDULER_NO_TASK;
3018 GNUNET_free_non_null (occ->emsg);
3020 LOG_DEBUG ("0x%llx: Peers connected - Sending overlay connect success\n",
3022 msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
3024 htons (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
3025 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONEVENT);
3026 msg->event_type = htonl (GNUNET_TESTBED_ET_CONNECT);
3027 msg->peer1 = htonl (occ->peer_id);
3028 msg->peer2 = htonl (occ->other_peer_id);
3029 msg->operation_id = GNUNET_htonll (occ->op_id);
3030 queue_message (occ->client, &msg->header);
3031 occ->cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup_occ, occ);
3032 //cleanup_occ (occ);
3037 * Task to ask transport of a peer to connect to another peer
3039 * @param cls the TryConnectContext
3040 * @param tc the scheduler task context
3043 try_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
3047 * Callback to be called with result of the try connect request.
3049 * @param cls the overlay connect context
3050 * @param result GNUNET_OK if message was transmitted to transport service
3051 * GNUNET_SYSERR if message was not transmitted to transport service
3054 try_connect_cb (void *cls, const int result)
3056 struct TryConnectContext *tcc = cls;
3059 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == tcc->task);
3060 tcc->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
3061 (GNUNET_TIME_UNIT_MILLISECONDS,
3062 500 + pow(2, ++tcc->retries)),
3063 &try_connect_task, tcc);
3068 * Task to ask transport of a peer to connect to another peer
3070 * @param cls the TryConnectContext
3071 * @param tc the scheduler task context
3074 try_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3076 struct TryConnectContext *tcc = cls;
3078 tcc->task = GNUNET_SCHEDULER_NO_TASK;
3079 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
3081 GNUNET_assert (NULL == tcc->tch);
3082 GNUNET_assert (NULL != tcc->pid);
3083 GNUNET_assert (NULL != tcc->th);
3084 LOG_DEBUG ("0x%llx: Trail %u to connect to peer %s\n", tcc->op_id, tcc->retries,
3085 GNUNET_i2s(tcc->pid));
3086 tcc->tch = GNUNET_TRANSPORT_try_connect (tcc->th, tcc->pid, &try_connect_cb, tcc);
3091 * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
3094 * @param cls the OverlayConnectContext
3095 * @param tc the TaskContext from scheduler
3098 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
3102 * Task that is run when hello has been sent
3104 * @param cls the overlay connect context
3105 * @param tc the scheduler task context; if tc->reason =
3106 * GNUNET_SCHEDULER_REASON_TIMEOUT then sending HELLO failed; if
3107 * GNUNET_SCHEDULER_REASON_READ_READY is succeeded
3110 occ_hello_sent_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3112 struct OverlayConnectContext *occ = cls;
3115 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == occ->send_hello_task);
3116 if (GNUNET_SCHEDULER_REASON_TIMEOUT == tc->reason)
3118 GNUNET_free_non_null (occ->emsg);
3119 GNUNET_asprintf (&occ->emsg,
3120 "0x%llx: Timeout while offering HELLO to other peer",
3122 occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
3125 if (GNUNET_SCHEDULER_REASON_READ_READY != tc->reason)
3127 GNUNET_free_non_null (occ->emsg);
3128 GNUNET_asprintf (&occ->emsg, "0x%llx: Timeout while try connect",
3130 occ->tcc.pid = &occ->peer_identity;
3131 occ->tcc.op_id = occ->op_id;
3132 occ->tcc.task = GNUNET_SCHEDULER_add_now (&try_connect_task, &occ->tcc);
3137 * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
3140 * @param cls the OverlayConnectContext
3141 * @param tc the TaskContext from scheduler
3144 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3146 struct OverlayConnectContext *occ = cls;
3147 char *other_peer_str;
3149 occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
3150 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
3152 GNUNET_assert (NULL != occ->hello);
3153 other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
3154 if (NULL != occ->peer2_controller)
3156 struct GNUNET_TESTBED_RequestConnectMessage *msg;
3158 uint16_t hello_size;
3160 LOG_DEBUG ("0x%llx: Offering HELLO of %s (size: %u) to %s via Remote "
3161 "Overlay Request\n",
3163 GNUNET_i2s (&occ->peer_identity),
3164 ntohs (occ->hello->size),
3166 hello_size = ntohs (occ->hello->size);
3167 msize = sizeof (struct GNUNET_TESTBED_RequestConnectMessage) + hello_size;
3168 msg = GNUNET_malloc (msize);
3169 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT);
3170 msg->header.size = htons (msize);
3171 msg->peer = htonl (occ->other_peer_id);
3172 msg->operation_id = GNUNET_htonll (occ->op_id);
3173 (void) memcpy (&msg->peer_identity, &occ->peer_identity,
3174 sizeof (struct GNUNET_PeerIdentity));
3175 memcpy (msg->hello, occ->hello, hello_size);
3176 GNUNET_TESTBED_queue_message_ (occ->peer2_controller, &msg->header);
3180 LOG_DEBUG ("0x%llx: Offering HELLO of %s to %s\n",
3182 GNUNET_i2s (&occ->peer_identity), other_peer_str);
3183 occ->ohh = GNUNET_TRANSPORT_offer_hello (occ->tcc.th,
3187 if (NULL == occ->ohh)
3190 occ->send_hello_task =
3191 GNUNET_SCHEDULER_add_delayed
3192 (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
3193 100 + GNUNET_CRYPTO_random_u32
3194 (GNUNET_CRYPTO_QUALITY_WEAK, 500)),
3198 GNUNET_free (other_peer_str);
3203 * Connects to the transport of the other peer if it is a local peer and
3204 * schedules the send hello task
3206 * @param occ the overlay connect context
3209 p2_transport_connect (struct OverlayConnectContext *occ)
3211 GNUNET_assert (NULL == occ->emsg);
3212 GNUNET_assert (NULL != occ->hello);
3213 GNUNET_assert (NULL == occ->ghh);
3214 GNUNET_assert (NULL == occ->p1th);
3215 if (NULL == occ->peer2_controller)
3217 peer_list[occ->other_peer_id]->reference_cnt++;
3219 GNUNET_TRANSPORT_connect (peer_list[occ->other_peer_id]->details.local.cfg,
3220 &occ->other_peer_identity, NULL, NULL, NULL,
3222 if (NULL == occ->tcc.th)
3224 GNUNET_asprintf (&occ->emsg, "0x%llx: Cannot connect to TRANSPORT of %s",
3225 occ->op_id, GNUNET_i2s (&occ->other_peer_identity));
3226 GNUNET_SCHEDULER_cancel (occ->timeout_task);
3227 occ->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
3231 GNUNET_asprintf (&occ->emsg, "0x%llx: Timeout while offering HELLO to %s",
3232 occ->op_id, GNUNET_i2s (&occ->other_peer_identity));
3233 occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
3238 * Test for checking whether HELLO message is empty
3240 * @param cls empty flag to set
3241 * @param address the HELLO
3242 * @param expiration expiration of the HELLO
3246 test_address (void *cls, const struct GNUNET_HELLO_Address *address,
3247 struct GNUNET_TIME_Absolute expiration)
3257 * Function called whenever there is an update to the HELLO of peers in the
3258 * OverlayConnectClosure. If we have a valid HELLO, we connect to the peer 2's
3259 * transport and offer peer 1's HELLO and ask peer 2 to connect to peer 1
3261 * @param cls closure
3262 * @param hello our updated HELLO
3265 hello_update_cb (void *cls, const struct GNUNET_MessageHeader *hello)
3267 struct OverlayConnectContext *occ = cls;
3271 msize = ntohs (hello->size);
3273 (void) GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *)
3274 hello, GNUNET_NO, &test_address,
3276 if (GNUNET_YES == empty)
3278 LOG_DEBUG ("0x%llx: HELLO of %s is empty\n",
3279 occ->op_id, GNUNET_i2s (&occ->peer_identity));
3282 LOG_DEBUG ("0x%llx: Received HELLO of %s\n",
3283 occ->op_id, GNUNET_i2s (&occ->peer_identity));
3284 occ->hello = GNUNET_malloc (msize);
3285 hello_cache_add (&occ->peer_identity, hello);
3286 memcpy (occ->hello, hello, msize);
3287 GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
3289 GNUNET_TRANSPORT_disconnect (occ->p1th);
3291 occ->peer->reference_cnt--;
3292 GNUNET_free_non_null (occ->emsg);
3294 p2_transport_connect (occ);
3299 * Function called after GNUNET_CORE_connect has succeeded (or failed
3300 * for good). Note that the private key of the peer is intentionally
3301 * not exposed here; if you need it, your process should try to read
3302 * the private key file directly (which should work if you are
3305 * @param cls closure
3306 * @param server handle to the server, NULL if we failed
3307 * @param my_identity ID of this peer, NULL if we failed
3310 core_startup_cb (void *cls, struct GNUNET_CORE_Handle *server,
3311 const struct GNUNET_PeerIdentity *my_identity)
3313 struct OverlayConnectContext *occ = cls;
3314 const struct GNUNET_MessageHeader *hello;
3316 GNUNET_free_non_null (occ->emsg);
3317 (void) GNUNET_asprintf (&occ->emsg,
3318 "0x%llx: Failed to connect to CORE of peer with"
3319 "id: %u", occ->op_id, occ->peer_id);
3320 if ((NULL == server) || (NULL == my_identity))
3322 GNUNET_free (occ->emsg);
3325 memcpy (&occ->peer_identity, my_identity,
3326 sizeof (struct GNUNET_PeerIdentity));
3327 LOG_DEBUG ("0x%llx: Acquiring HELLO of peer %s\n",
3328 occ->op_id, GNUNET_i2s (&occ->peer_identity));
3329 /* Lookup for HELLO in hello cache */
3330 if (NULL != (hello = hello_cache_lookup (&occ->peer_identity)))
3332 LOG_DEBUG ("0x%llx: HELLO of peer %s found in cache\n",
3333 occ->op_id, GNUNET_i2s (&occ->peer_identity));
3334 occ->hello = GNUNET_copy_message (hello);
3335 p2_transport_connect (occ);
3338 occ->peer->reference_cnt++;
3340 GNUNET_TRANSPORT_connect (occ->peer->details.local.cfg,
3341 &occ->peer_identity, NULL, NULL, NULL, NULL);
3342 if (NULL == occ->p1th)
3344 GNUNET_asprintf (&occ->emsg,
3345 "0x%llx: Cannot connect to TRANSPORT of peer %4s",
3346 occ->op_id, GNUNET_i2s (&occ->peer_identity));
3349 GNUNET_asprintf (&occ->emsg,
3350 "0x%llx: Timeout while acquiring HELLO of peer %4s",
3351 occ->op_id, GNUNET_i2s (&occ->peer_identity));
3352 occ->ghh = GNUNET_TRANSPORT_get_hello (occ->p1th, &hello_update_cb, occ);
3356 GNUNET_SCHEDULER_cancel (occ->timeout_task);
3357 occ->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
3363 * Callback to be called when forwarded get peer config operation as part of
3364 * overlay connect is successfull. Connection to Peer 1's core is made and is
3365 * checked for new connection from peer 2
3367 * @param cls ForwardedOperationContext
3368 * @param msg the peer create success message
3371 overlay_connect_get_config (void *cls, const struct GNUNET_MessageHeader *msg)
3373 struct OverlayConnectContext *occ = cls;
3374 const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *cmsg;
3375 const struct GNUNET_CORE_MessageHandler no_handlers[] = {
3380 if (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG != ntohs (msg->type))
3382 cmsg = (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *)
3384 memcpy (&occ->other_peer_identity, &cmsg->peer_identity,
3385 sizeof (struct GNUNET_PeerIdentity));
3386 GNUNET_free_non_null (occ->emsg);
3387 GNUNET_asprintf (&occ->emsg, "0x%llx: Timeout while connecting to CORE",
3389 occ->peer->reference_cnt++;
3391 GNUNET_CORE_connect (occ->peer->details.local.cfg, occ, &core_startup_cb,
3392 &overlay_connect_notify, NULL, NULL, GNUNET_NO, NULL,
3393 GNUNET_NO, no_handlers);
3394 if (NULL == occ->ch)
3399 GNUNET_SCHEDULER_cancel (occ->timeout_task);
3401 GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
3406 * Callback which will be called to after a host registration succeeded or failed
3408 * @param cls the RegisteredHostContext
3409 * @param emsg the error message; NULL if host registration is successful
3412 registeredhost_registration_completion (void *cls, const char *emsg)
3414 struct RegisteredHostContext *rhc = cls;
3415 struct GNUNET_CONFIGURATION_Handle *cfg;
3416 uint32_t peer2_host_id;
3418 /* if (NULL != rhc->focc_dll_head) */
3419 /* process_next_focc (rhc); */
3420 peer2_host_id = GNUNET_TESTBED_host_get_id_ (rhc->reg_host);
3421 GNUNET_assert (RHC_INIT == rhc->state);
3422 GNUNET_assert (NULL == rhc->sub_op);
3423 if ((NULL == rhc->gateway2)
3424 || ((peer2_host_id < slave_list_size) /* Check if we have the needed config */
3425 && (NULL != slave_list[peer2_host_id])))
3427 rhc->state = RHC_LINK;
3428 cfg = (NULL == rhc->gateway2) ? our_config : slave_list[peer2_host_id]->cfg;
3430 GNUNET_TESTBED_controller_link (rhc,
3431 rhc->gateway->controller,
3438 rhc->state = RHC_GET_CFG;
3439 rhc->sub_op = GNUNET_TESTBED_get_slave_config (rhc,
3440 rhc->gateway2->controller,
3446 * Iterator to match a registered host context
3448 * @param cls pointer 2 pointer of RegisteredHostContext
3449 * @param key current key code
3450 * @param value value in the hash map
3451 * @return GNUNET_YES if we should continue to
3456 reghost_match_iterator (void *cls,
3457 const struct GNUNET_HashCode * key,
3460 struct RegisteredHostContext **rh = cls;
3461 struct RegisteredHostContext *rh_val = value;
3463 if ((rh_val->host == (*rh)->host) && (rh_val->reg_host == (*rh)->reg_host))
3474 * Function to generate the hashcode corresponding to a RegisteredHostContext
3476 * @param reg_host the host which is being registered in RegisteredHostContext
3477 * @param host the host of the controller which has to connect to the above rhost
3478 * @return the hashcode
3480 static struct GNUNET_HashCode
3481 hash_hosts (struct GNUNET_TESTBED_Host *reg_host,
3482 struct GNUNET_TESTBED_Host *host)
3484 struct GNUNET_HashCode hash;
3485 uint32_t host_ids[2];
3487 host_ids[0] = GNUNET_TESTBED_host_get_id_ (reg_host);
3488 host_ids[1] = GNUNET_TESTBED_host_get_id_ (host);
3489 GNUNET_CRYPTO_hash (host_ids, sizeof (host_ids), &hash);
3495 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT messages
3498 * @param client identification of the client
3499 * @param message the actual message
3502 handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
3503 const struct GNUNET_MessageHeader *message)
3505 const struct GNUNET_TESTBED_OverlayConnectMessage *msg;
3506 const struct GNUNET_CORE_MessageHandler no_handlers[] = {
3510 struct OverlayConnectContext *occ;
3511 struct GNUNET_TESTBED_Controller *peer2_controller;
3512 uint64_t operation_id;
3515 uint32_t peer2_host_id;
3517 msg = (const struct GNUNET_TESTBED_OverlayConnectMessage *) message;
3518 p1 = ntohl (msg->peer1);
3519 p2 = ntohl (msg->peer2);
3520 peer2_host_id = ntohl (msg->peer2_host_id);
3521 GNUNET_assert (p1 < peer_list_size);
3522 GNUNET_assert (NULL != peer_list[p1]);
3523 peer = peer_list[p1];
3524 operation_id = GNUNET_ntohll (msg->operation_id);
3525 LOG_DEBUG ("Received overlay connect for peers %u and %u with op id: 0x%llx\n",
3526 p1, p2, operation_id);
3527 if (GNUNET_YES == peer->is_remote)
3529 struct ForwardedOperationContext *fopc;
3530 struct Route *route_to_peer2_host;
3531 struct Route *route_to_peer1_host;
3533 LOG_DEBUG ("0x%llx: Forwarding overlay connect\n", operation_id);
3534 route_to_peer2_host = NULL;
3535 route_to_peer1_host = NULL;
3536 route_to_peer2_host = find_dest_route (peer2_host_id);
3537 if ((NULL != route_to_peer2_host)
3538 || (peer2_host_id == master_context->host_id))
3540 /* Peer 2 either below us OR with us */
3541 route_to_peer1_host =
3542 find_dest_route (peer_list[p1]->details.remote.remote_host_id);
3543 /* Because we get this message only if we know where peer 1 is */
3544 GNUNET_assert (NULL != route_to_peer1_host);
3545 if ((peer2_host_id == master_context->host_id)
3546 || (route_to_peer2_host->dest != route_to_peer1_host->dest))
3548 /* Peer2 is either with us OR peer1 and peer2 can be reached through
3549 different gateways */
3550 struct GNUNET_HashCode hash;
3551 struct RegisteredHostContext *rhc;
3554 rhc = GNUNET_malloc (sizeof (struct RegisteredHostContext));
3555 if (NULL != route_to_peer2_host)
3556 rhc->reg_host = host_list[route_to_peer2_host->dest];
3558 rhc->reg_host = host_list[master_context->host_id];
3559 rhc->host = host_list[route_to_peer1_host->dest];
3560 GNUNET_assert (NULL != rhc->reg_host);
3561 GNUNET_assert (NULL != rhc->host);
3562 rhc->gateway = peer->details.remote.slave;
3563 rhc->gateway2 = (NULL == route_to_peer2_host) ? NULL :
3564 slave_list[route_to_peer2_host->dest];
3565 rhc->state = RHC_INIT;
3566 GNUNET_SERVER_client_keep (client);
3567 rhc->client = client;
3568 hash = hash_hosts (rhc->reg_host, rhc->host);
3569 skip_focc = GNUNET_NO;
3571 GNUNET_CONTAINER_multihashmap_contains
3572 (peer->details.remote.slave->reghost_map, &hash))
3573 || (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_get_multiple
3574 (peer->details.remote.slave->reghost_map, &hash,
3575 reghost_match_iterator, &rhc)))
3577 /* create and add a new registerd host context */
3578 /* add the focc to its queue */
3579 GNUNET_CONTAINER_multihashmap_put
3580 (peer->details.remote.slave->reghost_map,
3581 &hash, rhc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3582 GNUNET_assert (NULL != host_list[peer2_host_id]);
3583 queue_host_registration (peer->details.remote.slave,
3584 registeredhost_registration_completion, rhc,
3585 host_list[peer2_host_id]);
3588 /* rhc is now set to the existing one from the hash map by
3589 reghost_match_iterator() */
3590 /* if queue is empty then ignore creating focc and proceed with
3591 normal forwarding */
3592 if (RHC_OL_CONNECT == rhc->state)
3593 skip_focc = GNUNET_YES;
3595 if (GNUNET_NO == skip_focc)
3597 struct ForwardedOverlayConnectContext *focc;
3599 focc = GNUNET_malloc (sizeof (struct ForwardedOverlayConnectContext));
3602 focc->peer2_host_id = peer2_host_id;
3603 focc->orig_msg = GNUNET_copy_message (message);
3604 focc->operation_id = operation_id;
3605 GNUNET_CONTAINER_DLL_insert_tail (rhc->focc_dll_head,
3608 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3613 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
3614 GNUNET_SERVER_client_keep (client);
3615 fopc->client = client;
3616 fopc->operation_id = operation_id;
3617 fopc->type = OP_OVERLAY_CONNECT;
3619 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.slave->controller,
3620 operation_id, message,
3621 &forwarded_operation_reply_relay,
3623 fopc->timeout_task =
3624 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
3626 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
3627 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3631 peer2_controller = NULL;
3632 if ((p2 >= peer_list_size) || (NULL == peer_list[p2]))
3634 if ((peer2_host_id >= slave_list_size)
3635 || (NULL ==slave_list[peer2_host_id]))
3637 LOG (GNUNET_ERROR_TYPE_WARNING,
3638 "0x%llx: Configuration of peer2's controller missing for connecting peers"
3639 "%u and %u\n", operation_id, p1, p2);
3640 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3643 peer2_controller = slave_list[peer2_host_id]->controller;
3644 if (NULL == peer2_controller)
3646 GNUNET_break (0); /* What's going on? */
3647 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3653 if (GNUNET_YES == peer_list[p2]->is_remote)
3654 peer2_controller = peer_list[p2]->details.remote.slave->controller;
3656 occ = GNUNET_malloc (sizeof (struct OverlayConnectContext));
3657 GNUNET_CONTAINER_DLL_insert_tail (occq_head, occq_tail, occ);
3658 GNUNET_SERVER_client_keep (client);
3659 occ->client = client;
3661 occ->other_peer_id = p2;
3662 occ->peer = peer_list[p1];
3663 occ->op_id = GNUNET_ntohll (msg->operation_id);
3664 occ->peer2_controller = peer2_controller;
3665 /* Get the identity of the second peer */
3666 if (NULL != occ->peer2_controller)
3668 struct GNUNET_TESTBED_PeerGetConfigurationMessage cmsg;
3671 htons (sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
3672 cmsg.header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG);
3673 cmsg.peer_id = msg->peer2;
3674 cmsg.operation_id = msg->operation_id;
3676 GNUNET_TESTBED_forward_operation_msg_ (occ->peer2_controller,
3677 occ->op_id, &cmsg.header,
3678 &overlay_connect_get_config,
3680 GNUNET_asprintf (&occ->emsg,
3681 "0x%llx: Timeout while getting peer identity of peer "
3682 "with id: %u", occ->op_id, occ->other_peer_id);
3684 GNUNET_SCHEDULER_add_delayed (TIMEOUT,
3685 &timeout_overlay_connect, occ);
3686 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3689 GNUNET_TESTING_peer_get_identity (peer_list[occ->other_peer_id]->details.local.peer,
3690 &occ->other_peer_identity);
3691 /* Connect to the core of 1st peer and wait for the 2nd peer to connect */
3692 occ->emsg = GNUNET_strdup ("Timeout while connecting to CORE");
3693 GNUNET_asprintf (&occ->emsg,
3694 "0x%llx: Timeout while connecting to CORE of peer with "
3695 "id: %u", occ->op_id, occ->peer_id);
3696 occ->peer->reference_cnt++;
3698 GNUNET_CORE_connect (occ->peer->details.local.cfg, occ, &core_startup_cb,
3699 &overlay_connect_notify, NULL, NULL, GNUNET_NO, NULL,
3700 GNUNET_NO, no_handlers);
3701 if (NULL == occ->ch)
3703 GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
3706 GNUNET_SCHEDULER_add_delayed (TIMEOUT,
3707 &timeout_overlay_connect, occ);
3708 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3713 * Function to cleanup RequestOverlayConnectContext and any associated tasks
3716 * @param rocc the RequestOverlayConnectContext
3719 cleanup_rocc (struct RequestOverlayConnectContext *rocc)
3721 LOG_DEBUG ("0x%llx: Cleaning up rocc\n", rocc->op_id);
3722 if (GNUNET_SCHEDULER_NO_TASK != rocc->attempt_connect_task_id)
3723 GNUNET_SCHEDULER_cancel (rocc->attempt_connect_task_id);
3724 if (GNUNET_SCHEDULER_NO_TASK != rocc->timeout_rocc_task_id)
3725 GNUNET_SCHEDULER_cancel (rocc->timeout_rocc_task_id);
3726 if (NULL != rocc->ohh)
3727 GNUNET_TRANSPORT_offer_hello_cancel (rocc->ohh);
3728 if (NULL != rocc->tcc.tch)
3729 GNUNET_TRANSPORT_try_connect_cancel (rocc->tcc.tch);
3730 if (GNUNET_SCHEDULER_NO_TASK != rocc->tcc.task)
3731 GNUNET_SCHEDULER_cancel (rocc->tcc.task);
3732 GNUNET_TRANSPORT_disconnect (rocc->tcc.th);
3733 rocc->peer->reference_cnt--;
3734 if ((GNUNET_YES == rocc->peer->destroy_flag)
3735 && (0 == rocc->peer->reference_cnt))
3736 destroy_peer (rocc->peer);
3737 GNUNET_free_non_null (rocc->hello);
3738 GNUNET_CONTAINER_DLL_remove (roccq_head, roccq_tail, rocc);
3744 * Task to timeout rocc and cleanit up
3746 * @param cls the RequestOverlayConnectContext
3747 * @param tc the TaskContext from scheduler
3750 timeout_rocc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3752 struct RequestOverlayConnectContext *rocc = cls;
3754 GNUNET_assert (rocc->timeout_rocc_task_id != GNUNET_SCHEDULER_NO_TASK);
3755 rocc->timeout_rocc_task_id = GNUNET_SCHEDULER_NO_TASK;
3756 LOG_DEBUG ("0x%llx: rocc timed out\n", rocc->op_id);
3757 cleanup_rocc (rocc);
3762 * Function called to notify transport users that another
3763 * peer connected to us.
3765 * @param cls closure
3766 * @param new_peer the peer that connected
3767 * @param ats performance data
3768 * @param ats_count number of entries in ats (excluding 0-termination)
3771 transport_connect_notify (void *cls, const struct GNUNET_PeerIdentity *new_peer,
3772 const struct GNUNET_ATS_Information * ats,
3775 struct RequestOverlayConnectContext *rocc = cls;
3777 LOG_DEBUG ("0x%llx: Request Overlay connect notify\n", rocc->op_id);
3778 if (0 != memcmp (new_peer, &rocc->a_id, sizeof (struct GNUNET_PeerIdentity)))
3780 LOG_DEBUG ("0x%llx: Peer %4s connected\n", rocc->op_id,
3781 GNUNET_i2s (&rocc->a_id));
3782 cleanup_rocc (rocc);
3787 * Task to offer the HELLO message to the peer and ask it to connect to the peer
3788 * whose identity is in RequestOverlayConnectContext
3790 * @param cls the RequestOverlayConnectContext
3791 * @param tc the TaskContext from scheduler
3794 attempt_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
3798 * Task that is run when hello has been sent
3800 * @param cls the overlay connect context
3801 * @param tc the scheduler task context; if tc->reason =
3802 * GNUNET_SCHEDULER_REASON_TIMEOUT then sending HELLO failed; if
3803 * GNUNET_SCHEDULER_REASON_READ_READY is succeeded
3806 rocc_hello_sent_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3808 struct RequestOverlayConnectContext *rocc = cls;
3811 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rocc->attempt_connect_task_id);
3812 LOG_DEBUG ("0x%llx: HELLO of peer %4s sent to local peer with id: %u\n",
3813 rocc->op_id, GNUNET_i2s (&rocc->a_id), rocc->peer->id);
3814 if (GNUNET_SCHEDULER_REASON_TIMEOUT == tc->reason)
3817 rocc->attempt_connect_task_id =
3818 GNUNET_SCHEDULER_add_now (&attempt_connect_task,
3822 if (GNUNET_SCHEDULER_REASON_READ_READY != tc->reason)
3824 rocc->tcc.task = GNUNET_SCHEDULER_add_now (&try_connect_task, &rocc->tcc);
3829 * Task to offer the HELLO message to the peer and ask it to connect to the peer
3830 * whose identity is in RequestOverlayConnectContext
3832 * @param cls the RequestOverlayConnectContext
3833 * @param tc the TaskContext from scheduler
3836 attempt_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3838 struct RequestOverlayConnectContext *rocc = cls;
3840 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != rocc->attempt_connect_task_id);
3841 rocc->attempt_connect_task_id = GNUNET_SCHEDULER_NO_TASK;
3842 LOG_DEBUG ("0x%llx: Offering HELLO of peer %4s to local peer with id: %u\n",
3843 rocc->op_id, GNUNET_i2s (&rocc->a_id), rocc->peer->id);
3844 rocc->ohh = GNUNET_TRANSPORT_offer_hello (rocc->tcc.th, rocc->hello,
3845 rocc_hello_sent_cb, rocc);
3846 if (NULL == rocc->ohh)
3847 rocc->attempt_connect_task_id =
3848 GNUNET_SCHEDULER_add_delayed
3849 (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
3850 100 + GNUNET_CRYPTO_random_u32
3851 (GNUNET_CRYPTO_QUALITY_WEAK, 500)),
3852 &attempt_connect_task, rocc);
3857 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT messages
3860 * @param client identification of the client
3861 * @param message the actual message
3864 handle_overlay_request_connect (void *cls, struct GNUNET_SERVER_Client *client,
3865 const struct GNUNET_MessageHeader *message)
3867 const struct GNUNET_TESTBED_RequestConnectMessage *msg;
3868 struct RequestOverlayConnectContext *rocc;
3874 msize = ntohs (message->size);
3875 if (sizeof (struct GNUNET_TESTBED_RequestConnectMessage) >= msize)
3878 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3881 msg = (const struct GNUNET_TESTBED_RequestConnectMessage *) message;
3882 if ((NULL == msg->hello) ||
3883 (GNUNET_MESSAGE_TYPE_HELLO != ntohs (msg->hello->type)))
3886 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3889 hsize = ntohs (msg->hello->size);
3890 if ((sizeof (struct GNUNET_TESTBED_RequestConnectMessage) + hsize) != msize)
3893 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3896 peer_id = ntohl (msg->peer);
3897 if ((peer_id >= peer_list_size) || (NULL == (peer = peer_list[peer_id])))
3899 GNUNET_break_op (0);
3900 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3903 if (GNUNET_YES == peer->is_remote)
3905 struct GNUNET_MessageHeader *msg2;
3907 msg2 = GNUNET_copy_message (message);
3908 GNUNET_TESTBED_queue_message_ (peer->details.remote.slave->controller, msg2);
3909 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3912 rocc = GNUNET_malloc (sizeof (struct RequestOverlayConnectContext));
3913 rocc->op_id = GNUNET_ntohll (msg->operation_id);
3914 GNUNET_CONTAINER_DLL_insert_tail (roccq_head, roccq_tail, rocc);
3915 memcpy (&rocc->a_id, &msg->peer_identity,
3916 sizeof (struct GNUNET_PeerIdentity));
3917 LOG_DEBUG ("Received request for overlay connection with op_id: 0x%llx "
3918 "from local peer %u to peer %4s with hello size: %u\n",
3921 GNUNET_i2s (&rocc->a_id),
3924 rocc->peer->reference_cnt++;
3925 rocc->tcc.op_id = rocc->op_id;
3926 rocc->tcc.th = GNUNET_TRANSPORT_connect (rocc->peer->details.local.cfg, NULL, rocc,
3927 NULL, &transport_connect_notify, NULL);
3928 if (NULL == rocc->tcc.th)
3932 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3935 rocc->tcc.pid = &rocc->a_id;
3936 rocc->hello = GNUNET_malloc (hsize);
3937 memcpy (rocc->hello, msg->hello, hsize);
3938 rocc->attempt_connect_task_id =
3939 GNUNET_SCHEDULER_add_now (&attempt_connect_task, rocc);
3940 rocc->timeout_rocc_task_id =
3941 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_rocc_task, rocc);
3942 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3947 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
3950 * @param client identification of the client
3951 * @param message the actual message
3954 handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
3955 const struct GNUNET_MessageHeader *message)
3957 struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
3958 struct Slave *slave;
3959 struct GNUNET_TESTBED_SlaveConfiguration *reply;
3963 size_t xconfig_size;
3968 msg = (struct GNUNET_TESTBED_SlaveGetConfigurationMessage *) message;
3969 slave_id = ntohl (msg->slave_id);
3970 op_id = GNUNET_ntohll (msg->operation_id);
3971 if ((slave_list_size <= slave_id) || (NULL == slave_list[slave_id]))
3973 /* FIXME: Add forwardings for this type of message here.. */
3974 send_operation_fail_msg (client, op_id, "Slave not found");
3975 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3978 slave = slave_list[slave_id];
3979 if (NULL == slave->cfg)
3981 send_operation_fail_msg (client, op_id,
3982 "Configuration not found (slave not started by me)");
3983 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3986 config = GNUNET_CONFIGURATION_serialize (slave->cfg, &config_size);
3987 xconfig_size = GNUNET_TESTBED_compress_config_ (config, config_size,
3989 GNUNET_free (config);
3990 reply_size = xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
3991 GNUNET_break (reply_size <= UINT16_MAX);
3992 GNUNET_break (config_size <= UINT16_MAX);
3993 reply = GNUNET_realloc (xconfig, reply_size);
3994 (void) memmove (&reply[1], reply, xconfig_size);
3995 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG);
3996 reply->header.size = htons ((uint16_t) reply_size);
3997 reply->slave_id = msg->slave_id;
3998 reply->operation_id = msg->operation_id;
3999 reply->config_size = htons ((uint16_t) config_size);
4000 queue_message (client, &reply->header);
4001 GNUNET_SERVER_receive_done (client, GNUNET_OK);
4006 * Iterator over hash map entries.
4008 * @param cls closure
4009 * @param key current key code
4010 * @param value value in the hash map
4011 * @return GNUNET_YES if we should continue to
4016 ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
4018 struct SharedService *ss = value;
4020 GNUNET_assert (GNUNET_YES ==
4021 GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
4022 GNUNET_free (ss->name);
4029 * Iterator for freeing hash map entries in a slave's reghost_map
4031 * @param cls handle to the slave
4032 * @param key current key code
4033 * @param value value in the hash map
4034 * @return GNUNET_YES if we should continue to
4039 reghost_free_iterator (void *cls,
4040 const struct GNUNET_HashCode * key,
4043 struct Slave *slave = cls;
4044 struct RegisteredHostContext *rhc = value;
4045 struct ForwardedOverlayConnectContext *focc;
4047 GNUNET_assert (GNUNET_YES ==
4048 GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map,
4050 while (NULL != (focc = rhc->focc_dll_head))
4052 GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head,
4055 cleanup_focc (focc);
4057 if (NULL != rhc->sub_op)
4058 GNUNET_TESTBED_operation_done (rhc->sub_op);
4059 if (NULL != rhc->client)
4060 GNUNET_SERVER_client_drop (rhc->client);
4061 GNUNET_free (value);
4067 * Task to clean up and shutdown nicely
4070 * @param tc the TaskContext from scheduler
4073 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
4075 struct LCFContextQueue *lcfq;
4076 struct OverlayConnectContext *occ;
4077 struct RequestOverlayConnectContext *rocc;
4078 struct ForwardedOperationContext *fopc;
4079 struct MessageQueue *mq_entry;
4082 shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
4083 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
4084 (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
4086 GNUNET_CONTAINER_multihashmap_destroy (ss_map);
4087 /* cleanup any remaining forwarded operations */
4088 while (NULL != (fopc = fopcq_head))
4090 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
4091 GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
4092 if (GNUNET_SCHEDULER_NO_TASK != fopc->timeout_task)
4093 GNUNET_SCHEDULER_cancel (fopc->timeout_task);
4094 GNUNET_SERVER_client_drop (fopc->client);
4097 case OP_PEER_CREATE:
4098 GNUNET_free (fopc->cls);
4102 case OP_PEER_DESTROY:
4104 case OP_OVERLAY_CONNECT:
4105 case OP_LINK_CONTROLLERS:
4106 case OP_GET_SLAVE_CONFIG:
4113 if (NULL != lcfq_head)
4115 if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
4117 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
4118 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
4121 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
4122 for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
4124 GNUNET_free (lcfq->lcf->msg);
4125 GNUNET_free (lcfq->lcf);
4126 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
4129 while (NULL != (occ = occq_head))
4131 while (NULL != (rocc = roccq_head))
4132 cleanup_rocc (rocc);
4133 /* Clear peer list */
4134 for (id = 0; id < peer_list_size; id++)
4135 if (NULL != peer_list[id])
4137 /* If destroy flag is set it means that this peer should have been
4138 destroyed by a context which we destroy before */
4139 GNUNET_break (GNUNET_NO == peer_list[id]->destroy_flag);
4140 /* counter should be zero as we free all contexts before */
4141 GNUNET_break (0 == peer_list[id]->reference_cnt);
4142 if ( (GNUNET_NO == peer_list[id]->is_remote)
4143 && (GNUNET_YES == peer_list[id]->details.local.is_running))
4144 GNUNET_TESTING_peer_kill (peer_list[id]->details.local.peer);
4146 for (id = 0; id < peer_list_size; id++)
4147 if (NULL != peer_list[id])
4149 if (GNUNET_NO == peer_list[id]->is_remote)
4151 if (GNUNET_YES == peer_list[id]->details.local.is_running)
4152 GNUNET_TESTING_peer_wait (peer_list[id]->details.local.peer);
4153 GNUNET_TESTING_peer_destroy (peer_list[id]->details.local.peer);
4154 GNUNET_CONFIGURATION_destroy (peer_list[id]->details.local.cfg);
4156 GNUNET_free (peer_list[id]);
4158 GNUNET_free_non_null (peer_list);
4159 /* Clear host list */
4160 for (id = 0; id < host_list_size; id++)
4161 if (NULL != host_list[id])
4162 GNUNET_TESTBED_host_destroy (host_list[id]);
4163 GNUNET_free_non_null (host_list);
4164 /* Clear route list */
4165 for (id = 0; id < route_list_size; id++)
4166 if (NULL != route_list[id])
4167 GNUNET_free (route_list[id]);
4168 GNUNET_free_non_null (route_list);
4169 /* Clear slave_list */
4170 for (id = 0; id < slave_list_size; id++)
4171 if (NULL != slave_list[id])
4173 struct HostRegistration *hr_entry;
4175 while (NULL != (hr_entry = slave_list[id]->hr_dll_head))
4177 GNUNET_CONTAINER_DLL_remove (slave_list[id]->hr_dll_head,
4178 slave_list[id]->hr_dll_tail,
4180 GNUNET_free (hr_entry);
4182 if (NULL != slave_list[id]->rhandle)
4183 GNUNET_TESTBED_cancel_registration (slave_list[id]->rhandle);
4184 (void) GNUNET_CONTAINER_multihashmap_iterate (slave_list[id]->reghost_map,
4185 reghost_free_iterator,
4187 GNUNET_CONTAINER_multihashmap_destroy (slave_list[id]->reghost_map);
4188 if (NULL != slave_list[id]->cfg)
4189 GNUNET_CONFIGURATION_destroy (slave_list[id]->cfg);
4190 if (NULL != slave_list[id]->controller)
4191 GNUNET_TESTBED_controller_disconnect (slave_list[id]->controller);
4192 if (NULL != slave_list[id]->controller_proc)
4193 GNUNET_TESTBED_controller_stop (slave_list[id]->controller_proc);
4194 GNUNET_free (slave_list[id]);
4196 GNUNET_free_non_null (slave_list);
4197 if (NULL != master_context)
4199 GNUNET_free_non_null (master_context->master_ip);
4200 if (NULL != master_context->system)
4201 GNUNET_TESTING_system_destroy (master_context->system, GNUNET_YES);
4202 GNUNET_SERVER_client_drop (master_context->client);
4203 GNUNET_free (master_context);
4204 master_context = NULL;
4206 if (NULL != transmit_handle)
4207 GNUNET_SERVER_notify_transmit_ready_cancel (transmit_handle);
4208 while (NULL != (mq_entry = mq_head))
4210 GNUNET_free (mq_entry->msg);
4211 GNUNET_SERVER_client_drop (mq_entry->client);
4212 GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
4213 GNUNET_free (mq_entry);
4215 GNUNET_free_non_null (hostname);
4216 GNUNET_CONFIGURATION_destroy (our_config);
4217 /* Free hello cache */
4218 if (NULL != hello_cache)
4220 (GNUNET_CONTAINER_multihashmap_size (hello_cache) <= hello_cache_size);
4221 while (NULL != lru_hcache_head)
4222 hello_cache_remove (lru_hcache_head);
4223 if (NULL != hello_cache)
4225 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (hello_cache));
4226 GNUNET_CONTAINER_multihashmap_destroy (hello_cache);
4232 * Callback for client disconnect
4235 * @param client the client which has disconnected
4238 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
4240 if (NULL == master_context)
4242 if (client == master_context->client)
4244 LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
4245 /* should not be needed as we're terminated by failure to read
4246 * from stdin, but if stdin fails for some reason, this shouldn't
4247 * hurt for now --- might need to revise this later if we ever
4248 * decide that master connections might be temporarily down
4249 * for some reason */
4250 //GNUNET_SCHEDULER_shutdown ();
4258 * @param cls closure
4259 * @param server the initialized server
4260 * @param cfg configuration to use
4263 testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
4264 const struct GNUNET_CONFIGURATION_Handle *cfg)
4266 static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
4267 {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT, 0},
4268 {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST, 0},
4269 {&handle_configure_shared_service, NULL,
4270 GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE, 0},
4271 {&handle_link_controllers, NULL,
4272 GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS, 0},
4273 {&handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER, 0},
4274 {&handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER,
4275 sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
4276 {&handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STARTPEER,
4277 sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
4278 {&handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOPPEER,
4279 sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
4280 {&handle_peer_get_config, NULL, GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG,
4281 sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
4282 {&handle_overlay_connect, NULL, GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT,
4283 sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
4284 {&handle_overlay_request_connect, NULL, GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT,
4286 {handle_slave_get_config, NULL, GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG,
4287 sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
4291 unsigned long long num;
4293 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
4298 GNUNET_break (GNUNET_OK == GNUNET_log_setup ("testbed", "DEBUG", logfile));
4299 GNUNET_free (logfile);
4301 GNUNET_assert (GNUNET_OK ==
4302 GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
4305 hello_cache_size = (unsigned int) num;
4306 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string
4307 (cfg, "testbed", "HOSTNAME", &hostname));
4308 our_config = GNUNET_CONFIGURATION_dup (cfg);
4309 GNUNET_SERVER_add_handlers (server, message_handlers);
4310 GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
4311 ss_map = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
4312 if (1 < hello_cache_size)
4313 hello_cache = GNUNET_CONTAINER_multihashmap_create (hello_cache_size / 2,
4316 GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
4317 GNUNET_SCHEDULER_PRIORITY_IDLE,
4318 &shutdown_task, NULL);
4319 LOG_DEBUG ("Testbed startup complete\n");
4320 event_mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
4325 * The starting point of execution
4328 main (int argc, char *const *argv)
4330 //sleep (15); /* Debugging */
4331 return (GNUNET_OK ==
4332 GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
4333 &testbed_run, NULL)) ? 0 : 1;
4336 /* end of gnunet-service-testbed.c */