2 This file is part of GNUnet
3 (C) 2008, 2009 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 3, 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 testing/testing_group.c
23 * @brief convenience API for writing testcases for GNUnet
24 * @author Nathan Evans
25 * @author Christian Grothoff
29 #include "gnunet_arm_service.h"
30 #include "gnunet_testing_lib.h"
31 #include "gnunet_core_service.h"
33 #define VERBOSE_TESTING GNUNET_NO
35 #define VERBOSE_TOPOLOGY GNUNET_YES
37 #define DEBUG_CHURN GNUNET_NO
40 * Lowest port used for GNUnet testing. Should be high enough to not
41 * conflict with other applications running on the hosts but be low
42 * enough to not conflict with client-ports (typically starting around
45 #define LOW_PORT 10000
48 * Highest port used for GNUnet testing. Should be low enough to not
49 * conflict with the port range for "local" ports (client apps; see
50 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
52 #define HIGH_PORT 56000
54 #define MAX_OUTSTANDING_CONNECTIONS 200
56 #define MAX_CONCURRENT_HOSTKEYS 200
58 #define MAX_CONCURRENT_STARTING 200
60 #define MAX_CONCURRENT_SHUTDOWN 100
62 #define CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 180)
64 #define CONNECT_ATTEMPTS 30
67 * Prototype of a function called whenever two peers would be connected
68 * in a certain topology.
70 typedef unsigned int (*GNUNET_TESTING_ConnectionProcessor) (struct
71 GNUNET_TESTING_PeerGroup
80 * Context for handling churning a peer group
85 * Callback used to notify of churning finished
87 GNUNET_TESTING_NotifyCompletion cb;
90 * Closure for callback
95 * Number of peers that still need to be started
97 unsigned int num_to_start;
100 * Number of peers that still need to be stopped
102 unsigned int num_to_stop;
105 * Number of peers that failed to start
107 unsigned int num_failed_start;
110 * Number of peers that failed to stop
112 unsigned int num_failed_stop;
115 struct RestartContext
118 * The group of peers being restarted
120 struct GNUNET_TESTING_PeerGroup *peer_group;
123 * How many peers have been restarted thus far
125 unsigned int peers_restarted;
128 * How many peers got an error when restarting
130 unsigned int peers_restart_failed;
133 * The function to call once all peers have been restarted
135 GNUNET_TESTING_NotifyCompletion callback;
138 * Closure for callback function
145 struct ShutdownContext
148 * Total peers to wait for
150 unsigned int total_peers;
153 * Number of peers successfully shut down
155 unsigned int peers_down;
158 * Number of peers failed to shut down
160 unsigned int peers_failed;
163 * Number of peers we have started shutting
164 * down. If too many, wait on them.
166 unsigned int outstanding;
169 * Timeout for shutdown.
171 struct GNUNET_TIME_Relative timeout;
174 * Callback to call when all peers either
175 * shutdown or failed to shutdown
177 GNUNET_TESTING_NotifyCompletion cb;
186 * Individual shutdown context for a particular peer.
188 struct PeerShutdownContext
191 * Pointer to the high level shutdown context.
193 struct ShutdownContext *shutdown_ctx;
196 * The daemon handle for the peer to shut down.
198 struct GNUNET_TESTING_Daemon *daemon;
202 * Individual shutdown context for a particular peer.
204 struct PeerRestartContext
207 * Pointer to the high level restart context.
209 struct ChurnRestartContext *churn_restart_ctx;
212 * The daemon handle for the peer to shut down.
214 struct GNUNET_TESTING_Daemon *daemon;
218 struct CreateTopologyContext
222 * Function to call with number of connections
224 GNUNET_TESTING_NotifyConnections cont;
227 * Closure for connection notification
234 /** Waiting to read number of peers */
237 /** Should find next peer index */
240 /** Should find colon */
243 /** Should read other peer index, space, or endline */
248 struct PeerConnection
253 struct PeerConnection *next;
256 * Pointer to daemon handle
258 struct GNUNET_TESTING_Daemon *daemon;
263 struct InternalStartContext
266 * Pointer to peerdata
268 struct PeerData *peer;
271 * Timeout for peer startup
273 struct GNUNET_TIME_Relative timeout;
276 * Client callback for hostkey notification
278 GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback;
281 * Closure for hostkey_callback
286 * Client callback for peer start notification
288 GNUNET_TESTING_NotifyDaemonRunning start_cb;
296 * Hostname, where to start the peer
298 const char *hostname;
301 * Username to use when connecting to the
304 const char *username;
307 * Pointer to starting memory location of a hostkey
312 * Port to use for ssh.
318 struct ChurnRestartContext
321 * Number of restarts currently in flight.
323 unsigned int outstanding;
326 * Handle to the underlying churn context.
328 struct ChurnContext *churn_ctx;
331 * How long to allow the operation to take.
333 struct GNUNET_TIME_Relative timeout;
337 * Data we keep per peer.
342 * (Initial) configuration of the host.
343 * (initial because clients could change
344 * it and we would not know about those
347 struct GNUNET_CONFIGURATION_Handle *cfg;
350 * Handle for controlling the daemon.
352 struct GNUNET_TESTING_Daemon *daemon;
355 * The peergroup this peer belongs to.
357 struct GNUNET_TESTING_PeerGroup *pg;
360 * Hash map of allowed peer connections (F2F created topology)
362 struct GNUNET_CONTAINER_MultiHashMap *allowed_peers;
365 * Hash map of blacklisted peers
367 struct GNUNET_CONTAINER_MultiHashMap *blacklisted_peers;
370 * Hash map of peer connections
372 struct GNUNET_CONTAINER_MultiHashMap *connect_peers;
375 * Temporary hash map of peer connections
377 struct GNUNET_CONTAINER_MultiHashMap *connect_peers_working_set;
380 * Temporary variable for topology creation, should be reset before
381 * creating any topology so the count is valid once finished.
386 * Context to keep track of peers being started, to
387 * stagger hostkey generation and peer startup.
389 struct InternalStartContext internal_context;
394 * Linked list of per-host data.
404 * SSH username to use when connecting to this host.
409 * SSH port to use when connecting to this host.
414 * Lowest port that we have not yet used
420 struct TopologyIterateContext
423 * Callback for notifying of two connected peers.
425 GNUNET_TESTING_NotifyTopology topology_cb;
428 * Closure for topology_cb
433 * Number of peers currently connected to.
435 unsigned int connected;
438 * Number of peers we have finished iterating.
440 unsigned int completed;
443 * Number of peers total.
448 struct StatsIterateContext
451 * Continuation to call once all stats information has been retrieved.
453 GNUNET_STATISTICS_Callback cont;
456 * Proc function to call on each value received.
458 GNUNET_TESTING_STATISTICS_Iterator proc;
461 * Closure for topology_cb
466 * Number of peers currently connected to.
468 unsigned int connected;
471 * Number of peers we have finished iterating.
473 unsigned int completed;
476 * Number of peers total.
484 struct GNUNET_TESTING_Daemon *daemon;
487 struct StatsCoreContext
490 struct GNUNET_TESTING_Daemon *daemon;
492 * Handle to the statistics service.
494 struct GNUNET_STATISTICS_Handle *stats_handle;
497 * Handle for getting statistics.
499 struct GNUNET_STATISTICS_GetHandle *stats_get_handle;
503 * Handle to a group of GNUnet peers.
505 struct GNUNET_TESTING_PeerGroup
508 * Configuration template.
510 const struct GNUNET_CONFIGURATION_Handle *cfg;
513 * Function to call on each started daemon.
515 //GNUNET_TESTING_NotifyDaemonRunning cb;
523 * Function to call on each topology connection created
525 GNUNET_TESTING_NotifyConnection notify_connection;
528 * Callback for notify_connection
530 void *notify_connection_cls;
533 * Array of information about hosts.
535 struct HostData *hosts;
538 * Number of hosts (size of HostData)
540 unsigned int num_hosts;
543 * Array of "total" peers.
545 struct PeerData *peers;
548 * Number of peers in this group.
553 * At what time should we fail the peer startup process?
555 struct GNUNET_TIME_Absolute max_timeout;
558 * How many peers are being started right now?
560 unsigned int starting;
563 * How many peers have already been started?
565 unsigned int started;
570 struct GNUNET_CONFIGURATION_Handle *ret;
571 const struct GNUNET_CONFIGURATION_Handle *orig;
572 const char *hostname;
578 struct ConnectTopologyContext
581 * How many connections are left to create.
583 unsigned int remaining_connections;
586 * Handle to group of peers.
588 struct GNUNET_TESTING_PeerGroup *pg;
591 * Temp value set for each iteration.
593 struct PeerData *first;
596 * Notification that all peers are connected.
598 GNUNET_TESTING_NotifyCompletion notify_connections_done;
601 * Closure for notify.
606 struct ConnectContext
609 * Peer to connect second to.
611 struct GNUNET_TESTING_Daemon *first;
614 * Peer to connect first to.
616 struct GNUNET_TESTING_Daemon *second;
619 * Higher level topology connection context.
621 struct ConnectTopologyContext *ct_ctx;
624 struct UnblacklistContext
629 struct GNUNET_TESTING_PeerGroup *pg;
632 * uid of the first peer
642 struct GNUNET_TESTING_PeerGroup *pg;
645 * uid of the first peer
650 * Peer data for first peer.
652 struct PeerData *first;
655 * Random percentage to use
660 struct MinimumContext
665 struct GNUNET_TESTING_PeerGroup *pg;
668 * uid of the first peer
673 * Peer data for first peer.
675 struct PeerData *first;
678 * Number of conns per peer
680 unsigned int num_to_add;
683 * Permuted array of all possible connections. Only add the Nth
684 * peer if it's in the Nth position.
686 unsigned int *pg_array;
689 * What number is the current element we are iterating over?
691 unsigned int current;
699 struct GNUNET_TESTING_PeerGroup *pg;
702 * uid of the first peer
707 * uid of the second peer
712 * Peer data for first peer.
714 struct PeerData *first;
717 * Which peer has been chosen as the one to add?
722 * What number is the current element we are iterating over?
724 unsigned int current;
728 * Convert unique ID to hash code.
730 * @param uid unique ID to convert
731 * @param hash set to uid (extended with zeros)
734 hash_from_uid (uint32_t uid, GNUNET_HashCode * hash)
736 memset (hash, 0, sizeof (GNUNET_HashCode));
737 *((uint32_t *) hash) = uid;
741 * Convert hash code to unique ID.
743 * @param uid unique ID to convert
744 * @param hash set to uid (extended with zeros)
747 uid_from_hash (const GNUNET_HashCode * hash, uint32_t * uid)
749 memcpy (uid, hash, sizeof (uint32_t));
753 * Number of connects we are waiting on, allows us to rate limit
756 static int outstanding_connects;
759 * Get a topology from a string input.
761 * @param topology where to write the retrieved topology
762 * @param topology_string The string to attempt to
763 * get a configuration value from
764 * @return GNUNET_YES if topology string matched a
765 * known topology, GNUNET_NO if not
768 GNUNET_TESTING_topology_get (enum GNUNET_TESTING_Topology *topology,
769 const char *topology_string)
772 * Strings representing topologies in enum
774 static const char *topology_strings[] = {
776 * A clique (everyone connected to everyone else).
781 * Small-world network (2d torus plus random links).
786 * Small-world network (ring plus random links).
806 * Certain percentage of peers are unable to communicate directly
807 * replicating NAT conditions
812 * Scale free topology.
817 * Straight line topology.
822 * All peers are disconnected.
827 * Read the topology from a file.
835 if (topology_string == NULL)
837 while (topology_strings[curr] != NULL)
839 if (strcasecmp (topology_strings[curr], topology_string) == 0)
846 *topology = GNUNET_TESTING_TOPOLOGY_NONE;
852 * Get connect topology option from string input.
854 * @param topology_option where to write the retrieved topology
855 * @param topology_string The string to attempt to
856 * get a configuration value from
857 * @return GNUNET_YES if string matched a known
858 * topology option, GNUNET_NO if not
861 GNUNET_TESTING_topology_option_get (enum GNUNET_TESTING_TopologyOption
863 const char *topology_string)
866 * Options for connecting a topology as strings.
868 static const char *topology_option_strings[] = {
870 * Try to connect all peers specified in the topology.
875 * Choose a random subset of connections to create.
877 "CONNECT_RANDOM_SUBSET",
880 * Create at least X connections for each peer.
885 * Using a depth first search, create one connection
886 * per peer. If any are missed (graph disconnected)
887 * start over at those peers until all have at least one
893 * Find the N closest peers to each allowed peer in the
894 * topology and make sure a connection to those peers
895 * exists in the connect topology.
900 * No options specified.
908 if (topology_string == NULL)
910 while (NULL != topology_option_strings[curr])
912 if (strcasecmp (topology_option_strings[curr], topology_string) == 0)
914 *topology_option = curr;
919 *topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_NONE;
924 * Function to iterate over options. Copies
925 * the options to the target configuration,
926 * updating PORT values as needed.
929 * @param section name of the section
930 * @param option name of the option
931 * @param value value of the option
934 update_config (void *cls,
935 const char *section, const char *option, const char *value)
937 struct UpdateContext *ctx = cls;
941 char *single_variable;
942 char *per_host_variable;
943 unsigned long long num_per_host;
945 if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival)))
947 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
950 GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing",
953 GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++);
957 GNUNET_free (single_variable);
960 if (0 == strcmp (option, "UNIXPATH"))
962 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
963 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
965 GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing",
968 GNUNET_snprintf (uval,
970 "/tmp/test-service-%s-%u", section, ctx->upnum++);
973 else if ((GNUNET_YES ==
974 GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing",
976 &num_per_host)) && (num_per_host > 0))
979 GNUNET_snprintf (uval,
981 "/tmp/test-service-%s-%u",
982 section, ctx->fdnum % num_per_host);
985 GNUNET_free (single_variable);
986 GNUNET_free (per_host_variable);
990 if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL))
992 value = ctx->hostname;
995 GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value);
1000 * Create a new configuration using the given configuration
1001 * as a template; however, each PORT in the existing cfg
1002 * must be renumbered by incrementing "*port". If we run
1003 * out of "*port" numbers, return NULL.
1005 * @param cfg template configuration
1006 * @param port port numbers to use, update to reflect
1007 * port numbers that were used
1008 * @param upnum number to make unix domain socket names unique
1009 * @param hostname hostname of the controlling host, to allow control connections from
1010 * @param fdnum number used to offset the unix domain socket for grouped processes
1011 * (such as statistics or peerinfo, which can be shared among others)
1013 * @return new configuration, NULL on error
1015 static struct GNUNET_CONFIGURATION_Handle *
1016 make_config (const struct GNUNET_CONFIGURATION_Handle *cfg,
1018 uint32_t * upnum, const char *hostname, uint32_t * fdnum)
1020 struct UpdateContext uc;
1023 char *allowed_hosts;
1029 uc.ret = GNUNET_CONFIGURATION_create ();
1030 uc.hostname = hostname;
1033 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
1034 if (uc.nport >= HIGH_PORT)
1037 GNUNET_CONFIGURATION_destroy (uc.ret);
1041 if (GNUNET_CONFIGURATION_get_value_string
1042 (cfg, "testing", "control_host", &control_host) == GNUNET_OK)
1044 if (hostname != NULL)
1045 GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1; %s;", control_host,
1048 GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", control_host);
1050 GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "ACCEPT_FROM",
1052 GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport",
1053 "ACCEPT_FROM", allowed_hosts);
1054 GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "ACCEPT_FROM",
1056 GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics",
1057 "ACCEPT_FROM", allowed_hosts);
1058 GNUNET_free_non_null (control_host);
1059 GNUNET_free (allowed_hosts);
1063 /* arm needs to know to allow connections from the host on which it is running,
1064 * otherwise gnunet-arm is unable to connect to it in some instances */
1065 if (hostname != NULL)
1067 GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", hostname);
1068 GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-udp",
1069 "BINDTO", hostname);
1070 GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-tcp",
1071 "BINDTO", hostname);
1072 GNUNET_CONFIGURATION_set_value_string (uc.ret, "arm", "ACCEPT_FROM",
1074 GNUNET_free (allowed_hosts);
1078 GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-tcp",
1079 "BINDTO", "127.0.0.1");
1080 GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-udp",
1081 "BINDTO", "127.0.0.1");
1084 *port = (uint16_t) uc.nport;
1093 * Add entries to the peers connect list
1095 * @param pg the peer group we are working with
1096 * @param first index of the first peer
1097 * @param second index of the second peer
1099 * @return the number of connections added
1100 * technically should only be 0 or 2
1104 add_actual_connections (struct GNUNET_TESTING_PeerGroup *pg,
1105 unsigned int first, unsigned int second)
1111 GNUNET_HashCode hash_first;
1112 GNUNET_HashCode hash_second;
1114 hash_from_uid (first, &hash_first);
1115 hash_from_uid (second, &hash_second);
1117 add_first = GNUNET_NO;
1119 GNUNET_CONTAINER_multihashmap_contains (pg->peers[first].connect_peers,
1122 add_first = GNUNET_YES;
1125 add_second = GNUNET_NO;
1127 GNUNET_CONTAINER_multihashmap_contains (pg->peers[second].connect_peers,
1130 add_second = GNUNET_YES;
1136 GNUNET_assert (GNUNET_OK ==
1137 GNUNET_CONTAINER_multihashmap_put (pg->
1139 [first].connect_peers,
1142 peers[second].daemon,
1143 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1144 pg->peers[first].num_connections++;
1150 GNUNET_assert (GNUNET_OK ==
1151 GNUNET_CONTAINER_multihashmap_put (pg->
1153 [second].connect_peers,
1156 peers[first].daemon,
1157 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1158 pg->peers[second].num_connections++;
1167 * Add entries to the peers allowed connections list
1169 * @param pg the peer group we are working with
1170 * @param first index of the first peer
1171 * @param second index of the second peer
1173 * @return the number of connections added (can be 0, 1 or 2)
1174 * technically should only be 0 or 2, but the small price
1175 * of iterating over the lists (hashmaps in the future)
1176 * for being sure doesn't bother me!
1180 add_allowed_connections (struct GNUNET_TESTING_PeerGroup *pg,
1181 unsigned int first, unsigned int second)
1185 struct PeerConnection *first_iter;
1186 struct PeerConnection *second_iter;
1187 struct PeerConnection *new_first;
1188 struct PeerConnection *new_second;
1193 GNUNET_HashCode hash_first;
1194 GNUNET_HashCode hash_second;
1196 hash_from_uid (first, &hash_first);
1197 hash_from_uid (second, &hash_second);
1199 add_first = GNUNET_NO;
1201 GNUNET_CONTAINER_multihashmap_contains (pg->peers[first].allowed_peers,
1204 add_first = GNUNET_YES;
1207 add_second = GNUNET_NO;
1209 GNUNET_CONTAINER_multihashmap_contains (pg->peers[second].allowed_peers,
1212 add_second = GNUNET_YES;
1215 first_iter = pg->peers[first].connected_peers;
1216 while (first_iter != NULL)
1218 if (first_iter->daemon == pg->peers[second].daemon)
1219 add_first = GNUNET_NO;
1220 first_iter = first_iter->next;
1223 second_iter = pg->peers[second].connected_peers;
1224 add_second = GNUNET_YES;
1225 while (second_iter != NULL)
1227 if (second_iter->daemon == pg->peers[first].daemon)
1228 add_second = GNUNET_NO;
1229 second_iter = second_iter->next;
1236 GNUNET_assert (GNUNET_OK ==
1237 GNUNET_CONTAINER_multihashmap_put (pg->
1239 [first].allowed_peers,
1242 peers[second].daemon,
1243 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1245 new_first = GNUNET_malloc (sizeof (struct PeerConnection));
1246 new_first->daemon = pg->peers[second].daemon;
1247 new_first->next = pg->peers[first].connected_peers;
1248 pg->peers[first].connected_peers = new_first;
1250 pg->peers[first].num_connections++;
1256 GNUNET_assert (GNUNET_OK ==
1257 GNUNET_CONTAINER_multihashmap_put (pg->
1259 [second].allowed_peers,
1262 peers[first].daemon,
1263 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1265 new_second = GNUNET_malloc (sizeof (struct PeerConnection));
1266 new_second->daemon = pg->peers[first].daemon;
1267 new_second->next = pg->peers[second].connected_peers;
1268 pg->peers[second].connected_peers = new_second;
1269 pg->peers[first].num_connections++;
1271 pg->peers[second].num_connections++;
1279 * Add entries to the peers blacklisted list
1281 * @param pg the peer group we are working with
1282 * @param first index of the first peer
1283 * @param second index of the second peer
1285 * @return the number of connections added (can be 0, 1 or 2)
1289 blacklist_connections (struct GNUNET_TESTING_PeerGroup *pg,
1290 unsigned int first, unsigned int second)
1295 GNUNET_HashCode hash_first;
1296 GNUNET_HashCode hash_second;
1298 hash_from_uid (first, &hash_first);
1299 hash_from_uid (second, &hash_second);
1301 add_first = GNUNET_NO;
1303 GNUNET_CONTAINER_multihashmap_contains (pg->
1304 peers[first].blacklisted_peers,
1307 add_first = GNUNET_YES;
1310 add_second = GNUNET_NO;
1312 GNUNET_CONTAINER_multihashmap_contains (pg->
1313 peers[second].blacklisted_peers,
1316 add_second = GNUNET_YES;
1322 GNUNET_assert (GNUNET_OK ==
1323 GNUNET_CONTAINER_multihashmap_put (pg->
1325 [first].blacklisted_peers,
1328 peers[second].daemon,
1329 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1330 pg->peers[first].num_connections++;
1336 GNUNET_assert (GNUNET_OK ==
1337 GNUNET_CONTAINER_multihashmap_put (pg->
1339 [second].blacklisted_peers,
1342 peers[first].daemon,
1343 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1344 pg->peers[second].num_connections++;
1352 * Remove entries from the peers blacklisted list
1354 * @param pg the peer group we are working with
1355 * @param first index of the first peer
1356 * @param second index of the second peer
1358 * @return the number of connections removed (can be 0, 1 or 2)
1362 unblacklist_connections (struct GNUNET_TESTING_PeerGroup *pg,
1363 unsigned int first, unsigned int second)
1368 GNUNET_HashCode hash_first;
1369 GNUNET_HashCode hash_second;
1371 hash_from_uid (first, &hash_first);
1372 hash_from_uid (second, &hash_second);
1375 GNUNET_CONTAINER_multihashmap_contains (pg->
1376 peers[first].blacklisted_peers,
1379 GNUNET_CONTAINER_multihashmap_contains (pg->
1380 peers[second].blacklisted_peers,
1386 GNUNET_assert (GNUNET_YES ==
1387 GNUNET_CONTAINER_multihashmap_remove (pg->
1389 [first].blacklisted_peers,
1399 GNUNET_assert (GNUNET_YES ==
1400 GNUNET_CONTAINER_multihashmap_remove (pg->
1402 [second].blacklisted_peers,
1414 * Scale free network construction as described in:
1416 * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999.
1418 * Start with a network of "one" peer, then progressively add
1419 * peers up to the total number. At each step, iterate over
1420 * all possible peers and connect new peer based on number of
1421 * existing connections of the target peer.
1423 * @param pg the peer group we are dealing with
1424 * @param proc the connection processor to use
1426 * @return the number of connections created
1429 create_scale_free (struct GNUNET_TESTING_PeerGroup *pg,
1430 GNUNET_TESTING_ConnectionProcessor proc)
1433 unsigned int total_connections;
1434 unsigned int outer_count;
1436 unsigned int previous_total_connections;
1440 GNUNET_assert (pg->total > 1);
1442 /* Add a connection between the first two nodes */
1443 total_connections = proc (pg, 0, 1);
1445 for (outer_count = 1; outer_count < pg->total; outer_count++)
1447 previous_total_connections = total_connections;
1448 for (i = 0; i < outer_count; i++)
1451 pg->peers[i].num_connections /
1452 (double) previous_total_connections;
1455 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
1456 UINT64_MAX)) / ((double) UINT64_MAX);
1458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1459 "Considering connecting peer %d to peer %d\n",
1462 if (random < probability)
1465 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1466 "Connecting peer %d to peer %d\n", outer_count, i);
1468 total_connections += proc (pg, outer_count, i);
1473 return total_connections;
1477 * Create a topology given a peer group (set of running peers)
1478 * and a connection processor. Creates a small world topology
1479 * according to the rewired ring construction. The basic
1480 * behavior is that a ring topology is created, but with some
1481 * probability instead of connecting a peer to the next
1482 * neighbor in the ring a connection will be created to a peer
1483 * selected uniformly at random. We use the TESTING
1484 * PERCENTAGE option to specify what number of
1485 * connections each peer should have. Default is 2,
1486 * which makes the ring, any given number is multiplied by
1487 * the log of the network size; i.e. a PERCENTAGE of 2 makes
1488 * each peer have on average 2logn connections. The additional
1489 * connections are made at increasing distance around the ring
1490 * from the original peer, or to random peers based on the re-
1491 * wiring probability. The TESTING
1492 * PROBABILITY option is used as the probability that a given
1493 * connection is rewired.
1495 * @param pg the peergroup to create the topology on
1496 * @param proc the connection processor to call to actually set
1497 * up connections between two peers
1499 * @return the number of connections that were set up
1503 create_small_world_ring (struct GNUNET_TESTING_PeerGroup *pg,
1504 GNUNET_TESTING_ConnectionProcessor proc)
1508 unsigned int natLog;
1509 unsigned int randomPeer;
1510 double random, logNModifier, probability;
1511 unsigned int smallWorldConnections;
1516 unsigned int useAnd;
1517 int connect_attempts;
1519 logNModifier = 0.5; /* FIXME: default value? */
1520 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg,
1525 if (sscanf (p_string, "%lf", &logNModifier) != 1)
1526 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1528 ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1529 p_string, "LOGNMODIFIER", "TESTING");
1530 GNUNET_free (p_string);
1532 probability = 0.5; /* FIXME: default percentage? */
1533 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg,
1538 if (sscanf (p_string, "%lf", &probability) != 1)
1539 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1541 ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1542 p_string, "PERCENTAGE", "TESTING");
1543 GNUNET_free (p_string);
1545 natLog = log (pg->total);
1546 connsPerPeer = ceil (natLog * logNModifier);
1548 if (connsPerPeer % 2 == 1)
1551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Target is %d connections per peer."), connsPerPeer);
1553 smallWorldConnections = 0;
1554 connect_attempts = 0;
1555 for (i = 0; i < pg->total; i++)
1558 max = i + connsPerPeer / 2;
1559 min = i - connsPerPeer / 2;
1561 if (max > pg->total - 1)
1563 max = max - pg->total;
1569 min = pg->total - 1 + min;
1573 for (j = 0; j < connsPerPeer / 2; j++)
1577 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
1578 UINT64_MAX) / ((double) UINT64_MAX));
1579 if (random < probability)
1581 /* Connect to uniformly selected random peer */
1583 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1585 while ((((randomPeer < max) && (randomPeer > min))
1586 && (useAnd == 0)) || (((randomPeer > min)
1587 || (randomPeer < max))
1591 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1594 smallWorldConnections += proc (pg, i, randomPeer);
1598 nodeToConnect = i + j + 1;
1599 if (nodeToConnect > pg->total - 1)
1601 nodeToConnect = nodeToConnect - pg->total;
1603 connect_attempts += proc (pg, i, nodeToConnect);
1609 connect_attempts += smallWorldConnections;
1611 return connect_attempts;
1615 * Create a topology given a peer group (set of running peers)
1616 * and a connection processor.
1618 * @param pg the peergroup to create the topology on
1619 * @param proc the connection processor to call to actually set
1620 * up connections between two peers
1622 * @return the number of connections that were set up
1626 create_nated_internet (struct GNUNET_TESTING_PeerGroup *pg,
1627 GNUNET_TESTING_ConnectionProcessor proc)
1629 unsigned int outer_count, inner_count;
1630 unsigned int cutoff;
1631 int connect_attempts;
1632 double nat_percentage;
1635 nat_percentage = 0.6; /* FIXME: default percentage? */
1636 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg,
1641 if (sscanf (p_string, "%lf", &nat_percentage) != 1)
1642 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1644 ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1645 p_string, "PERCENTAGE", "TESTING");
1646 GNUNET_free (p_string);
1651 cutoff = (unsigned int) (nat_percentage * pg->total);
1653 connect_attempts = 0;
1655 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
1657 for (inner_count = outer_count + 1; inner_count < pg->total;
1660 if ((outer_count > cutoff) || (inner_count > cutoff))
1663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1664 "Connecting peer %d to peer %d\n",
1665 outer_count, inner_count);
1667 connect_attempts += proc (pg, outer_count, inner_count);
1672 return connect_attempts;
1677 * Create a topology given a peer group (set of running peers)
1678 * and a connection processor.
1680 * @param pg the peergroup to create the topology on
1681 * @param proc the connection processor to call to actually set
1682 * up connections between two peers
1684 * @return the number of connections that were set up
1688 create_small_world (struct GNUNET_TESTING_PeerGroup *pg,
1689 GNUNET_TESTING_ConnectionProcessor proc)
1691 unsigned int i, j, k;
1692 unsigned int square;
1695 unsigned int toggle = 1;
1696 unsigned int nodeToConnect;
1697 unsigned int natLog;
1698 unsigned int node1Row;
1699 unsigned int node1Col;
1700 unsigned int node2Row;
1701 unsigned int node2Col;
1702 unsigned int distance;
1703 double probability, random, percentage;
1704 unsigned int smallWorldConnections;
1705 unsigned int small_world_it;
1707 int connect_attempts;
1708 square = floor (sqrt (pg->total));
1712 percentage = 0.5; /* FIXME: default percentage? */
1713 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg,
1718 if (sscanf (p_string, "%lf", &percentage) != 1)
1719 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1721 ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1722 p_string, "PERCENTAGE", "TESTING");
1723 GNUNET_free (p_string);
1725 if (percentage < 0.0)
1727 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1729 ("Invalid value `%s' for option `%s' in section `%s': got %f, needed value greater than 0\n"),
1730 "PERCENTAGE", "TESTING", percentage);
1733 probability = 0.5; /* FIXME: default percentage? */
1734 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg,
1739 if (sscanf (p_string, "%lf", &probability) != 1)
1740 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1742 ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1743 p_string, "PROBABILITY", "TESTING");
1744 GNUNET_free (p_string);
1746 if (square * square != pg->total)
1748 while (rows * cols < pg->total)
1750 if (toggle % 2 == 0)
1759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1761 ("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
1765 connect_attempts = 0;
1766 /* Rows and columns are all sorted out, now iterate over all nodes and connect each
1767 * to the node to its right and above. Once this is over, we'll have our torus!
1768 * Special case for the last node (if the rows and columns are not equal), connect
1769 * to the first in the row to maintain topology.
1771 for (i = 0; i < pg->total; i++)
1773 /* First connect to the node to the right */
1774 if (((i + 1) % cols != 0) && (i + 1 != pg->total))
1775 nodeToConnect = i + 1;
1776 else if (i + 1 == pg->total)
1777 nodeToConnect = rows * cols - cols;
1779 nodeToConnect = i - cols + 1;
1781 connect_attempts += proc (pg, i, nodeToConnect);
1784 nodeToConnect = (rows * cols) - cols + i;
1786 nodeToConnect = i - cols;
1788 if (nodeToConnect < pg->total)
1789 connect_attempts += proc (pg, i, nodeToConnect);
1791 natLog = log (pg->total);
1792 #if VERBOSE_TESTING > 2
1793 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1794 _("natural log of %d is %d, will run %d iterations\n"),
1795 pg->total, natLog, (int) (natLog * percentage));
1796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1797 _("Total connections added thus far: %u!\n"), connect_attempts);
1799 smallWorldConnections = 0;
1800 small_world_it = (unsigned int) (natLog * percentage);
1801 if (small_world_it < 1)
1803 GNUNET_assert (small_world_it > 0 && small_world_it < (unsigned int) -1);
1804 for (i = 0; i < small_world_it; i++)
1806 for (j = 0; j < pg->total; j++)
1808 /* Determine the row and column of node at position j on the 2d torus */
1809 node1Row = j / cols;
1810 node1Col = j - (node1Row * cols);
1811 for (k = 0; k < pg->total; k++)
1813 /* Determine the row and column of node at position k on the 2d torus */
1814 node2Row = k / cols;
1815 node2Col = k - (node2Row * cols);
1816 /* Simple Cartesian distance */
1818 abs (node1Row - node2Row) + abs (node1Col - node2Col);
1821 /* Calculate probability as 1 over the square of the distance */
1822 probability = 1.0 / (distance * distance);
1823 /* Choose a random value between 0 and 1 */
1826 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
1828 ((double) UINT64_MAX);
1829 /* If random < probability, then connect the two nodes */
1830 if (random < probability)
1831 smallWorldConnections += proc (pg, j, k);
1837 connect_attempts += smallWorldConnections;
1838 #if VERBOSE_TESTING > 2
1839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1840 _("Total connections added for small world: %d!\n"),
1841 smallWorldConnections);
1843 return connect_attempts;
1847 * Create a topology given a peer group (set of running peers)
1848 * and a connection processor.
1850 * @param pg the peergroup to create the topology on
1851 * @param proc the connection processor to call to actually set
1852 * up connections between two peers
1854 * @return the number of connections that were set up
1858 create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg,
1859 GNUNET_TESTING_ConnectionProcessor proc)
1862 unsigned int outer_count;
1863 unsigned int inner_count;
1864 int connect_attempts;
1868 probability = 0.5; /* FIXME: default percentage? */
1869 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg,
1874 if (sscanf (p_string, "%lf", &probability) != 1)
1875 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1877 ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1878 p_string, "PROBABILITY", "TESTING");
1879 GNUNET_free (p_string);
1881 connect_attempts = 0;
1882 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
1884 for (inner_count = outer_count + 1; inner_count < pg->total;
1889 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
1890 UINT64_MAX)) / ((double) UINT64_MAX);
1892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1893 _("rand is %f probability is %f\n"), temp_rand,
1896 if (temp_rand < probability)
1898 connect_attempts += proc (pg, outer_count, inner_count);
1903 return connect_attempts;
1907 * Create a topology given a peer group (set of running peers)
1908 * and a connection processor. This particular function creates
1909 * the connections for a 2d-torus, plus additional "closest"
1910 * connections per peer.
1912 * @param pg the peergroup to create the topology on
1913 * @param proc the connection processor to call to actually set
1914 * up connections between two peers
1916 * @return the number of connections that were set up
1920 create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg,
1921 GNUNET_TESTING_ConnectionProcessor proc)
1924 unsigned int square;
1927 unsigned int toggle = 1;
1928 unsigned int nodeToConnect;
1929 int connect_attempts;
1931 connect_attempts = 0;
1933 square = floor (sqrt (pg->total));
1937 if (square * square != pg->total)
1939 while (rows * cols < pg->total)
1941 if (toggle % 2 == 0)
1950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1952 ("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
1955 /* Rows and columns are all sorted out, now iterate over all nodes and connect each
1956 * to the node to its right and above. Once this is over, we'll have our torus!
1957 * Special case for the last node (if the rows and columns are not equal), connect
1958 * to the first in the row to maintain topology.
1960 for (i = 0; i < pg->total; i++)
1962 /* First connect to the node to the right */
1963 if (((i + 1) % cols != 0) && (i + 1 != pg->total))
1964 nodeToConnect = i + 1;
1965 else if (i + 1 == pg->total)
1966 nodeToConnect = rows * cols - cols;
1968 nodeToConnect = i - cols + 1;
1970 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1971 "Connecting peer %d to peer %d\n", i, nodeToConnect);
1973 connect_attempts += proc (pg, i, nodeToConnect);
1975 /* Second connect to the node immediately above */
1977 nodeToConnect = (rows * cols) - cols + i;
1979 nodeToConnect = i - cols;
1981 if (nodeToConnect < pg->total)
1984 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1985 "Connecting peer %d to peer %d\n", i, nodeToConnect);
1987 connect_attempts += proc (pg, i, nodeToConnect);
1992 return connect_attempts;
1997 * Create a topology given a peer group (set of running peers)
1998 * and a connection processor.
2000 * @param pg the peergroup to create the topology on
2001 * @param proc the connection processor to call to actually set
2002 * up connections between two peers
2004 * @return the number of connections that were set up
2008 create_clique (struct GNUNET_TESTING_PeerGroup *pg,
2009 GNUNET_TESTING_ConnectionProcessor proc)
2011 unsigned int outer_count;
2012 unsigned int inner_count;
2013 int connect_attempts;
2015 connect_attempts = 0;
2017 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
2019 for (inner_count = outer_count + 1; inner_count < pg->total;
2023 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2024 "Connecting peer %d to peer %d\n",
2025 outer_count, inner_count);
2027 connect_attempts += proc (pg, outer_count, inner_count);
2031 return connect_attempts;
2035 * Iterator over hash map entries.
2037 * @param cls closure the peer group
2038 * @param key the key stored in the hashmap is the
2039 * index of the peer to connect to
2040 * @param value value in the hash map, handle to the peer daemon
2041 * @return GNUNET_YES if we should continue to
2046 unblacklist_iterator (void *cls,
2047 const GNUNET_HashCode * key,
2050 struct UnblacklistContext *un_ctx = cls;
2051 uint32_t second_pos;
2053 uid_from_hash (key, &second_pos);
2055 unblacklist_connections(un_ctx->pg, un_ctx->first_uid, second_pos);
2061 * Create a blacklist topology based on the allowed topology
2062 * which disallows any connections not in the allowed topology
2063 * at the transport level.
2065 * @param pg the peergroup to create the topology on
2066 * @param proc the connection processor to call to allow
2067 * up connections between two peers
2069 * @return the number of connections that were set up
2073 copy_allowed (struct GNUNET_TESTING_PeerGroup *pg,
2074 GNUNET_TESTING_ConnectionProcessor proc)
2076 struct UnblacklistContext un_ctx;
2082 for (count = 0; count < pg->total - 1; count++)
2084 un_ctx.first_uid = count;
2085 total += GNUNET_CONTAINER_multihashmap_iterate(pg->peers[count].allowed_peers, &unblacklist_iterator, &un_ctx);
2087 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Unblacklisted %u peers\n", total);
2092 * Create a topology given a peer group (set of running peers)
2093 * and a connection processor.
2095 * @param pg the peergroup to create the topology on
2096 * @param proc the connection processor to call to actually set
2097 * up connections between two peers
2099 * @return the number of connections that were set up
2103 create_line (struct GNUNET_TESTING_PeerGroup *pg,
2104 GNUNET_TESTING_ConnectionProcessor proc)
2107 int connect_attempts;
2109 connect_attempts = 0;
2111 /* Connect each peer to the next highest numbered peer */
2112 for (count = 0; count < pg->total - 1; count++)
2115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2116 "Connecting peer %d to peer %d\n", count, count + 1);
2118 connect_attempts += proc (pg, count, count + 1);
2121 return connect_attempts;
2125 * Create a topology given a peer group (set of running peers)
2126 * and a connection processor.
2128 * @param pg the peergroup to create the topology on
2129 * @param filename the file to read topology information from
2130 * @param proc the connection processor to call to actually set
2131 * up connections between two peers
2133 * @return the number of connections that were set up
2137 create_from_file (struct GNUNET_TESTING_PeerGroup *pg,
2139 GNUNET_TESTING_ConnectionProcessor proc)
2141 int connect_attempts;
2142 unsigned int first_peer_index;
2143 unsigned int second_peer_index;
2144 connect_attempts = 0;
2149 unsigned int total_peers;
2151 enum States curr_state;
2153 if (GNUNET_OK != GNUNET_DISK_file_test (filename))
2154 GNUNET_DISK_fn_write (filename, NULL, 0, GNUNET_DISK_PERM_USER_READ);
2156 if ((0 != STAT (filename, &frstat)) || (frstat.st_size == 0))
2158 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2159 "Could not open file `%s' specified for topology!", filename);
2160 return connect_attempts;
2163 data = GNUNET_malloc_large (frstat.st_size);
2164 GNUNET_assert(data != NULL);
2165 if (frstat.st_size !=
2166 GNUNET_DISK_fn_read (filename, data, frstat.st_size))
2168 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2169 "Could not read file %s specified for host list, ending test!", filename);
2171 return connect_attempts;
2176 /* First line should contain a single integer, specifying the number of peers */
2177 /* Each subsequent line should contain this format PEER_INDEX:OTHER_PEER_INDEX[,...] */
2178 curr_state = NUM_PEERS;
2179 while (count < frstat.st_size - 1)
2181 if ((buf[count] == '\n') || (buf[count] == ' '))
2190 if (1 != sscanf(&buf[count], "%u", &total_peers))
2192 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to read number of peers from topology file!\n");
2193 GNUNET_free_non_null(data);
2194 return connect_attempts;
2196 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Read %u total peers in topology\n", total_peers);
2197 GNUNET_assert(total_peers == pg->total);
2198 curr_state = PEER_INDEX;
2199 while((buf[count] != '\n') && (count < frstat.st_size - 1))
2204 if (1 != sscanf(&buf[count], "%u", &first_peer_index))
2206 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to read peer index from topology file!\n");
2207 GNUNET_free_non_null(data);
2208 return connect_attempts;
2210 while((buf[count] != ':') && (count < frstat.st_size - 1))
2213 curr_state = OTHER_PEER_INDEX;
2216 if (1 == sscanf(&buf[count], ":"))
2217 curr_state = OTHER_PEER_INDEX;
2220 case OTHER_PEER_INDEX:
2221 if (1 != sscanf(&buf[count], "%u", &second_peer_index))
2223 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to peer index from topology file!\n");
2224 GNUNET_free_non_null(data);
2225 return connect_attempts;
2227 /* Assume file is written with first peer 1, but array index is 0 */
2228 connect_attempts += proc (pg, first_peer_index - 1, second_peer_index - 1);
2229 while((buf[count] != '\n') && (buf[count] != ',') && (count < frstat.st_size - 1))
2231 if (buf[count] == '\n')
2233 curr_state = PEER_INDEX;
2235 else if (buf[count] != ',')
2237 curr_state = OTHER_PEER_INDEX;
2242 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Found bad data in topology file while in state %d!\n", curr_state);
2244 return connect_attempts;
2249 /* Connect each peer to the next highest numbered peer */
2250 for (count = 0; count < pg->total - 1; count++)
2253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2254 "Connecting peer %d to peer %d\n", first_peer_index, second_peer_index);
2256 connect_attempts += proc (pg, first_peer_index, second_peer_index);
2259 return connect_attempts;
2263 * Create a topology given a peer group (set of running peers)
2264 * and a connection processor.
2266 * @param pg the peergroup to create the topology on
2267 * @param proc the connection processor to call to actually set
2268 * up connections between two peers
2270 * @return the number of connections that were set up
2274 create_ring (struct GNUNET_TESTING_PeerGroup *pg,
2275 GNUNET_TESTING_ConnectionProcessor proc)
2278 int connect_attempts;
2280 connect_attempts = 0;
2282 /* Connect each peer to the next highest numbered peer */
2283 for (count = 0; count < pg->total - 1; count++)
2286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2287 "Connecting peer %d to peer %d\n", count, count + 1);
2289 connect_attempts += proc (pg, count, count + 1);
2292 /* Connect the last peer to the first peer */
2293 connect_attempts += proc (pg, pg->total - 1, 0);
2295 return connect_attempts;
2300 * Iterator for writing friends of a peer to a file.
2302 * @param cls closure, an open writable file handle
2303 * @param key the key the daemon was stored under
2304 * @param value the GNUNET_TESTING_Daemon that needs to be written.
2306 * @return GNUNET_YES to continue iteration
2308 * TODO: Could replace friend_file_iterator and blacklist_file_iterator
2309 * with a single file_iterator that takes a closure which contains
2310 * the prefix to write before the peer. Then this could be used
2311 * for blacklisting multiple transports and writing the friend
2312 * file. I'm sure *someone* will complain loudly about other
2313 * things that negate these functions even existing so no point in
2317 friend_file_iterator (void *cls, const GNUNET_HashCode * key, void *value)
2319 FILE *temp_friend_handle = cls;
2320 struct GNUNET_TESTING_Daemon *peer = value;
2321 struct GNUNET_PeerIdentity *temppeer;
2322 struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
2324 temppeer = &peer->id;
2325 GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc);
2326 fprintf (temp_friend_handle, "%s\n", (char *) &peer_enc);
2331 struct BlacklistContext
2334 * The (open) file handle to write to
2336 FILE *temp_file_handle;
2339 * The transport that this peer will be blacklisted on.
2345 * Iterator for writing blacklist data to appropriate files.
2347 * @param cls closure, an open writable file handle
2348 * @param key the key the daemon was stored under
2349 * @param value the GNUNET_TESTING_Daemon that needs to be written.
2351 * @return GNUNET_YES to continue iteration
2354 blacklist_file_iterator (void *cls, const GNUNET_HashCode * key, void *value)
2356 struct BlacklistContext *blacklist_ctx = cls;
2357 struct GNUNET_TESTING_Daemon *peer = value;
2358 struct GNUNET_PeerIdentity *temppeer;
2359 struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
2361 temppeer = &peer->id;
2362 GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc);
2363 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Writing entry %s:%s to file\n", blacklist_ctx->transport, (char *) &peer_enc);
2364 fprintf (blacklist_ctx->temp_file_handle, "%s:%s\n",
2365 blacklist_ctx->transport, (char *) &peer_enc);
2371 * Create the friend files based on the PeerConnection's
2372 * of each peer in the peer group, and copy the files
2373 * to the appropriate place
2375 * @param pg the peer group we are dealing with
2378 create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
2380 FILE *temp_friend_handle;
2381 unsigned int pg_iter;
2382 char *temp_service_path;
2383 struct GNUNET_OS_Process **procarr;
2386 enum GNUNET_OS_ProcessStatusType type;
2387 unsigned long return_code;
2392 procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total);
2393 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2395 mytemp = GNUNET_DISK_mktemp ("friends");
2396 GNUNET_assert (mytemp != NULL);
2397 temp_friend_handle = fopen (mytemp, "wt");
2398 GNUNET_assert (temp_friend_handle != NULL);
2399 GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers,
2400 &friend_file_iterator,
2401 temp_friend_handle);
2402 fclose (temp_friend_handle);
2405 GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].
2406 daemon->cfg, "PATHS",
2408 &temp_service_path))
2410 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2412 ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
2413 "SERVICEHOME", "PATHS");
2414 if (UNLINK (mytemp) != 0)
2415 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink",
2417 GNUNET_free (mytemp);
2421 if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
2423 GNUNET_asprintf (&arg, "%s/friends", temp_service_path);
2424 procarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
2428 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2429 _("Copying file with command cp %s %s\n"), mytemp, arg);
2434 else /* Remote, scp the file to the correct place */
2436 if (NULL != pg->peers[pg_iter].daemon->username)
2437 GNUNET_asprintf (&arg, "%s@%s:%s/friends",
2438 pg->peers[pg_iter].daemon->username,
2439 pg->peers[pg_iter].daemon->hostname,
2442 GNUNET_asprintf (&arg, "%s:%s/friends",
2443 pg->peers[pg_iter].daemon->hostname,
2446 GNUNET_OS_start_process (NULL, NULL, "scp", "scp", mytemp, arg,
2450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2451 _("Copying file with command scp %s %s\n"), mytemp,
2456 GNUNET_free (temp_service_path);
2457 GNUNET_free (mytemp);
2461 ret = GNUNET_SYSERR;
2462 while ((count < max_wait) && (ret != GNUNET_OK))
2465 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2469 _("Checking copy status of file %d\n"), pg_iter);
2471 if (procarr[pg_iter] != NULL) /* Check for already completed! */
2473 if (GNUNET_OS_process_status
2474 (procarr[pg_iter], &type, &return_code) != GNUNET_OK)
2476 ret = GNUNET_SYSERR;
2478 else if ((type != GNUNET_OS_PROCESS_EXITED)
2479 || (return_code != 0))
2481 ret = GNUNET_SYSERR;
2485 GNUNET_OS_process_close (procarr[pg_iter]);
2486 procarr[pg_iter] = NULL;
2488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2489 _("File %d copied\n"), pg_iter);
2495 if (ret == GNUNET_SYSERR)
2497 /* FIXME: why sleep here? -CG */
2503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2504 _("Finished copying all friend files!\n"));
2506 GNUNET_free (procarr);
2512 * Create the blacklist files based on the PeerConnection's
2513 * of each peer in the peer group, and copy the files
2514 * to the appropriate place.
2516 * @param pg the peer group we are dealing with
2517 * @param transports space delimited list of transports to blacklist
2520 create_and_copy_blacklist_files (struct GNUNET_TESTING_PeerGroup *pg,
2521 const char *transports)
2523 FILE *temp_file_handle;
2524 static struct BlacklistContext blacklist_ctx;
2525 unsigned int pg_iter;
2526 char *temp_service_path;
2527 struct GNUNET_OS_Process **procarr;
2530 enum GNUNET_OS_ProcessStatusType type;
2531 unsigned long return_code;
2538 char *temp_transports;
2541 procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total);
2542 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2544 mytemp = GNUNET_DISK_mktemp ("blacklist");
2545 GNUNET_assert (mytemp != NULL);
2546 temp_file_handle = fopen (mytemp, "wt");
2547 GNUNET_assert (temp_file_handle != NULL);
2548 temp_transports = GNUNET_strdup (transports);
2549 blacklist_ctx.temp_file_handle = temp_file_handle;
2550 transport_len = strlen (temp_transports) + 1;
2553 for (i = 0; i < transport_len; i++)
2555 if ((temp_transports[i] == ' ') && (pos == NULL))
2556 continue; /* At start of string (whitespace) */
2557 else if ((temp_transports[i] == ' ') || (temp_transports[i] == '\0')) /* At end of string */
2559 temp_transports[i] = '\0';
2560 blacklist_ctx.transport = pos;
2561 entry_count = GNUNET_CONTAINER_multihashmap_iterate (pg->
2563 [pg_iter].blacklisted_peers,
2564 &blacklist_file_iterator,
2567 } /* At beginning of actual string */
2568 else if (pos == NULL)
2570 pos = &temp_transports[i];
2574 GNUNET_free (temp_transports);
2575 fclose (temp_file_handle);
2578 GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].
2579 daemon->cfg, "PATHS",
2581 &temp_service_path))
2583 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2585 ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
2586 "SERVICEHOME", "PATHS");
2587 if (UNLINK (mytemp) != 0)
2588 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink",
2590 GNUNET_free (mytemp);
2594 if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
2596 GNUNET_asprintf (&arg, "%s/blacklist", temp_service_path);
2597 procarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
2601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2602 _("Copying file with command cp %s %s\n"), mytemp, arg);
2607 else /* Remote, scp the file to the correct place */
2609 if (NULL != pg->peers[pg_iter].daemon->username)
2610 GNUNET_asprintf (&arg, "%s@%s:%s/blacklist",
2611 pg->peers[pg_iter].daemon->username,
2612 pg->peers[pg_iter].daemon->hostname,
2615 GNUNET_asprintf (&arg, "%s:%s/blacklist",
2616 pg->peers[pg_iter].daemon->hostname,
2619 GNUNET_OS_start_process (NULL, NULL, "scp", "scp", mytemp, arg,
2623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2624 _("Copying file with command scp %s %s\n"), mytemp,
2629 GNUNET_free (temp_service_path);
2630 GNUNET_free (mytemp);
2634 ret = GNUNET_SYSERR;
2635 while ((count < max_wait) && (ret != GNUNET_OK))
2638 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2641 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2642 _("Checking copy status of file %d\n"), pg_iter);
2644 if (procarr[pg_iter] != NULL) /* Check for already completed! */
2646 if (GNUNET_OS_process_status
2647 (procarr[pg_iter], &type, &return_code) != GNUNET_OK)
2649 ret = GNUNET_SYSERR;
2651 else if ((type != GNUNET_OS_PROCESS_EXITED)
2652 || (return_code != 0))
2654 ret = GNUNET_SYSERR;
2658 GNUNET_OS_process_close (procarr[pg_iter]);
2659 procarr[pg_iter] = NULL;
2661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2662 _("File %d copied\n"), pg_iter);
2668 if (ret == GNUNET_SYSERR)
2670 /* FIXME: why sleep here? -CG */
2676 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2677 _("Finished copying all blacklist files!\n"));
2679 GNUNET_free (procarr);
2685 * Internal notification of a connection, kept so that we can ensure some connections
2686 * happen instead of flooding all testing daemons with requests to connect.
2689 internal_connect_notify (void *cls,
2690 const struct GNUNET_PeerIdentity *first,
2691 const struct GNUNET_PeerIdentity *second,
2693 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
2694 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
2695 struct GNUNET_TESTING_Daemon *first_daemon,
2696 struct GNUNET_TESTING_Daemon *second_daemon,
2699 struct ConnectTopologyContext *ct_ctx = cls;
2700 struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg;
2701 outstanding_connects--;
2702 ct_ctx->remaining_connections--;
2703 if (ct_ctx->remaining_connections == 0)
2705 if (ct_ctx->notify_connections_done != NULL)
2706 ct_ctx->notify_connections_done (ct_ctx->notify_cls, NULL);
2707 GNUNET_free (ct_ctx);
2710 if (pg->notify_connection != NULL)
2711 pg->notify_connection (pg->notify_connection_cls, first, second, distance,
2712 first_cfg, second_cfg, first_daemon, second_daemon,
2718 * Either delay a connection (because there are too many outstanding)
2719 * or schedule it for right now.
2721 * @param cls a connection context
2722 * @param tc the task runtime context
2725 schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2727 struct ConnectContext *connect_context = cls;
2729 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2732 if (outstanding_connects > MAX_OUTSTANDING_CONNECTIONS)
2734 #if VERBOSE_TESTING > 2
2735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2737 ("Delaying connect, we have too many outstanding connections!\n"));
2739 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2740 (GNUNET_TIME_UNIT_MILLISECONDS, 100),
2741 &schedule_connect, connect_context);
2745 #if VERBOSE_TESTING > 2
2746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2747 _("Creating connection, outstanding_connections is %d\n"),
2748 outstanding_connects);
2750 outstanding_connects++;
2751 GNUNET_TESTING_daemons_connect (connect_context->first,
2752 connect_context->second,
2755 &internal_connect_notify,
2756 connect_context->ct_ctx);
2757 GNUNET_free (connect_context);
2763 * Iterator for actually scheduling connections to be created
2764 * between two peers.
2766 * @param cls closure, a GNUNET_TESTING_Daemon
2767 * @param key the key the second Daemon was stored under
2768 * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2770 * @return GNUNET_YES to continue iteration
2773 connect_iterator (void *cls, const GNUNET_HashCode * key, void *value)
2775 struct ConnectTopologyContext *ct_ctx = cls;
2776 struct PeerData *first = ct_ctx->first;
2777 struct GNUNET_TESTING_Daemon *second = value;
2778 struct ConnectContext *connect_context;
2780 connect_context = GNUNET_malloc (sizeof (struct ConnectContext));
2781 connect_context->first = first->daemon;
2782 connect_context->second = second;
2783 connect_context->ct_ctx = ct_ctx;
2784 GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context);
2791 * Iterator for copying all entries in the allowed hashmap to the
2794 * @param cls closure, a GNUNET_TESTING_Daemon
2795 * @param key the key the second Daemon was stored under
2796 * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2798 * @return GNUNET_YES to continue iteration
2801 copy_topology_iterator (void *cls, const GNUNET_HashCode * key, void *value)
2803 struct PeerData *first = cls;
2805 GNUNET_assert (GNUNET_OK ==
2806 GNUNET_CONTAINER_multihashmap_put (first->connect_peers, key,
2808 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2814 * Make the peers to connect the same as those that are allowed to be
2817 * @param pg the peer group
2820 copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg)
2822 unsigned int pg_iter;
2827 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2830 GNUNET_CONTAINER_multihashmap_iterate (pg->
2831 peers[pg_iter].allowed_peers,
2832 ©_topology_iterator,
2833 &pg->peers[pg_iter]);
2834 if (GNUNET_SYSERR == ret)
2835 return GNUNET_SYSERR;
2837 total = total + ret;
2845 * Connect the topology as specified by the PeerConnection's
2846 * of each peer in the peer group
2848 * @param pg the peer group we are dealing with
2849 * @param notify_callback callback to notify when finished
2850 * @param notify_cls closure for notify callback
2852 * @return the number of connections that will be attempted
2855 connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
2856 GNUNET_TESTING_NotifyCompletion notify_callback,
2859 unsigned int pg_iter;
2862 struct ConnectTopologyContext *ct_ctx;
2864 struct PeerConnection *connection_iter;
2865 struct ConnectContext *connect_context;
2869 ct_ctx = GNUNET_malloc (sizeof (struct ConnectTopologyContext));
2870 ct_ctx->notify_connections_done = notify_callback;
2871 ct_ctx->notify_cls = notify_cls;
2874 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2877 GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].connect_peers);
2882 GNUNET_free (ct_ctx);
2885 ct_ctx->remaining_connections = total;
2888 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2890 ct_ctx->first = &pg->peers[pg_iter];
2892 GNUNET_CONTAINER_multihashmap_iterate (pg->
2893 peers[pg_iter].connect_peers,
2894 &connect_iterator, ct_ctx);
2895 GNUNET_assert (GNUNET_SYSERR != ret && ret >= 0);
2896 total = total + ret;
2899 connection_iter = FIXME;
2900 while (connection_iter != NULL)
2902 connect_context = GNUNET_malloc (sizeof (struct ConnectContext));
2903 connect_context->pg = pg;
2904 connect_context->first = FIXME;
2905 connect_context->second = connection_iter->daemon;
2906 GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context);
2907 connection_iter = connection_iter->next;
2916 * Takes a peer group and creates a topology based on the
2917 * one specified. Creates a topology means generates friend
2918 * files for the peers so they can only connect to those allowed
2919 * by the topology. This will only have an effect once peers
2920 * are started if the FRIENDS_ONLY option is set in the base
2921 * config. Also takes an optional restrict topology which
2922 * disallows connections based on particular transports
2923 * UNLESS they are specified in the restricted topology.
2925 * @param pg the peer group struct representing the running peers
2926 * @param topology which topology to connect the peers in
2927 * @param restrict_topology disallow restrict_transports transport
2928 * connections to peers NOT in this topology
2929 * use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions
2930 * @param restrict_transports space delimited list of transports to blacklist
2931 * to create restricted topology
2933 * @return the maximum number of connections were all allowed peers
2934 * connected to each other
2937 GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg,
2938 enum GNUNET_TESTING_Topology topology,
2939 enum GNUNET_TESTING_Topology
2941 const char *restrict_transports)
2944 unsigned int num_connections;
2945 int unblacklisted_connections;
2950 case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2952 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating clique topology\n"));
2954 num_connections = create_clique (pg, &add_allowed_connections);
2956 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2959 _("Creating small world (ring) topology\n"));
2962 create_small_world_ring (pg, &add_allowed_connections);
2964 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2967 _("Creating small world (2d-torus) topology\n"));
2969 num_connections = create_small_world (pg, &add_allowed_connections);
2971 case GNUNET_TESTING_TOPOLOGY_RING:
2973 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating ring topology\n"));
2975 num_connections = create_ring (pg, &add_allowed_connections);
2977 case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating 2d torus topology\n"));
2981 num_connections = create_2d_torus (pg, &add_allowed_connections);
2983 case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2985 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2986 _("Creating Erdos-Renyi topology\n"));
2988 num_connections = create_erdos_renyi (pg, &add_allowed_connections);
2990 case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2992 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating InterNAT topology\n"));
2994 num_connections = create_nated_internet (pg, &add_allowed_connections);
2996 case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
2998 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2999 _("Creating Scale Free topology\n"));
3001 num_connections = create_scale_free (pg, &add_allowed_connections);
3003 case GNUNET_TESTING_TOPOLOGY_LINE:
3005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3006 _("Creating straight line topology\n"));
3008 num_connections = create_line (pg, &add_allowed_connections);
3010 case GNUNET_TESTING_TOPOLOGY_FROM_FILE:
3012 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3013 _("Creating topology from file!\n"));
3016 GNUNET_CONFIGURATION_get_value_string (pg->cfg, "testing", "topology_file",
3018 num_connections = create_from_file (pg, filename, &add_allowed_connections);
3021 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Missing configuration option TESTING:TOPOLOGY_FILE for creating topology from file!");
3022 num_connections = 0;
3025 case GNUNET_TESTING_TOPOLOGY_NONE:
3027 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3029 ("Creating no allowed topology (all peers can connect at core level)\n"));
3031 num_connections = 0;
3034 num_connections = 0;
3039 GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
3041 ret = create_and_copy_friend_files (pg);
3042 if (ret != GNUNET_OK)
3045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3046 _("Failed during friend file copying!\n"));
3048 return GNUNET_SYSERR;
3053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3054 _("Friend files created/copied successfully!\n"));
3059 /* Use the create clique method to initially set all connections as blacklisted. */
3060 create_clique (pg, &blacklist_connections);
3062 unblacklisted_connections = 0;
3063 /* Un-blacklist connections as per the topology specified */
3064 switch (restrict_topology)
3066 case GNUNET_TESTING_TOPOLOGY_CLIQUE:
3068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3069 _("Blacklisting all but clique topology\n"));
3071 unblacklisted_connections =
3072 create_clique (pg, &unblacklist_connections);
3074 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
3076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3077 _("Blacklisting all but small world (ring) topology\n"));
3079 unblacklisted_connections =
3080 create_small_world_ring (pg, &unblacklist_connections);
3082 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
3084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3086 ("Blacklisting all but small world (2d-torus) topology\n"));
3088 unblacklisted_connections =
3089 create_small_world (pg, &unblacklist_connections);
3091 case GNUNET_TESTING_TOPOLOGY_RING:
3093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3094 _("Blacklisting all but ring topology\n"));
3096 unblacklisted_connections = create_ring (pg, &unblacklist_connections);
3098 case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
3100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3101 _("Blacklisting all but 2d torus topology\n"));
3103 unblacklisted_connections =
3104 create_2d_torus (pg, &unblacklist_connections);
3106 case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
3108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3109 _("Blacklisting all but Erdos-Renyi topology\n"));
3111 unblacklisted_connections =
3112 create_erdos_renyi (pg, &unblacklist_connections);
3114 case GNUNET_TESTING_TOPOLOGY_INTERNAT:
3116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3117 _("Blacklisting all but InterNAT topology\n"));
3119 unblacklisted_connections =
3120 create_nated_internet (pg, &unblacklist_connections);
3122 case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
3124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3125 _("Blacklisting all but Scale Free topology\n"));
3127 unblacklisted_connections =
3128 create_scale_free (pg, &unblacklist_connections);
3130 case GNUNET_TESTING_TOPOLOGY_LINE:
3132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3133 _("Blacklisting all but straight line topology\n"));
3135 unblacklisted_connections = create_line (pg, &unblacklist_connections);
3137 case GNUNET_TESTING_TOPOLOGY_NONE:
3138 case GNUNET_TESTING_TOPOLOGY_FROM_FILE:
3140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3142 ("Creating no blacklist topology (all peers can connect at transport level)\n"));
3144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3146 ("Creating blacklist topology from allowed\n"));
3147 unblacklisted_connections = copy_allowed (pg, &unblacklist_connections);
3152 if ((unblacklisted_connections > 0) && (restrict_transports != NULL))
3154 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Creating blacklist with `%s'", restrict_transports);
3155 ret = create_and_copy_blacklist_files (pg, restrict_transports);
3156 if (ret != GNUNET_OK)
3159 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3160 _("Failed during blacklist file copying!\n"));
3167 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3168 _("Blacklist files created/copied successfully!\n"));
3172 return num_connections;
3177 * Iterator for choosing random peers to connect.
3179 * @param cls closure, a RandomContext
3180 * @param key the key the second Daemon was stored under
3181 * @param value the GNUNET_TESTING_Daemon that the first is to connect to
3183 * @return GNUNET_YES to continue iteration
3186 random_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value)
3188 struct RandomContext *random_ctx = cls;
3189 double random_number;
3190 uint32_t second_pos;
3191 GNUNET_HashCode first_hash;
3194 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
3195 UINT64_MAX)) / ((double) UINT64_MAX);
3196 if (random_number < random_ctx->percentage)
3198 GNUNET_assert (GNUNET_OK ==
3199 GNUNET_CONTAINER_multihashmap_put (random_ctx->
3200 first->connect_peers_working_set,
3202 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3204 /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */
3205 uid_from_hash (key, &second_pos);
3206 hash_from_uid (random_ctx->first_uid, &first_hash);
3207 GNUNET_assert (random_ctx->pg->total > second_pos);
3208 GNUNET_assert (GNUNET_YES ==
3209 GNUNET_CONTAINER_multihashmap_remove (random_ctx->
3211 [second_pos].connect_peers,
3220 * Iterator for adding at least X peers to a peers connection set.
3222 * @param cls closure, MinimumContext
3223 * @param key the key the second Daemon was stored under
3224 * @param value the GNUNET_TESTING_Daemon that the first is to connect to
3226 * @return GNUNET_YES to continue iteration
3229 minimum_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value)
3231 struct MinimumContext *min_ctx = cls;
3232 uint32_t second_pos;
3233 GNUNET_HashCode first_hash;
3236 if (GNUNET_CONTAINER_multihashmap_size
3237 (min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add)
3239 for (i = 0; i < min_ctx->num_to_add; i++)
3241 if (min_ctx->pg_array[i] == min_ctx->current)
3243 GNUNET_assert (GNUNET_OK ==
3244 GNUNET_CONTAINER_multihashmap_put
3245 (min_ctx->first->connect_peers_working_set, key,
3247 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3248 uid_from_hash (key, &second_pos);
3249 hash_from_uid (min_ctx->first_uid, &first_hash);
3250 GNUNET_assert (min_ctx->pg->total > second_pos);
3251 GNUNET_assert (GNUNET_OK ==
3252 GNUNET_CONTAINER_multihashmap_put (min_ctx->
3254 [second_pos].connect_peers_working_set,
3258 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3259 /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */
3260 GNUNET_assert (GNUNET_YES ==
3261 GNUNET_CONTAINER_multihashmap_remove
3262 (min_ctx->pg->peers[second_pos].connect_peers,
3263 &first_hash, min_ctx->first->daemon));
3270 return GNUNET_NO; /* We can stop iterating, we have enough peers! */
3276 * Iterator for adding peers to a connection set based on a depth first search.
3278 * @param cls closure, MinimumContext
3279 * @param key the key the second daemon was stored under
3280 * @param value the GNUNET_TESTING_Daemon that the first is to connect to
3282 * @return GNUNET_YES to continue iteration
3285 dfs_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value)
3287 struct DFSContext *dfs_ctx = cls;
3288 GNUNET_HashCode first_hash;
3290 if (dfs_ctx->current == dfs_ctx->chosen)
3292 GNUNET_assert (GNUNET_OK ==
3293 GNUNET_CONTAINER_multihashmap_put (dfs_ctx->
3294 first->connect_peers_working_set,
3296 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3297 uid_from_hash (key, &dfs_ctx->second_uid);
3298 hash_from_uid (dfs_ctx->first_uid, &first_hash);
3299 GNUNET_assert (GNUNET_OK ==
3300 GNUNET_CONTAINER_multihashmap_put (dfs_ctx->
3302 [dfs_ctx->second_uid].connect_peers_working_set,
3306 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3307 GNUNET_assert (GNUNET_YES ==
3308 GNUNET_CONTAINER_multihashmap_remove (dfs_ctx->
3310 [dfs_ctx->second_uid].connect_peers,
3314 /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */
3315 return GNUNET_NO; /* We have found our peer, don't iterate more */
3324 * From the set of connections possible, choose percentage percent of connections
3325 * to actually connect.
3327 * @param pg the peergroup we are dealing with
3328 * @param percentage what percent of total connections to make
3331 choose_random_connections (struct GNUNET_TESTING_PeerGroup *pg,
3334 struct RandomContext random_ctx;
3337 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3339 random_ctx.first_uid = pg_iter;
3340 random_ctx.first = &pg->peers[pg_iter];
3341 random_ctx.percentage = percentage;
3343 pg->peers[pg_iter].connect_peers_working_set =
3344 GNUNET_CONTAINER_multihashmap_create (pg->total);
3345 GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers,
3346 &random_connect_iterator,
3348 /* Now remove the old connections */
3349 GNUNET_CONTAINER_multihashmap_destroy (pg->
3350 peers[pg_iter].connect_peers);
3351 /* And replace with the random set */
3352 pg->peers[pg_iter].connect_peers =
3353 pg->peers[pg_iter].connect_peers_working_set;
3358 * From the set of connections possible, choose at least num connections per
3361 * @param pg the peergroup we are dealing with
3362 * @param num how many connections at least should each peer have (if possible)?
3365 choose_minimum (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
3367 struct MinimumContext minimum_ctx;
3370 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3372 pg->peers[pg_iter].connect_peers_working_set =
3373 GNUNET_CONTAINER_multihashmap_create (num);
3376 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3378 minimum_ctx.first_uid = pg_iter;
3379 minimum_ctx.pg_array =
3380 GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
3381 GNUNET_CONTAINER_multihashmap_size
3382 (pg->peers[pg_iter].connect_peers));
3383 minimum_ctx.first = &pg->peers[pg_iter];
3384 minimum_ctx.pg = pg;
3385 minimum_ctx.num_to_add = num;
3386 minimum_ctx.current = 0;
3387 GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers,
3388 &minimum_connect_iterator,
3392 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3394 /* Remove the "old" connections */
3395 GNUNET_CONTAINER_multihashmap_destroy (pg->
3396 peers[pg_iter].connect_peers);
3397 /* And replace with the working set */
3398 pg->peers[pg_iter].connect_peers =
3399 pg->peers[pg_iter].connect_peers_working_set;
3406 count_workingset_connections (struct GNUNET_TESTING_PeerGroup *pg)
3409 unsigned int pg_iter;
3413 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3416 GNUNET_CONTAINER_multihashmap_size (pg->
3418 [pg_iter].connect_peers_working_set);
3426 count_allowed_connections (struct GNUNET_TESTING_PeerGroup *pg)
3429 unsigned int pg_iter;
3433 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3436 GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].connect_peers);
3443 struct FindClosestContext
3446 * The currently known closest peer.
3448 struct GNUNET_TESTING_Daemon *closest;
3451 * The info for the peer we are adding connections for.
3453 struct PeerData *curr_peer;
3456 * The distance (bits) between the current
3457 * peer and the currently known closest.
3459 unsigned int closest_dist;
3462 * The offset of the closest known peer in
3465 unsigned int closest_num;
3469 * Iterator over hash map entries of the allowed
3470 * peer connections. Find the closest, not already
3471 * connected peer and return it.
3473 * @param cls closure (struct FindClosestContext)
3474 * @param key current key code (hash of offset in pg)
3475 * @param value value in the hash map - a GNUNET_TESTING_Daemon
3476 * @return GNUNET_YES if we should continue to
3481 find_closest_peers (void *cls, const GNUNET_HashCode * key, void *value)
3483 struct FindClosestContext *closest_ctx = cls;
3484 struct GNUNET_TESTING_Daemon *daemon = value;
3486 if (((closest_ctx->closest == NULL) ||
3487 (GNUNET_CRYPTO_hash_matching_bits
3488 (&daemon->id.hashPubKey,
3489 &closest_ctx->curr_peer->daemon->id.hashPubKey) >
3490 closest_ctx->closest_dist))
3492 GNUNET_CONTAINER_multihashmap_contains (closest_ctx->
3493 curr_peer->connect_peers,
3496 closest_ctx->closest_dist =
3497 GNUNET_CRYPTO_hash_matching_bits (&daemon->id.hashPubKey,
3498 &closest_ctx->curr_peer->daemon->
3500 closest_ctx->closest = daemon;
3501 uid_from_hash (key, &closest_ctx->closest_num);
3507 * From the set of connections possible, choose at num connections per
3508 * peer based on depth which are closest out of those allowed. Guaranteed
3509 * to add num peers to connect to, provided there are that many peers
3510 * in the underlay topology to connect to.
3512 * @param pg the peergroup we are dealing with
3513 * @param num how many connections at least should each peer have (if possible)?
3514 * @param proc processor to actually add the connections
3517 add_closest (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num,
3518 GNUNET_TESTING_ConnectionProcessor proc)
3520 struct FindClosestContext closest_ctx;
3524 for (i = 0; i < num; i++) /* Each time find a closest peer (from those available) */
3526 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3528 closest_ctx.curr_peer = &pg->peers[pg_iter];
3529 closest_ctx.closest = NULL;
3530 closest_ctx.closest_dist = 0;
3531 closest_ctx.closest_num = 0;
3532 GNUNET_CONTAINER_multihashmap_iterate (pg->
3533 peers[pg_iter].allowed_peers,
3534 &find_closest_peers,
3536 if (closest_ctx.closest != NULL)
3538 GNUNET_assert (closest_ctx.closest_num < pg->total);
3539 proc (pg, pg_iter, closest_ctx.closest_num);
3546 * From the set of connections possible, choose at least num connections per
3547 * peer based on depth first traversal of peer connections. If DFS leaves
3548 * peers unconnected, ensure those peers get connections.
3550 * @param pg the peergroup we are dealing with
3551 * @param num how many connections at least should each peer have (if possible)?
3554 perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
3556 struct DFSContext dfs_ctx;
3559 uint32_t starting_peer;
3560 uint32_t least_connections;
3561 GNUNET_HashCode second_hash;
3563 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3565 pg->peers[pg_iter].connect_peers_working_set =
3566 GNUNET_CONTAINER_multihashmap_create (num);
3571 while ((count_workingset_connections (pg) < num * pg->total)
3572 && (count_allowed_connections (pg) > 0))
3574 if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */
3576 least_connections = -1; /* Set to very high number */
3577 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3579 if (GNUNET_CONTAINER_multihashmap_size
3580 (pg->peers[pg_iter].connect_peers_working_set) <
3583 starting_peer = pg_iter;
3585 GNUNET_CONTAINER_multihashmap_size (pg->
3587 [pg_iter].connect_peers_working_set);
3592 if (GNUNET_CONTAINER_multihashmap_size (pg->peers[starting_peer].connect_peers) == 0) /* Ensure there is at least one peer left to connect! */
3598 /* Choose a random peer from the chosen peers set of connections to add */
3600 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
3601 GNUNET_CONTAINER_multihashmap_size
3602 (pg->peers[starting_peer].connect_peers));
3603 dfs_ctx.first_uid = starting_peer;
3604 dfs_ctx.first = &pg->peers[starting_peer];
3606 dfs_ctx.current = 0;
3608 GNUNET_CONTAINER_multihashmap_iterate (pg->
3610 [starting_peer].connect_peers,
3611 &dfs_connect_iterator, &dfs_ctx);
3612 /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */
3613 hash_from_uid (dfs_ctx.second_uid, &second_hash);
3614 GNUNET_assert (GNUNET_YES ==
3615 GNUNET_CONTAINER_multihashmap_remove (pg->peers
3616 [starting_peer].connect_peers,
3620 [dfs_ctx.second_uid].daemon));
3621 starting_peer = dfs_ctx.second_uid;
3624 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3626 /* Remove the "old" connections */
3627 GNUNET_CONTAINER_multihashmap_destroy (pg->
3628 peers[pg_iter].connect_peers);
3629 /* And replace with the working set */
3630 pg->peers[pg_iter].connect_peers =
3631 pg->peers[pg_iter].connect_peers_working_set;
3636 * Internal callback for topology information for a particular peer.
3639 internal_topology_callback (void *cls,
3640 const struct GNUNET_PeerIdentity *peer,
3641 const struct GNUNET_TRANSPORT_ATS_Information
3644 struct CoreContext *core_ctx = cls;
3645 struct TopologyIterateContext *iter_ctx = core_ctx->iter_context;
3647 if (peer == NULL) /* Either finished, or something went wrong */
3649 iter_ctx->completed++;
3650 iter_ctx->connected--;
3651 /* One core context allocated per iteration, must free! */
3652 GNUNET_free (core_ctx);
3656 iter_ctx->topology_cb (iter_ctx->cls, &core_ctx->daemon->id,
3660 if (iter_ctx->completed == iter_ctx->total)
3662 iter_ctx->topology_cb (iter_ctx->cls, NULL, NULL, NULL);
3663 /* Once all are done, free the iteration context */
3664 GNUNET_free (iter_ctx);
3670 * Check running topology iteration tasks, if below max start a new one, otherwise
3671 * schedule for some time in the future.
3674 schedule_get_topology (void *cls,
3675 const struct GNUNET_SCHEDULER_TaskContext *tc)
3677 struct CoreContext *core_context = cls;
3678 struct TopologyIterateContext *topology_context =
3679 (struct TopologyIterateContext *) core_context->iter_context;
3680 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3683 if (topology_context->connected > MAX_OUTSTANDING_CONNECTIONS)
3685 #if VERBOSE_TESTING > 2
3686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3688 ("Delaying connect, we have too many outstanding connections!\n"));
3690 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
3691 (GNUNET_TIME_UNIT_MILLISECONDS, 100),
3692 &schedule_get_topology, core_context);
3696 #if VERBOSE_TESTING > 2
3697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3698 _("Creating connection, outstanding_connections is %d\n"),
3699 outstanding_connects);
3701 topology_context->connected++;
3704 GNUNET_CORE_iterate_peers (core_context->daemon->cfg,
3705 &internal_topology_callback,
3708 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Topology iteration failed.\n");
3709 internal_topology_callback (core_context, NULL, NULL);
3715 * Iterate over all (running) peers in the peer group, retrieve
3716 * all connections that each currently has.
3719 GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg,
3720 GNUNET_TESTING_NotifyTopology cb, void *cls)
3722 struct TopologyIterateContext *topology_context;
3723 struct CoreContext *core_ctx;
3725 unsigned int total_count;
3727 /* Allocate a single topology iteration context */
3728 topology_context = GNUNET_malloc (sizeof (struct TopologyIterateContext));
3729 topology_context->topology_cb = cb;
3730 topology_context->cls = cls;
3732 for (i = 0; i < pg->total; i++)
3734 if (pg->peers[i].daemon->running == GNUNET_YES)
3736 /* Allocate one core context per core we need to connect to */
3737 core_ctx = GNUNET_malloc (sizeof (struct CoreContext));
3738 core_ctx->daemon = pg->peers[i].daemon;
3739 /* Set back pointer to topology iteration context */
3740 core_ctx->iter_context = topology_context;
3741 GNUNET_SCHEDULER_add_now (&schedule_get_topology, core_ctx);
3745 if (total_count == 0)
3747 cb (cls, NULL, NULL, "Cannot iterate over topology, no running peers!");
3748 GNUNET_free (topology_context);
3751 topology_context->total = total_count;
3756 * Callback function to process statistic values.
3757 * This handler is here only really to insert a peer
3758 * identity (or daemon) so the statistics can be uniquely
3759 * tied to a single running peer.
3761 * @param cls closure
3762 * @param subsystem name of subsystem that created the statistic
3763 * @param name the name of the datum
3764 * @param value the current value
3765 * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
3766 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
3769 internal_stats_callback (void *cls,
3770 const char *subsystem,
3771 const char *name, uint64_t value, int is_persistent)
3773 struct StatsCoreContext *core_context = cls;
3774 struct StatsIterateContext *stats_context =
3775 (struct StatsIterateContext *) core_context->iter_context;
3777 return stats_context->proc (stats_context->cls, &core_context->daemon->id,
3778 subsystem, name, value, is_persistent);
3782 * Internal continuation call for statistics iteration.
3784 * @param cls closure, the CoreContext for this iteration
3785 * @param success whether or not the statistics iterations
3786 * was canceled or not (we don't care)
3789 internal_stats_cont (void *cls, int success)
3791 struct StatsCoreContext *core_context = cls;
3792 struct StatsIterateContext *stats_context =
3793 (struct StatsIterateContext *) core_context->iter_context;
3795 stats_context->connected--;
3796 stats_context->completed++;
3798 if (stats_context->completed == stats_context->total)
3800 stats_context->cont (stats_context->cls, GNUNET_YES);
3801 GNUNET_free (stats_context);
3804 if (core_context->stats_handle != NULL)
3805 GNUNET_STATISTICS_destroy (core_context->stats_handle, GNUNET_NO);
3807 GNUNET_free (core_context);
3811 * Check running topology iteration tasks, if below max start a new one, otherwise
3812 * schedule for some time in the future.
3815 schedule_get_statistics (void *cls,
3816 const struct GNUNET_SCHEDULER_TaskContext *tc)
3818 struct StatsCoreContext *core_context = cls;
3819 struct StatsIterateContext *stats_context =
3820 (struct StatsIterateContext *) core_context->iter_context;
3822 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3825 if (stats_context->connected > MAX_OUTSTANDING_CONNECTIONS)
3827 #if VERBOSE_TESTING > 2
3828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3830 ("Delaying connect, we have too many outstanding connections!\n"));
3832 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
3833 (GNUNET_TIME_UNIT_MILLISECONDS, 100),
3834 &schedule_get_statistics, core_context);
3838 #if VERBOSE_TESTING > 2
3839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3840 _("Creating connection, outstanding_connections is %d\n"),
3841 outstanding_connects);
3844 stats_context->connected++;
3845 core_context->stats_handle =
3846 GNUNET_STATISTICS_create ("testing", core_context->daemon->cfg);
3847 if (core_context->stats_handle == NULL)
3849 internal_stats_cont (core_context, GNUNET_NO);
3853 core_context->stats_get_handle =
3854 GNUNET_STATISTICS_get (core_context->stats_handle, NULL, NULL,
3855 GNUNET_TIME_relative_get_forever (),
3856 &internal_stats_cont, &internal_stats_callback,
3858 if (core_context->stats_get_handle == NULL)
3859 internal_stats_cont (core_context, GNUNET_NO);
3864 struct DuplicateStats
3867 * Next item in the list
3869 struct DuplicateStats *next;
3872 * Nasty string, concatenation of relevant information.
3874 char *unique_string;
3878 * Check whether the combination of port/host/unix domain socket
3879 * already exists in the list of peers being checked for statistics.
3881 * @param pg the peergroup in question
3882 * @param specific_peer the peer we're concerned with
3883 * @param stats_list the list to return to the caller
3885 * @return GNUNET_YES if the statistics instance has been seen already,
3886 * GNUNET_NO if not (and we may have added it to the list)
3889 stats_check_existing (struct GNUNET_TESTING_PeerGroup *pg,
3890 struct PeerData *specific_peer,
3891 struct DuplicateStats **stats_list)
3893 struct DuplicateStats *pos;
3894 char *unix_domain_socket;
3895 unsigned long long port;
3898 GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "testing",
3899 "single_statistics_per_host"))
3900 return GNUNET_NO; /* Each peer has its own statistics instance, do nothing! */
3904 GNUNET_CONFIGURATION_get_value_string (specific_peer->cfg, "statistics",
3905 "unixpath", &unix_domain_socket))
3909 GNUNET_CONFIGURATION_get_value_number (specific_peer->cfg, "statistics",
3912 GNUNET_free(unix_domain_socket);
3916 if (specific_peer->daemon->hostname != NULL)
3917 GNUNET_asprintf (&to_match, "%s%s%llu", specific_peer->daemon->hostname,
3918 unix_domain_socket, port);
3920 GNUNET_asprintf (&to_match, "%s%llu", unix_domain_socket, port);
3924 if (0 == strcmp (to_match, pos->unique_string))
3926 GNUNET_free (unix_domain_socket);
3927 GNUNET_free (to_match);
3932 pos = GNUNET_malloc (sizeof (struct DuplicateStats));
3933 pos->unique_string = to_match;
3934 pos->next = *stats_list;
3936 GNUNET_free (unix_domain_socket);
3941 * Iterate over all (running) peers in the peer group, retrieve
3942 * all statistics from each.
3945 GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg,
3946 GNUNET_STATISTICS_Callback cont,
3947 GNUNET_TESTING_STATISTICS_Iterator proc,
3950 struct StatsIterateContext *stats_context;
3951 struct StatsCoreContext *core_ctx;
3953 unsigned int total_count;
3954 struct DuplicateStats *stats_list;
3955 struct DuplicateStats *pos;
3958 /* Allocate a single stats iteration context */
3959 stats_context = GNUNET_malloc (sizeof (struct StatsIterateContext));
3960 stats_context->cont = cont;
3961 stats_context->proc = proc;
3962 stats_context->cls = cls;
3965 for (i = 0; i < pg->total; i++)
3967 if ((pg->peers[i].daemon->running == GNUNET_YES)
3969 stats_check_existing (pg, &pg->peers[i], &stats_list)))
3971 /* Allocate one core context per core we need to connect to */
3972 core_ctx = GNUNET_malloc (sizeof (struct StatsCoreContext));
3973 core_ctx->daemon = pg->peers[i].daemon;
3974 /* Set back pointer to topology iteration context */
3975 core_ctx->iter_context = stats_context;
3976 GNUNET_SCHEDULER_add_now (&schedule_get_statistics, core_ctx);
3981 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3982 "Retrieving stats from %u total instances.\n", total_count);
3983 stats_context->total = total_count;
3984 if (stats_list != NULL)
3989 GNUNET_free (pos->unique_string);
3990 stats_list = pos->next;
3992 pos = stats_list->next;
3999 * There are many ways to connect peers that are supported by this function.
4000 * To connect peers in the same topology that was created via the
4001 * GNUNET_TESTING_create_topology, the topology variable must be set to
4002 * GNUNET_TESTING_TOPOLOGY_NONE. If the topology variable is specified,
4003 * a new instance of that topology will be generated and attempted to be
4004 * connected. This could result in some connections being impossible,
4005 * because some topologies are non-deterministic.
4007 * @param pg the peer group struct representing the running peers
4008 * @param topology which topology to connect the peers in
4009 * @param options options for connecting the topology
4010 * @param option_modifier modifier for options that take a parameter
4011 * @param notify_callback notification to be called once all connections completed
4012 * @param notify_cls closure for notification callback
4014 * @return the number of connections that will be attempted, GNUNET_SYSERR on error
4017 GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
4018 enum GNUNET_TESTING_Topology topology,
4019 enum GNUNET_TESTING_TopologyOption options,
4020 double option_modifier,
4021 GNUNET_TESTING_NotifyCompletion
4022 notify_callback, void *notify_cls)
4026 case GNUNET_TESTING_TOPOLOGY_CLIQUE:
4027 #if VERBOSE_TOPOLOGY
4028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4029 _("Creating clique CONNECT topology\n"));
4031 create_clique (pg, &add_actual_connections);
4033 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
4034 #if VERBOSE_TOPOLOGY
4035 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4036 _("Creating small world (ring) CONNECT topology\n"));
4038 create_small_world_ring (pg, &add_actual_connections);
4040 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
4041 #if VERBOSE_TOPOLOGY
4042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4043 _("Creating small world (2d-torus) CONNECT topology\n"));
4045 create_small_world (pg, &add_actual_connections);
4047 case GNUNET_TESTING_TOPOLOGY_RING:
4048 #if VERBOSE_TOPOLOGY
4049 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4050 _("Creating ring CONNECT topology\n"));
4052 create_ring (pg, &add_actual_connections);
4054 case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
4055 #if VERBOSE_TOPOLOGY
4056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4057 _("Creating 2d torus CONNECT topology\n"));
4059 create_2d_torus (pg, &add_actual_connections);
4061 case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
4062 #if VERBOSE_TOPOLOGY
4063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4064 _("Creating Erdos-Renyi CONNECT topology\n"));
4066 create_erdos_renyi (pg, &add_actual_connections);
4068 case GNUNET_TESTING_TOPOLOGY_INTERNAT:
4069 #if VERBOSE_TOPOLOGY
4070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4071 _("Creating InterNAT CONNECT topology\n"));
4073 create_nated_internet (pg, &add_actual_connections);
4075 case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
4076 #if VERBOSE_TOPOLOGY
4077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4078 _("Creating Scale Free CONNECT topology\n"));
4080 create_scale_free (pg, &add_actual_connections);
4082 case GNUNET_TESTING_TOPOLOGY_LINE:
4083 #if VERBOSE_TOPOLOGY
4084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4085 _("Creating straight line CONNECT topology\n"));
4087 create_line (pg, &add_actual_connections);
4089 case GNUNET_TESTING_TOPOLOGY_NONE:
4090 #if VERBOSE_TOPOLOGY
4091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4092 _("Creating no CONNECT topology\n"));
4094 copy_allowed_topology (pg);
4097 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4099 ("Unknown topology specification, can't connect peers!\n"));
4100 return GNUNET_SYSERR;
4105 case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM:
4106 #if VERBOSE_TOPOLOGY
4107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4109 ("Connecting random subset (%'.2f percent) of possible peers\n"),
4110 100 * option_modifier);
4112 choose_random_connections (pg, option_modifier);
4114 case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM:
4115 #if VERBOSE_TOPOLOGY
4116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4117 _("Connecting a minimum of %u peers each (if possible)\n"),
4118 (unsigned int) option_modifier);
4120 choose_minimum (pg, (unsigned int) option_modifier);
4122 case GNUNET_TESTING_TOPOLOGY_OPTION_DFS:
4123 #if VERBOSE_TOPOLOGY
4124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4126 ("Using DFS to connect a minimum of %u peers each (if possible)\n"),
4127 (unsigned int) option_modifier);
4129 perform_dfs (pg, (int) option_modifier);
4131 case GNUNET_TESTING_TOPOLOGY_OPTION_ADD_CLOSEST:
4132 #if VERBOSE_TOPOLOGY
4133 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4135 ("Finding additional %u closest peers each (if possible)\n"),
4136 (unsigned int) option_modifier);
4138 add_closest (pg, (unsigned int) option_modifier,
4139 &add_actual_connections);
4141 case GNUNET_TESTING_TOPOLOGY_OPTION_NONE:
4143 case GNUNET_TESTING_TOPOLOGY_OPTION_ALL:
4149 return connect_topology (pg, notify_callback, notify_cls);
4153 * Callback that is called whenever a hostkey is generated
4154 * for a peer. Call the real callback and decrement the
4155 * starting counter for the peergroup.
4157 * @param cls closure
4158 * @param id identifier for the daemon, NULL on error
4159 * @param d handle for the daemon
4160 * @param emsg error message (NULL on success)
4163 internal_hostkey_callback (void *cls,
4164 const struct GNUNET_PeerIdentity *id,
4165 struct GNUNET_TESTING_Daemon *d, const char *emsg)
4167 struct InternalStartContext *internal_context = cls;
4168 internal_context->peer->pg->starting--;
4169 internal_context->peer->pg->started++;
4170 if (internal_context->hostkey_callback != NULL)
4171 internal_context->hostkey_callback (internal_context->hostkey_cls, id, d,
4173 else if (internal_context->peer->pg->started ==
4174 internal_context->peer->pg->total)
4176 internal_context->peer->pg->started = 0; /* Internal startup may use this counter! */
4177 GNUNET_TESTING_daemons_continue_startup (internal_context->peer->pg);
4182 * Callback that is called whenever a peer has finished starting.
4183 * Call the real callback and decrement the starting counter
4184 * for the peergroup.
4186 * @param cls closure
4187 * @param id identifier for the daemon, NULL on error
4189 * @param d handle for the daemon
4190 * @param emsg error message (NULL on success)
4193 internal_startup_callback (void *cls,
4194 const struct GNUNET_PeerIdentity *id,
4195 const struct GNUNET_CONFIGURATION_Handle *cfg,
4196 struct GNUNET_TESTING_Daemon *d, const char *emsg)
4198 struct InternalStartContext *internal_context = cls;
4199 internal_context->peer->pg->starting--;
4200 if (internal_context->start_cb != NULL)
4201 internal_context->start_cb (internal_context->start_cb_cls, id, cfg, d,
4206 internal_continue_startup (void *cls,
4207 const struct GNUNET_SCHEDULER_TaskContext *tc)
4209 struct InternalStartContext *internal_context = cls;
4211 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
4216 if (internal_context->peer->pg->starting < MAX_CONCURRENT_STARTING)
4218 internal_context->peer->pg->starting++;
4219 GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon);
4223 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
4224 (GNUNET_TIME_UNIT_MILLISECONDS, 100),
4225 &internal_continue_startup,
4232 * Callback for informing us about a successful
4233 * or unsuccessful churn start call.
4235 * @param cls a ChurnContext
4236 * @param id the peer identity of the started peer
4237 * @param cfg the handle to the configuration of the peer
4238 * @param d handle to the daemon for the peer
4239 * @param emsg NULL on success, non-NULL on failure
4243 churn_start_callback (void *cls,
4244 const struct GNUNET_PeerIdentity *id,
4245 const struct GNUNET_CONFIGURATION_Handle *cfg,
4246 struct GNUNET_TESTING_Daemon *d, const char *emsg)
4248 struct ChurnRestartContext *startup_ctx = cls;
4249 struct ChurnContext *churn_ctx = startup_ctx->churn_ctx;
4251 unsigned int total_left;
4252 char *error_message;
4254 error_message = NULL;
4257 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4258 "Churn stop callback failed with error `%s'\n", emsg);
4259 churn_ctx->num_failed_start++;
4263 churn_ctx->num_to_start--;
4267 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4268 "Started peer, %d left.\n", churn_ctx->num_to_start);
4272 (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) +
4273 (churn_ctx->num_to_start - churn_ctx->num_failed_start);
4275 if (total_left == 0)
4277 if ((churn_ctx->num_failed_stop > 0)
4278 || (churn_ctx->num_failed_start > 0))
4279 GNUNET_asprintf (&error_message,
4280 "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!",
4281 churn_ctx->num_failed_start,
4282 churn_ctx->num_failed_stop);
4283 churn_ctx->cb (churn_ctx->cb_cls, error_message);
4284 GNUNET_free_non_null (error_message);
4285 GNUNET_free (churn_ctx);
4286 GNUNET_free (startup_ctx);
4292 schedule_churn_restart (void *cls,
4293 const struct GNUNET_SCHEDULER_TaskContext *tc)
4295 struct PeerRestartContext *peer_restart_ctx = cls;
4296 struct ChurnRestartContext *startup_ctx =
4297 peer_restart_ctx->churn_restart_ctx;
4299 if (startup_ctx->outstanding > MAX_CONCURRENT_STARTING)
4300 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
4301 (GNUNET_TIME_UNIT_MILLISECONDS, 100),
4302 &schedule_churn_restart, peer_restart_ctx);
4305 GNUNET_TESTING_daemon_start_stopped (peer_restart_ctx->daemon,
4306 startup_ctx->timeout,
4307 &churn_start_callback,
4309 GNUNET_free (peer_restart_ctx);
4314 internal_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
4316 struct InternalStartContext *internal_context = cls;
4318 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
4323 if (internal_context->peer->pg->starting < MAX_CONCURRENT_HOSTKEYS)
4325 internal_context->peer->pg->starting++;
4326 internal_context->peer->daemon =
4327 GNUNET_TESTING_daemon_start (internal_context->peer->cfg,
4328 internal_context->timeout,
4329 internal_context->hostname,
4330 internal_context->username,
4331 internal_context->sshport,
4332 internal_context->hostkey,
4333 &internal_hostkey_callback,
4335 &internal_startup_callback,
4340 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
4341 (GNUNET_TIME_UNIT_MILLISECONDS, 100),
4342 &internal_start, internal_context);
4347 * Function which continues a peer group starting up
4348 * after successfully generating hostkeys for each peer.
4350 * @param pg the peer group to continue starting
4354 GNUNET_TESTING_daemons_continue_startup (struct GNUNET_TESTING_PeerGroup *pg)
4359 for (i = 0; i < pg->total; i++)
4361 GNUNET_SCHEDULER_add_now (&internal_continue_startup,
4362 &pg->peers[i].internal_context);
4363 //GNUNET_TESTING_daemon_continue_startup(pg->peers[i].daemon);
4368 * Start count gnunet instances with the same set of transports and
4369 * applications. The port numbers (any option called "PORT") will be
4370 * adjusted to ensure that no two peers running on the same system
4371 * have the same port(s) in their respective configurations.
4373 * @param cfg configuration template to use
4374 * @param total number of daemons to start
4375 * @param timeout total time allowed for peers to start
4376 * @param hostkey_callback function to call on each peers hostkey generation
4377 * if NULL, peers will be started by this call, if non-null,
4378 * GNUNET_TESTING_daemons_continue_startup must be called after
4379 * successful hostkey generation
4380 * @param hostkey_cls closure for hostkey callback
4381 * @param cb function to call on each daemon that was started
4382 * @param cb_cls closure for cb
4383 * @param connect_callback function to call each time two hosts are connected
4384 * @param connect_callback_cls closure for connect_callback
4385 * @param hostnames linked list of host structs to use to start peers on
4386 * (NULL to run on localhost only)
4388 * @return NULL on error, otherwise handle to control peer group
4390 struct GNUNET_TESTING_PeerGroup *
4391 GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
4393 struct GNUNET_TIME_Relative timeout,
4394 GNUNET_TESTING_NotifyHostkeyCreated
4395 hostkey_callback, void *hostkey_cls,
4396 GNUNET_TESTING_NotifyDaemonRunning cb,
4398 GNUNET_TESTING_NotifyConnection
4399 connect_callback, void *connect_callback_cls,
4400 const struct GNUNET_TESTING_Host *hostnames)
4402 struct GNUNET_TESTING_PeerGroup *pg;
4403 const struct GNUNET_TESTING_Host *hostpos;
4409 const char *hostname;
4410 const char *username;
4411 char *baseservicehome;
4412 char *newservicehome;
4414 char *hostkeys_file;
4416 struct GNUNET_DISK_FileHandle *fd;
4417 struct GNUNET_CONFIGURATION_Handle *pcfg;
4419 unsigned int hostcnt;
4425 uint64_t total_hostkeys;
4432 hostkey_data = NULL;
4435 pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
4437 pg->notify_connection = connect_callback;
4438 pg->notify_connection_cls = connect_callback_cls;
4440 pg->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
4441 pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
4442 if (NULL != hostnames)
4445 hostpos = hostnames;
4446 while (hostpos != NULL)
4448 hostpos = hostpos->next;
4451 pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
4454 hostpos = hostnames;
4455 while (hostpos != NULL)
4457 pg->hosts[off].minport = LOW_PORT;
4458 pg->hosts[off].hostname = GNUNET_strdup (hostpos->hostname);
4459 if (hostpos->username != NULL)
4460 pg->hosts[off].username = GNUNET_strdup (hostpos->username);
4461 pg->hosts[off].sshport = hostpos->port;
4462 hostpos = hostpos->next;
4472 pg->num_hosts = off;
4476 /* skip leading spaces */
4477 while ((0 != *hostnames) && (isspace ((unsigned char) *hostnames)))
4480 while ('\0' != *rpos)
4482 if (isspace ((unsigned char) *rpos))
4486 pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
4488 start = GNUNET_strdup (hostnames);
4490 while ('\0' != *pos)
4492 if (isspace ((unsigned char) *pos))
4495 if (strlen (start) > 0)
4497 pg->hosts[off].minport = LOW_PORT;
4498 pg->hosts[off++].hostname = start;
4504 if (strlen (start) > 0)
4506 pg->hosts[off].minport = LOW_PORT;
4507 pg->hosts[off++].hostname = start;
4511 GNUNET_free (start);
4512 GNUNET_free (pg->hosts);
4516 minport = 0; /* make gcc happy */
4525 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "HOSTKEYSFILE",
4528 if (GNUNET_YES != GNUNET_DISK_file_test (hostkeys_file))
4529 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Couldn't read hostkeys file!");
4532 /* Check hostkey file size, read entire thing into memory */
4533 fd = GNUNET_DISK_file_open (hostkeys_file, GNUNET_DISK_OPEN_READ,
4534 GNUNET_DISK_PERM_NONE);
4537 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", hostkeys_file);
4541 if (GNUNET_YES != GNUNET_DISK_file_size (hostkeys_file, &fs, GNUNET_YES))
4544 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Found file size %llu for hostkeys, expect hostkeys to be size %d\n", fs, HOSTKEYFILESIZE);
4546 if (fs % HOSTKEYFILESIZE != 0)
4548 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "File size %llu seems incorrect for hostkeys...\n", fs);
4552 total_hostkeys = fs / HOSTKEYFILESIZE;
4553 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Will read %llu hostkeys from file\n", total_hostkeys);
4554 hostkey_data = GNUNET_malloc_large (fs);
4555 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, hostkey_data, fs));
4560 for (off = 0; off < total; off++)
4564 hostname = pg->hosts[off % hostcnt].hostname;
4565 username = pg->hosts[off % hostcnt].username;
4566 sshport = pg->hosts[off % hostcnt].sshport;
4567 pcfg = make_config (cfg,
4568 &pg->hosts[off % hostcnt].minport,
4569 &upnum, hostname, &fdnum);
4576 pcfg = make_config (cfg, &minport, &upnum, hostname, &fdnum);
4581 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4583 ("Could not create configuration for peer number %u on `%s'!\n"),
4584 off, hostname == NULL ? "localhost" : hostname);
4589 GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME",
4592 GNUNET_asprintf (&newservicehome, "%s/%d/", baseservicehome, off);
4593 GNUNET_free (baseservicehome);
4597 tmpdir = getenv ("TMPDIR");
4598 tmpdir = tmpdir ? tmpdir : "/tmp";
4599 GNUNET_asprintf (&newservicehome,
4601 tmpdir, "gnunet-testing-test-test", off);
4603 GNUNET_CONFIGURATION_set_value_string (pcfg,
4605 "SERVICEHOME", newservicehome);
4606 GNUNET_free (newservicehome);
4607 pg->peers[off].cfg = pcfg;
4608 pg->peers[off].allowed_peers =
4609 GNUNET_CONTAINER_multihashmap_create (total);
4610 pg->peers[off].connect_peers =
4611 GNUNET_CONTAINER_multihashmap_create (total);
4612 pg->peers[off].blacklisted_peers =
4613 GNUNET_CONTAINER_multihashmap_create (total);
4614 pg->peers[off].pg = pg;
4616 pg->peers[off].internal_context.peer = &pg->peers[off];
4617 pg->peers[off].internal_context.timeout = timeout;
4618 pg->peers[off].internal_context.hostname = hostname;
4619 pg->peers[off].internal_context.username = username;
4620 pg->peers[off].internal_context.sshport = sshport;
4621 if (hostkey_data != NULL)
4622 pg->peers[off].internal_context.hostkey = &hostkey_data[off * HOSTKEYFILESIZE];
4623 pg->peers[off].internal_context.hostkey_callback = hostkey_callback;
4624 pg->peers[off].internal_context.hostkey_cls = hostkey_cls;
4625 pg->peers[off].internal_context.start_cb = cb;
4626 pg->peers[off].internal_context.start_cb_cls = cb_cls;
4628 GNUNET_SCHEDULER_add_now (&internal_start,
4629 &pg->peers[off].internal_context);
4636 * Get a daemon by number, so callers don't have to do nasty
4637 * offsetting operation.
4639 struct GNUNET_TESTING_Daemon *
4640 GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg,
4641 unsigned int position)
4643 if (position < pg->total)
4644 return pg->peers[position].daemon;
4650 * Get a daemon by peer identity, so callers can
4651 * retrieve the daemon without knowing it's offset.
4653 * @param pg the peer group to retrieve the daemon from
4654 * @param peer_id the peer identity of the daemon to retrieve
4656 * @return the daemon on success, or NULL if no such peer identity is found
4658 struct GNUNET_TESTING_Daemon *
4659 GNUNET_TESTING_daemon_get_by_id (struct GNUNET_TESTING_PeerGroup *pg,
4660 struct GNUNET_PeerIdentity *peer_id)
4664 for (i = 0; i < pg->total; i++)
4667 memcmp (&pg->peers[i].daemon->id, peer_id,
4668 sizeof (struct GNUNET_PeerIdentity)))
4669 return pg->peers[i].daemon;
4676 * Prototype of a function that will be called when a
4677 * particular operation was completed the testing library.
4679 * @param cls closure (a struct RestartContext)
4680 * @param id id of the peer that was restarted
4681 * @param cfg handle to the configuration of the peer
4682 * @param d handle to the daemon that was restarted
4683 * @param emsg NULL on success
4686 restart_callback (void *cls,
4687 const struct GNUNET_PeerIdentity *id,
4688 const struct GNUNET_CONFIGURATION_Handle *cfg,
4689 struct GNUNET_TESTING_Daemon *d, const char *emsg)
4691 struct RestartContext *restart_context = cls;
4695 restart_context->peers_restarted++;
4699 restart_context->peers_restart_failed++;
4702 if (restart_context->peers_restarted == restart_context->peer_group->total)
4704 restart_context->callback (restart_context->callback_cls, NULL);
4705 GNUNET_free (restart_context);
4707 else if (restart_context->peers_restart_failed +
4708 restart_context->peers_restarted ==
4709 restart_context->peer_group->total)
4711 restart_context->callback (restart_context->callback_cls,
4712 "Failed to restart peers!");
4713 GNUNET_free (restart_context);
4719 * Callback for informing us about a successful
4720 * or unsuccessful churn stop call.
4722 * @param cls a ChurnContext
4723 * @param emsg NULL on success, non-NULL on failure
4727 churn_stop_callback (void *cls, const char *emsg)
4729 struct ShutdownContext *shutdown_ctx = cls;
4730 struct ChurnContext *churn_ctx = shutdown_ctx->cb_cls;
4731 unsigned int total_left;
4732 char *error_message;
4734 error_message = NULL;
4735 shutdown_ctx->outstanding--;
4739 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4740 "Churn stop callback failed with error `%s'\n", emsg);
4741 churn_ctx->num_failed_stop++;
4745 churn_ctx->num_to_stop--;
4749 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4750 "Stopped peer, %d left.\n", churn_ctx->num_to_stop);
4753 (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) +
4754 (churn_ctx->num_to_start - churn_ctx->num_failed_start);
4756 if (total_left == 0)
4758 if ((churn_ctx->num_failed_stop > 0)
4759 || (churn_ctx->num_failed_start > 0))
4761 GNUNET_asprintf (&error_message,
4762 "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!",
4763 churn_ctx->num_failed_start,
4764 churn_ctx->num_failed_stop);
4766 churn_ctx->cb (churn_ctx->cb_cls, error_message);
4767 GNUNET_free_non_null (error_message);
4768 GNUNET_free (churn_ctx);
4769 GNUNET_free (shutdown_ctx);
4774 * Count the number of running peers.
4776 * @param pg handle for the peer group
4778 * @return the number of currently running peers in the peer group
4781 GNUNET_TESTING_daemons_running (struct GNUNET_TESTING_PeerGroup *pg)
4784 unsigned int running = 0;
4785 for (i = 0; i < pg->total; i++)
4787 if (pg->peers[i].daemon->running == GNUNET_YES)
4789 GNUNET_assert (running != -1);
4797 * Task to rate limit the number of outstanding peer shutdown
4798 * requests. This is necessary for making sure we don't do
4799 * too many ssh connections at once, but is generally nicer
4800 * to any system as well (graduated task starts, as opposed
4801 * to calling gnunet-arm N times all at once).
4804 schedule_churn_shutdown_task (void *cls,
4805 const struct GNUNET_SCHEDULER_TaskContext *tc)
4807 struct PeerShutdownContext *peer_shutdown_ctx = cls;
4808 struct ShutdownContext *shutdown_ctx;
4810 GNUNET_assert (peer_shutdown_ctx != NULL);
4811 shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
4812 GNUNET_assert (shutdown_ctx != NULL);
4814 if (shutdown_ctx->outstanding > MAX_CONCURRENT_SHUTDOWN)
4815 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
4816 (GNUNET_TIME_UNIT_MILLISECONDS, 100),
4817 &schedule_churn_shutdown_task,
4821 shutdown_ctx->outstanding++;
4822 GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon,
4823 shutdown_ctx->timeout, shutdown_ctx->cb,
4824 shutdown_ctx, GNUNET_NO, GNUNET_YES);
4825 GNUNET_free (peer_shutdown_ctx);
4830 * Simulate churn by stopping some peers (and possibly
4831 * re-starting others if churn is called multiple times). This
4832 * function can only be used to create leave-join churn (peers "never"
4833 * leave for good). First "voff" random peers that are currently
4834 * online will be taken offline; then "von" random peers that are then
4835 * offline will be put back online. No notifications will be
4836 * generated for any of these operations except for the callback upon
4839 * @param pg handle for the peer group
4840 * @param voff number of peers that should go offline
4841 * @param von number of peers that should come back online;
4842 * must be zero on first call (since "testbed_start"
4843 * always starts all of the peers)
4844 * @param timeout how long to wait for operations to finish before
4846 * @param cb function to call at the end
4847 * @param cb_cls closure for cb
4850 GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg,
4853 struct GNUNET_TIME_Relative timeout,
4854 GNUNET_TESTING_NotifyCompletion cb,
4857 struct ChurnContext *churn_ctx;
4858 struct ShutdownContext *shutdown_ctx;
4859 struct PeerShutdownContext *peer_shutdown_ctx;
4860 struct PeerRestartContext *peer_restart_ctx;
4861 struct ChurnRestartContext *churn_startup_ctx;
4863 unsigned int running;
4864 unsigned int stopped;
4865 unsigned int total_running;
4866 unsigned int total_stopped;
4868 unsigned int *running_arr;
4869 unsigned int *stopped_arr;
4870 unsigned int *running_permute;
4871 unsigned int *stopped_permute;
4876 if ((von == 0) && (voff == 0)) /* No peers at all? */
4882 for (i = 0; i < pg->total; i++)
4884 if (pg->peers[i].daemon->running == GNUNET_YES)
4886 GNUNET_assert (running != -1);
4891 GNUNET_assert (stopped != -1);
4898 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4899 "Trying to stop more peers than are currently running!\n");
4900 cb (cb_cls, "Trying to stop more peers than are currently running!");
4906 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4907 "Trying to start more peers than are currently stopped!\n");
4908 cb (cb_cls, "Trying to start more peers than are currently stopped!");
4912 churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext));
4916 running_arr = GNUNET_malloc (running * sizeof (unsigned int));
4920 stopped_arr = GNUNET_malloc (stopped * sizeof (unsigned int));
4922 running_permute = NULL;
4923 stopped_permute = NULL;
4927 GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, running);
4930 GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, stopped);
4932 total_running = running;
4933 total_stopped = stopped;
4937 churn_ctx->num_to_start = von;
4938 churn_ctx->num_to_stop = voff;
4940 churn_ctx->cb_cls = cb_cls;
4942 for (i = 0; i < pg->total; i++)
4944 if (pg->peers[i].daemon->running == GNUNET_YES)
4946 GNUNET_assert ((running_arr != NULL) && (total_running > running));
4947 running_arr[running] = i;
4952 GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped));
4953 stopped_arr[stopped] = i;
4958 GNUNET_assert (running >= voff);
4961 shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext));
4962 shutdown_ctx->cb = &churn_stop_callback;
4963 shutdown_ctx->cb_cls = churn_ctx;
4964 shutdown_ctx->total_peers = voff;
4965 shutdown_ctx->timeout = timeout;
4968 for (i = 0; i < voff; i++)
4971 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %d!\n",
4972 running_permute[i]);
4974 GNUNET_assert (running_arr != NULL);
4975 peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext));
4976 peer_shutdown_ctx->daemon =
4977 pg->peers[running_arr[running_permute[i]]].daemon;
4978 peer_shutdown_ctx->shutdown_ctx = shutdown_ctx;
4979 GNUNET_SCHEDULER_add_now (&schedule_churn_shutdown_task,
4983 GNUNET_TESTING_daemon_stop (pg->peers[running_arr[running_permute[i]]].daemon,
4985 &churn_stop_callback, churn_ctx,
4986 GNUNET_NO, GNUNET_YES); */
4989 GNUNET_assert (stopped >= von);
4992 churn_startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext));
4993 churn_startup_ctx->churn_ctx = churn_ctx;
4994 churn_startup_ctx->timeout = timeout;
4996 for (i = 0; i < von; i++)
4999 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting up peer %d!\n",
5000 stopped_permute[i]);
5002 GNUNET_assert (stopped_arr != NULL);
5003 peer_restart_ctx = GNUNET_malloc (sizeof (struct PeerRestartContext));
5004 peer_restart_ctx->churn_restart_ctx = churn_startup_ctx;
5005 peer_restart_ctx->daemon =
5006 pg->peers[stopped_arr[stopped_permute[i]]].daemon;
5007 GNUNET_SCHEDULER_add_now (&schedule_churn_restart, peer_restart_ctx);
5009 GNUNET_TESTING_daemon_start_stopped(pg->peers[stopped_arr[stopped_permute[i]]].daemon,
5010 timeout, &churn_start_callback, churn_ctx); */
5013 GNUNET_free_non_null (running_arr);
5014 GNUNET_free_non_null (stopped_arr);
5015 GNUNET_free_non_null (running_permute);
5016 GNUNET_free_non_null (stopped_permute);
5021 * Restart all peers in the given group.
5023 * @param pg the handle to the peer group
5024 * @param callback function to call on completion (or failure)
5025 * @param callback_cls closure for the callback function
5028 GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg,
5029 GNUNET_TESTING_NotifyCompletion callback,
5032 struct RestartContext *restart_context;
5037 restart_context = GNUNET_malloc (sizeof (struct RestartContext));
5038 restart_context->peer_group = pg;
5039 restart_context->peers_restarted = 0;
5040 restart_context->callback = callback;
5041 restart_context->callback_cls = callback_cls;
5043 for (off = 0; off < pg->total; off++)
5045 GNUNET_TESTING_daemon_restart (pg->peers[off].daemon,
5046 &restart_callback, restart_context);
5052 * Start or stop an individual peer from the given group.
5054 * @param pg handle to the peer group
5055 * @param offset which peer to start or stop
5056 * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it
5057 * @param timeout how long to wait for shutdown
5058 * @param cb function to call at the end
5059 * @param cb_cls closure for cb
5062 GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg,
5063 unsigned int offset,
5065 struct GNUNET_TIME_Relative timeout,
5066 GNUNET_TESTING_NotifyCompletion cb, void *cb_cls)
5068 struct ShutdownContext *shutdown_ctx;
5069 struct ChurnRestartContext *startup_ctx;
5070 struct ChurnContext *churn_ctx;
5072 if (GNUNET_NO == desired_status)
5074 if (NULL != pg->peers[offset].daemon)
5076 shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext));
5077 churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext));
5078 churn_ctx->num_to_start = 0;
5079 churn_ctx->num_to_stop = 1;
5081 churn_ctx->cb_cls = cb_cls;
5082 shutdown_ctx->cb_cls = churn_ctx;
5083 GNUNET_TESTING_daemon_stop (pg->peers[offset].daemon,
5084 timeout, &churn_stop_callback,
5085 shutdown_ctx, GNUNET_NO, GNUNET_YES);
5088 else if (GNUNET_YES == desired_status)
5090 if (NULL == pg->peers[offset].daemon)
5092 startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext));
5093 churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext));
5094 churn_ctx->num_to_start = 1;
5095 churn_ctx->num_to_stop = 0;
5097 churn_ctx->cb_cls = cb_cls;
5098 startup_ctx->churn_ctx = churn_ctx;
5099 GNUNET_TESTING_daemon_start_stopped (pg->peers[offset].daemon,
5100 timeout, &churn_start_callback,
5110 * Callback for shutting down peers in a peer group.
5112 * @param cls closure (struct ShutdownContext)
5113 * @param emsg NULL on success
5116 internal_shutdown_callback (void *cls, const char *emsg)
5118 struct ShutdownContext *shutdown_ctx = cls;
5120 shutdown_ctx->outstanding--;
5123 shutdown_ctx->peers_down++;
5127 shutdown_ctx->peers_failed++;
5130 if ((shutdown_ctx->cb != NULL)
5131 && (shutdown_ctx->peers_down + shutdown_ctx->peers_failed ==
5132 shutdown_ctx->total_peers))
5134 if (shutdown_ctx->peers_failed > 0)
5135 shutdown_ctx->cb (shutdown_ctx->cb_cls,
5136 "Not all peers successfully shut down!");
5138 shutdown_ctx->cb (shutdown_ctx->cb_cls, NULL);
5139 GNUNET_free (shutdown_ctx);
5145 * Task to rate limit the number of outstanding peer shutdown
5146 * requests. This is necessary for making sure we don't do
5147 * too many ssh connections at once, but is generally nicer
5148 * to any system as well (graduated task starts, as opposed
5149 * to calling gnunet-arm N times all at once).
5152 schedule_shutdown_task (void *cls,
5153 const struct GNUNET_SCHEDULER_TaskContext *tc)
5155 struct PeerShutdownContext *peer_shutdown_ctx = cls;
5156 struct ShutdownContext *shutdown_ctx;
5158 GNUNET_assert (peer_shutdown_ctx != NULL);
5159 shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
5160 GNUNET_assert (shutdown_ctx != NULL);
5162 if (shutdown_ctx->outstanding > MAX_CONCURRENT_SHUTDOWN)
5163 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
5164 (GNUNET_TIME_UNIT_MILLISECONDS, 100),
5165 &schedule_shutdown_task, peer_shutdown_ctx);
5168 shutdown_ctx->outstanding++;
5169 GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon,
5170 shutdown_ctx->timeout,
5171 &internal_shutdown_callback, shutdown_ctx,
5172 GNUNET_YES, GNUNET_NO);
5173 GNUNET_free (peer_shutdown_ctx);
5178 * Shutdown all peers started in the given group.
5180 * @param pg handle to the peer group
5181 * @param timeout how long to wait for shutdown
5182 * @param cb callback to notify upon success or failure
5183 * @param cb_cls closure for cb
5186 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg,
5187 struct GNUNET_TIME_Relative timeout,
5188 GNUNET_TESTING_NotifyCompletion cb, void *cb_cls)
5191 struct ShutdownContext *shutdown_ctx;
5192 struct PeerShutdownContext *peer_shutdown_ctx;
5194 GNUNET_assert (pg->total > 0);
5196 shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext));
5197 shutdown_ctx->cb = cb;
5198 shutdown_ctx->cb_cls = cb_cls;
5199 shutdown_ctx->total_peers = pg->total;
5200 shutdown_ctx->timeout = timeout;
5201 /* shtudown_ctx->outstanding = 0; */
5203 for (off = 0; off < pg->total; off++)
5205 GNUNET_assert (NULL != pg->peers[off].daemon);
5206 peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext));
5207 peer_shutdown_ctx->daemon = pg->peers[off].daemon;
5208 peer_shutdown_ctx->shutdown_ctx = shutdown_ctx;
5209 GNUNET_SCHEDULER_add_now (&schedule_shutdown_task, peer_shutdown_ctx);
5210 //GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, timeout, shutdown_cb, shutdown_ctx, GNUNET_YES, GNUNET_NO);
5211 if (NULL != pg->peers[off].cfg)
5212 GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
5213 if (pg->peers[off].allowed_peers != NULL)
5214 GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].allowed_peers);
5215 if (pg->peers[off].connect_peers != NULL)
5216 GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].connect_peers);
5217 if (pg->peers[off].blacklisted_peers != NULL)
5218 GNUNET_CONTAINER_multihashmap_destroy (pg->
5219 peers[off].blacklisted_peers);
5221 GNUNET_free (pg->peers);
5222 for (off = 0; off < pg->num_hosts; off++)
5224 GNUNET_free (pg->hosts[off].hostname);
5225 GNUNET_free_non_null (pg->hosts[off].username);
5227 GNUNET_free_non_null (pg->hosts);
5232 /* end of testing_group.c */