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 2, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file testing/testing_group.c
23 * @brief convenience API for writing testcases for GNUnet
24 * @author Christian Grothoff
27 #include "gnunet_arm_service.h"
28 #include "gnunet_testing_lib.h"
30 #define VERBOSE_TESTING GNUNET_NO
33 * Lowest port used for GNUnet testing. Should be high enough to not
34 * conflict with other applications running on the hosts but be low
35 * enough to not conflict with client-ports (typically starting around
38 #define LOW_PORT 10000
41 * Highest port used for GNUnet testing. Should be low enough to not
42 * conflict with the port range for "local" ports (client apps; see
43 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
45 #define HIGH_PORT 32000
47 #define MAX_OUTSTANDING_CONNECTIONS 50
49 #define CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 160)
51 #define CONNECT_ATTEMPTS 8
54 * Prototype of a function called whenever two peers would be connected
55 * in a certain topology.
57 typedef int (*GNUNET_TESTING_ConnectionProcessor)
58 (struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second);
63 * The group of peers being restarted
65 struct GNUNET_TESTING_PeerGroup *peer_group;
68 * How many peers have been restarted thus far
70 unsigned int peers_restarted;
73 * How many peers got an error when restarting
75 unsigned int peers_restart_failed;
78 * The function to call once all peers have been restarted
80 GNUNET_TESTING_NotifyCompletion callback;
83 * Closure for callback function
89 struct CreateTopologyContext
93 * Function to call with number of connections
95 GNUNET_TESTING_NotifyConnections cont;
98 * Closure for connection notification
104 struct PeerConnection
109 struct PeerConnection *next;
112 * Pointer to daemon handle
114 struct GNUNET_TESTING_Daemon *daemon;
120 * Data we keep per peer.
125 * (Initial) configuration of the host.
126 * (initial because clients could change
127 * it and we would not know about those
130 struct GNUNET_CONFIGURATION_Handle *cfg;
133 * Handle for controlling the daemon.
135 struct GNUNET_TESTING_Daemon *daemon;
138 * The peergroup this peer belongs to.
140 struct GNUNET_TESTING_PeerGroup *pg;
143 * Linked list of peer connections (pointers)
145 //struct PeerConnection *connected_peers;
147 * Hash map of allowed peer connections (F2F created topology)
149 struct GNUNET_CONTAINER_MultiHashMap *allowed_peers;
152 * Hash map of blacklisted peers
154 struct GNUNET_CONTAINER_MultiHashMap *blacklisted_peers;
157 * Hash map of peer connections
159 struct GNUNET_CONTAINER_MultiHashMap *connect_peers;
162 * Temporary hash map of peer connections
164 struct GNUNET_CONTAINER_MultiHashMap *connect_peers_working_set;
167 * Temporary variable for topology creation, should be reset before
168 * creating any topology so the count is valid once finished.
175 * Data we keep per host.
185 * Lowest port that we have not yet used
193 * Handle to a group of GNUnet peers.
195 struct GNUNET_TESTING_PeerGroup
200 struct GNUNET_SCHEDULER_Handle *sched;
203 * Configuration template.
205 const struct GNUNET_CONFIGURATION_Handle *cfg;
208 * Function to call on each started daemon.
210 GNUNET_TESTING_NotifyDaemonRunning cb;
218 * Function to call on each topology connection created
220 GNUNET_TESTING_NotifyConnection notify_connection;
223 * Callback for notify_connection
225 void *notify_connection_cls;
228 * NULL-terminated array of information about
231 struct HostData *hosts;
234 * Array of "total" peers.
236 struct PeerData *peers;
239 * Number of peers in this group.
244 * At what time should we fail the peer startup process?
246 struct GNUNET_TIME_Absolute max_timeout;
250 * Convert unique ID to hash code.
252 * @param uid unique ID to convert
253 * @param hash set to uid (extended with zeros)
256 hash_from_uid (uint32_t uid,
257 GNUNET_HashCode *hash)
259 memset (hash, 0, sizeof(GNUNET_HashCode));
260 *((uint32_t*)hash) = uid;
264 * Convert hash code to unique ID.
266 * @param uid unique ID to convert
267 * @param hash set to uid (extended with zeros)
270 uid_from_hash (const GNUNET_HashCode *hash, uint32_t *uid)
272 memcpy (uid, hash, sizeof(uint32_t));
277 struct GNUNET_CONFIGURATION_Handle *ret;
279 const char *hostname;
283 struct ConnectContext
285 struct GNUNET_TESTING_Daemon *first;
287 struct GNUNET_TESTING_Daemon *second;
289 struct GNUNET_TESTING_PeerGroup *pg;
293 * Number of connects we are waiting on, allows us to rate limit
296 static int outstanding_connects;
300 * Function to iterate over options. Copies
301 * the options to the target configuration,
302 * updating PORT values as needed.
305 * @param section name of the section
306 * @param option name of the option
307 * @param value value of the option
310 update_config (void *cls,
311 const char *section, const char *option, const char *value)
313 struct UpdateContext *ctx = cls;
317 if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival)))
319 GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++);
323 if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL))
325 value = ctx->hostname;
328 GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value);
333 * Create a new configuration using the given configuration
334 * as a template; however, each PORT in the existing cfg
335 * must be renumbered by incrementing "*port". If we run
336 * out of "*port" numbers, return NULL.
338 * @param cfg template configuration
339 * @param port port numbers to use, update to reflect
340 * port numbers that were used
341 * @param hostname hostname of the controlling host, to allow control connections from
343 * @return new configuration, NULL on error
345 static struct GNUNET_CONFIGURATION_Handle *
346 make_config (const struct GNUNET_CONFIGURATION_Handle *cfg, uint16_t * port, const char *hostname)
348 struct UpdateContext uc;
355 uc.ret = GNUNET_CONFIGURATION_create ();
356 uc.hostname = hostname;
358 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
359 if (uc.nport >= HIGH_PORT)
362 GNUNET_CONFIGURATION_destroy (uc.ret);
366 if (GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "control_host", &control_host) == GNUNET_OK)
368 GNUNET_asprintf(&allowed_hosts, "%s; 127.0.0.1;", control_host);
369 GNUNET_CONFIGURATION_set_value_string(uc.ret, "core", "ACCEPT_FROM", allowed_hosts);
370 GNUNET_free_non_null(control_host);
371 GNUNET_free(allowed_hosts);
375 /* arm needs to know to allow connections from the host on which it is running,
376 * otherwise gnunet-arm is unable to connect to it in some instances */
377 if (hostname != NULL)
379 GNUNET_asprintf(&allowed_hosts, "%s; 127.0.0.1;", hostname);
380 GNUNET_CONFIGURATION_set_value_string(uc.ret, "arm", "ACCEPT_FROM", allowed_hosts);
381 GNUNET_free(allowed_hosts);
384 *port = (uint16_t) uc.nport;
390 * Add entries to the peers connect list
392 * @param pg the peer group we are working with
393 * @param first index of the first peer
394 * @param second index of the second peer
396 * @return the number of connections added (can be 0, 1 or 2)
397 * technically should only be 0 or 2, but the small price
398 * of iterating over the lists (hashmaps in the future)
399 * for being sure doesn't bother me!
403 add_actual_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
409 GNUNET_HashCode hash_first;
410 GNUNET_HashCode hash_second;
412 hash_from_uid(first, &hash_first);
413 hash_from_uid(second, &hash_second);
415 add_first = GNUNET_NO;
416 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[first].connect_peers, &hash_second))
418 add_first = GNUNET_YES;
421 add_second = GNUNET_NO;
422 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[second].connect_peers, &hash_first))
424 add_second = GNUNET_YES;
430 GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[first].connect_peers, &hash_second, pg->peers[second].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
431 pg->peers[first].num_connections++;
437 GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[second].connect_peers, &hash_first, pg->peers[first].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
438 pg->peers[second].num_connections++;
447 * Add entries to the peers allowed connections list
449 * @param pg the peer group we are working with
450 * @param first index of the first peer
451 * @param second index of the second peer
453 * @return the number of connections added (can be 0, 1 or 2)
454 * technically should only be 0 or 2, but the small price
455 * of iterating over the lists (hashmaps in the future)
456 * for being sure doesn't bother me!
460 add_allowed_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
464 struct PeerConnection *first_iter;
465 struct PeerConnection *second_iter;
466 struct PeerConnection *new_first;
467 struct PeerConnection *new_second;
472 GNUNET_HashCode hash_first;
473 GNUNET_HashCode hash_second;
475 hash_from_uid(first, &hash_first);
476 hash_from_uid(second, &hash_second);
478 add_first = GNUNET_NO;
479 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[first].allowed_peers, &hash_second))
481 add_first = GNUNET_YES;
484 add_second = GNUNET_NO;
485 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[second].allowed_peers, &hash_first))
487 add_second = GNUNET_YES;
490 first_iter = pg->peers[first].connected_peers;
491 while (first_iter != NULL)
493 if (first_iter->daemon == pg->peers[second].daemon)
494 add_first = GNUNET_NO;
495 first_iter = first_iter->next;
498 second_iter = pg->peers[second].connected_peers;
499 add_second = GNUNET_YES;
500 while (second_iter != NULL)
502 if (second_iter->daemon == pg->peers[first].daemon)
503 add_second = GNUNET_NO;
504 second_iter = second_iter->next;
511 GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[first].allowed_peers, &hash_second, pg->peers[second].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
513 new_first = GNUNET_malloc(sizeof(struct PeerConnection));
514 new_first->daemon = pg->peers[second].daemon;
515 new_first->next = pg->peers[first].connected_peers;
516 pg->peers[first].connected_peers = new_first;
518 pg->peers[first].num_connections++;
524 GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[second].allowed_peers, &hash_first, pg->peers[first].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
526 new_second = GNUNET_malloc(sizeof(struct PeerConnection));
527 new_second->daemon = pg->peers[first].daemon;
528 new_second->next = pg->peers[second].connected_peers;
529 pg->peers[second].connected_peers = new_second;
530 pg->peers[first].num_connections++;
532 pg->peers[second].num_connections++;
540 * Add entries to the peers blacklisted list
542 * @param pg the peer group we are working with
543 * @param first index of the first peer
544 * @param second index of the second peer
546 * @return the number of connections added (can be 0, 1 or 2)
550 blacklist_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
555 GNUNET_HashCode hash_first;
556 GNUNET_HashCode hash_second;
558 hash_from_uid(first, &hash_first);
559 hash_from_uid(second, &hash_second);
561 add_first = GNUNET_NO;
562 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[first].blacklisted_peers, &hash_second))
564 add_first = GNUNET_YES;
567 add_second = GNUNET_NO;
568 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[second].blacklisted_peers, &hash_first))
570 add_second = GNUNET_YES;
576 GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[first].blacklisted_peers, &hash_second, pg->peers[second].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
577 pg->peers[first].num_connections++;
583 GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[second].blacklisted_peers, &hash_first, pg->peers[first].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
584 pg->peers[second].num_connections++;
592 * Remove entries from the peers blacklisted list
594 * @param pg the peer group we are working with
595 * @param first index of the first peer
596 * @param second index of the second peer
598 * @return the number of connections removed (can be 0, 1 or 2)
602 unblacklist_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
607 GNUNET_HashCode hash_first;
608 GNUNET_HashCode hash_second;
610 hash_from_uid(first, &hash_first);
611 hash_from_uid(second, &hash_second);
613 remove_first = GNUNET_CONTAINER_multihashmap_contains(pg->peers[first].blacklisted_peers, &hash_second);
614 remove_second = GNUNET_CONTAINER_multihashmap_contains(pg->peers[second].blacklisted_peers, &hash_first);
619 GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(pg->peers[first].blacklisted_peers, &hash_second, pg->peers[second].daemon));
625 GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(pg->peers[second].blacklisted_peers, &hash_first, pg->peers[first].daemon));
633 * Scale free network construction as described in:
635 * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999.
637 * Start with a network of "one" peer, then progressively add
638 * peers up to the total number. At each step, iterate over
639 * all possible peers and connect new peer based on number of
640 * existing connections of the target peer.
642 * @param pg the peer group we are dealing with
643 * @param proc the connection processor to use
645 * @return the number of connections created
648 create_scale_free (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
651 unsigned int total_connections;
652 unsigned int outer_count;
654 unsigned int previous_total_connections;
658 GNUNET_assert(pg->total > 1);
660 /* Add a connection between the first two nodes */
661 total_connections = proc(pg, 0, 1);
663 for (outer_count = 1; outer_count < pg->total; outer_count++)
665 previous_total_connections = total_connections;
666 for (i = 0; i < outer_count; i++)
668 probability = pg->peers[i].num_connections / (double)previous_total_connections;
669 random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
670 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
673 "Considering connecting peer %d to peer %d\n",
676 if (random < probability)
679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680 "Connecting peer %d to peer %d\n",
683 total_connections += proc(pg, outer_count, i);
688 return total_connections;
692 create_small_world_ring(struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
697 unsigned int randomPeer;
698 double random, logNModifier, percentage;
699 unsigned int smallWorldConnections;
705 int connect_attempts;
707 logNModifier = 0.5; /* FIXME: default value? */
708 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
713 if (sscanf(p_string, "%lf", &logNModifier) != 1)
714 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
715 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
719 GNUNET_free (p_string);
721 percentage = 0.5; /* FIXME: default percentage? */
722 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
727 if (sscanf(p_string, "%lf", &percentage) != 1)
728 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
729 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
733 GNUNET_free (p_string);
735 natLog = log (pg->total);
736 connsPerPeer = ceil (natLog * logNModifier);
738 if (connsPerPeer % 2 == 1)
741 smallWorldConnections = 0;
742 connect_attempts = 0;
743 for (i = 0; i < pg->total; i++)
746 max = i + connsPerPeer / 2;
747 min = i - connsPerPeer / 2;
749 if (max > pg->total - 1)
751 max = max - pg->total;
757 min = pg->total - 1 + min;
761 for (j = 0; j < connsPerPeer / 2; j++)
763 random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
764 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
765 if (random < percentage)
767 /* Connect to uniformly selected random peer */
769 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
771 while ((((randomPeer < max) && (randomPeer > min))
772 && (useAnd == 0)) || (((randomPeer > min)
773 || (randomPeer < max))
777 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
780 smallWorldConnections +=
781 proc (pg, i, randomPeer);
785 nodeToConnect = i + j + 1;
786 if (nodeToConnect > pg->total - 1)
788 nodeToConnect = nodeToConnect - pg->total;
791 proc (pg, i, nodeToConnect);
797 connect_attempts += smallWorldConnections;
799 return connect_attempts;
804 create_nated_internet (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
806 unsigned int outer_count, inner_count;
808 int connect_attempts;
809 double nat_percentage;
812 nat_percentage = 0.6; /* FIXME: default percentage? */
813 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
818 if (sscanf(p_string, "%lf", &nat_percentage) != 1)
819 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
820 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
824 GNUNET_free (p_string);
829 cutoff = (unsigned int) (nat_percentage * pg->total);
831 connect_attempts = 0;
833 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
835 for (inner_count = outer_count + 1; inner_count < pg->total;
838 if ((outer_count > cutoff) || (inner_count > cutoff))
841 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
842 "Connecting peer %d to peer %d\n",
843 outer_count, inner_count);
845 connect_attempts += proc(pg, outer_count, inner_count);
850 return connect_attempts;
857 create_small_world (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
859 unsigned int i, j, k;
863 unsigned int toggle = 1;
864 unsigned int nodeToConnect;
866 unsigned int node1Row;
867 unsigned int node1Col;
868 unsigned int node2Row;
869 unsigned int node2Col;
870 unsigned int distance;
871 double probability, random, percentage;
872 unsigned int smallWorldConnections;
874 int connect_attempts;
875 square = floor (sqrt (pg->total));
879 percentage = 0.5; /* FIXME: default percentage? */
880 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
885 if (sscanf(p_string, "%lf", &percentage) != 1)
886 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
887 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
891 GNUNET_free (p_string);
893 probability = 0.5; /* FIXME: default percentage? */
894 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
899 if (sscanf(p_string, "%lf", &probability) != 1)
900 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
901 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
905 GNUNET_free (p_string);
907 if (square * square != pg->total)
909 while (rows * cols < pg->total)
920 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
921 _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
925 connect_attempts = 0;
926 /* Rows and columns are all sorted out, now iterate over all nodes and connect each
927 * to the node to its right and above. Once this is over, we'll have our torus!
928 * Special case for the last node (if the rows and columns are not equal), connect
929 * to the first in the row to maintain topology.
931 for (i = 0; i < pg->total; i++)
933 /* First connect to the node to the right */
934 if (((i + 1) % cols != 0) && (i + 1 != pg->total))
935 nodeToConnect = i + 1;
936 else if (i + 1 == pg->total)
937 nodeToConnect = rows * cols - cols;
939 nodeToConnect = i - cols + 1;
941 connect_attempts += proc (pg, i, nodeToConnect);
944 nodeToConnect = (rows * cols) - cols + i;
946 nodeToConnect = i - cols;
948 if (nodeToConnect < pg->total)
949 connect_attempts += proc (pg, i, nodeToConnect);
951 natLog = log (pg->total);
952 #if VERBOSE_TESTING > 2
953 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
954 _("natural log of %d is %d, will run %d iterations\n"),
955 pg->total, natLog, (int) (natLog * percentage));
956 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Total connections added thus far: %u!\n"), connect_attempts);
958 smallWorldConnections = 0;
959 for (i = 0; i < (int) (natLog * percentage); i++)
961 for (j = 0; j < pg->total; j++)
963 /* Determine the row and column of node at position j on the 2d torus */
965 node1Col = j - (node1Row * cols);
966 for (k = 0; k < pg->total; k++)
968 /* Determine the row and column of node at position k on the 2d torus */
970 node2Col = k - (node2Row * cols);
971 /* Simple Cartesian distance */
972 distance = abs (node1Row - node2Row) + abs (node1Col - node2Col);
975 /* Calculate probability as 1 over the square of the distance */
976 probability = 1.0 / (distance * distance);
977 /* Choose a random value between 0 and 1 */
978 random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
979 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
980 /* If random < probability, then connect the two nodes */
981 if (random < probability)
982 smallWorldConnections += proc (pg, j, k);
988 connect_attempts += smallWorldConnections;
989 #if VERBOSE_TESTING > 2
990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
991 _("Total connections added for small world: %d!\n"),
992 smallWorldConnections);
994 return connect_attempts;
1000 create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1003 unsigned int outer_count;
1004 unsigned int inner_count;
1005 int connect_attempts;
1009 probability = 0.5; /* FIXME: default percentage? */
1010 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
1015 if (sscanf(p_string, "%lf", &probability) != 1)
1016 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1017 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1021 GNUNET_free (p_string);
1023 connect_attempts = 0;
1024 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
1026 for (inner_count = outer_count + 1; inner_count < pg->total;
1029 temp_rand = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
1030 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
1032 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1033 _("rand is %f probability is %f\n"), temp_rand,
1036 if (temp_rand < probability)
1038 connect_attempts += proc (pg, outer_count, inner_count);
1043 return connect_attempts;
1047 create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1050 unsigned int square;
1053 unsigned int toggle = 1;
1054 unsigned int nodeToConnect;
1055 int connect_attempts;
1057 connect_attempts = 0;
1059 square = floor (sqrt (pg->total));
1063 if (square * square != pg->total)
1065 while (rows * cols < pg->total)
1067 if (toggle % 2 == 0)
1076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077 _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
1080 /* Rows and columns are all sorted out, now iterate over all nodes and connect each
1081 * to the node to its right and above. Once this is over, we'll have our torus!
1082 * Special case for the last node (if the rows and columns are not equal), connect
1083 * to the first in the row to maintain topology.
1085 for (i = 0; i < pg->total; i++)
1087 /* First connect to the node to the right */
1088 if (((i + 1) % cols != 0) && (i + 1 != pg->total))
1089 nodeToConnect = i + 1;
1090 else if (i + 1 == pg->total)
1091 nodeToConnect = rows * cols - cols;
1093 nodeToConnect = i - cols + 1;
1095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1096 "Connecting peer %d to peer %d\n",
1099 connect_attempts += proc(pg, i, nodeToConnect);
1101 /* Second connect to the node immediately above */
1103 nodeToConnect = (rows * cols) - cols + i;
1105 nodeToConnect = i - cols;
1107 if (nodeToConnect < pg->total)
1110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1111 "Connecting peer %d to peer %d\n",
1114 connect_attempts += proc(pg, i, nodeToConnect);
1119 return connect_attempts;
1125 create_clique (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1127 unsigned int outer_count;
1128 unsigned int inner_count;
1129 int connect_attempts;
1131 connect_attempts = 0;
1133 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
1135 for (inner_count = outer_count + 1; inner_count < pg->total;
1139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1140 "Connecting peer %d to peer %d\n",
1141 outer_count, inner_count);
1143 connect_attempts += proc(pg, outer_count, inner_count);
1147 return connect_attempts;
1152 create_ring (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1155 int connect_attempts;
1157 connect_attempts = 0;
1159 /* Connect each peer to the next highest numbered peer */
1160 for (count = 0; count < pg->total - 1; count++)
1163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1164 "Connecting peer %d to peer %d\n",
1167 connect_attempts += proc(pg, count, count + 1);
1170 /* Connect the last peer to the first peer */
1171 connect_attempts += proc(pg, pg->total - 1, 0);
1173 return connect_attempts;
1178 * Iterator for writing friends of a peer to a file.
1180 * @param cls closure, an open writable file handle
1181 * @param key the key the daemon was stored under
1182 * @param value the GNUNET_TESTING_Daemon that needs to be written.
1184 * @return GNUNET_YES to continue iteration
1186 * TODO: Could replace friend_file_iterator and blacklist_file_iterator
1187 * with a single file_iterator that takes a closure which contains
1188 * the prefix to write before the peer. Then this could be used
1189 * for blacklisting multiple transports and writing the friend
1190 * file. I'm sure *someone* will complain loudly about other
1191 * things that negate these functions even existing so no point in
1195 friend_file_iterator (void *cls,
1196 const GNUNET_HashCode * key,
1199 FILE *temp_friend_handle = cls;
1200 struct GNUNET_TESTING_Daemon *peer = value;
1201 struct GNUNET_PeerIdentity *temppeer;
1202 struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
1204 temppeer = &peer->id;
1205 GNUNET_CRYPTO_hash_to_enc(&temppeer->hashPubKey, &peer_enc);
1206 fprintf(temp_friend_handle, "%s\n", (char *)&peer_enc);
1213 * Iterator for writing blacklist data to appropriate files.
1215 * @param cls closure, an open writable file handle
1216 * @param key the key the daemon was stored under
1217 * @param value the GNUNET_TESTING_Daemon that needs to be written.
1219 * @return GNUNET_YES to continue iteration
1222 blacklist_file_iterator (void *cls,
1223 const GNUNET_HashCode * key,
1226 FILE *temp_blacklist_handle = cls;
1227 struct GNUNET_TESTING_Daemon *peer = value;
1228 struct GNUNET_PeerIdentity *temppeer;
1229 struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
1231 temppeer = &peer->id;
1232 GNUNET_CRYPTO_hash_to_enc(&temppeer->hashPubKey, &peer_enc);
1233 fprintf(temp_blacklist_handle, "tcp:%s\n", (char *)&peer_enc);
1239 * Create the friend files based on the PeerConnection's
1240 * of each peer in the peer group, and copy the files
1241 * to the appropriate place
1243 * @param pg the peer group we are dealing with
1246 create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
1248 FILE *temp_friend_handle;
1249 unsigned int pg_iter;
1250 char *temp_service_path;
1254 enum GNUNET_OS_ProcessStatusType type;
1255 unsigned long return_code;
1260 pidarr = GNUNET_malloc(sizeof(pid_t) * pg->total);
1261 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1263 mytemp = GNUNET_DISK_mktemp("friends");
1264 GNUNET_assert(mytemp != NULL);
1265 temp_friend_handle = fopen (mytemp, "wt");
1266 GNUNET_assert(temp_friend_handle != NULL);
1267 GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].allowed_peers, &friend_file_iterator, temp_friend_handle);
1268 fclose(temp_friend_handle);
1271 GNUNET_CONFIGURATION_get_value_string(pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path))
1273 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1274 _("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
1277 if (UNLINK (mytemp) != 0)
1278 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp);
1279 GNUNET_free (mytemp);
1283 if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
1285 GNUNET_asprintf (&arg, "%s/friends", temp_service_path);
1286 pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
1287 "mv", mytemp, arg, NULL);
1289 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1290 _("Copying file with command cp %s %s\n"), mytemp, arg);
1295 else /* Remote, scp the file to the correct place */
1297 if (NULL != pg->peers[pg_iter].daemon->username)
1298 GNUNET_asprintf (&arg, "%s@%s:%s/friends", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path);
1300 GNUNET_asprintf (&arg, "%s:%s/friends", pg->peers[pg_iter].daemon->hostname, temp_service_path);
1301 pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp",
1302 "scp", mytemp, arg, NULL);
1305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1306 _("Copying file with command scp %s %s\n"), mytemp, arg);
1310 GNUNET_free (temp_service_path);
1311 GNUNET_free (mytemp);
1315 ret = GNUNET_SYSERR;
1316 while ((count < max_wait) && (ret != GNUNET_OK))
1319 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1323 _("Checking copy status of file %d\n"), pg_iter);
1325 if (pidarr[pg_iter] != 0) /* Check for already completed! */
1327 if (GNUNET_OS_process_status(pidarr[pg_iter], &type, &return_code) != GNUNET_OK)
1329 ret = GNUNET_SYSERR;
1331 else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0))
1333 ret = GNUNET_SYSERR;
1337 pidarr[pg_iter] = 0;
1339 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1340 _("File %d copied\n"), pg_iter);
1346 if (ret == GNUNET_SYSERR)
1353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1354 _("Finished copying all friend files!\n"));
1356 GNUNET_free(pidarr);
1362 * Create the blacklist files based on the PeerConnection's
1363 * of each peer in the peer group, and copy the files
1364 * to the appropriate place.
1366 * @param pg the peer group we are dealing with
1369 create_and_copy_blacklist_files (struct GNUNET_TESTING_PeerGroup *pg)
1371 FILE *temp_friend_handle;
1372 unsigned int pg_iter;
1373 char *temp_service_path;
1377 enum GNUNET_OS_ProcessStatusType type;
1378 unsigned long return_code;
1383 pidarr = GNUNET_malloc(sizeof(pid_t) * pg->total);
1384 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1386 mytemp = GNUNET_DISK_mktemp("blacklist");
1387 GNUNET_assert(mytemp != NULL);
1388 temp_friend_handle = fopen (mytemp, "wt");
1389 GNUNET_assert(temp_friend_handle != NULL);
1390 GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].blacklisted_peers, &blacklist_file_iterator, temp_friend_handle);
1391 fclose(temp_friend_handle);
1394 GNUNET_CONFIGURATION_get_value_string(pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path))
1396 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1397 _("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
1400 if (UNLINK (mytemp) != 0)
1401 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp);
1402 GNUNET_free (mytemp);
1406 if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
1408 GNUNET_asprintf (&arg, "%s/blacklist", temp_service_path);
1409 pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
1410 "mv", mytemp, arg, NULL);
1412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1413 _("Copying file with command cp %s %s\n"), mytemp, arg);
1418 else /* Remote, scp the file to the correct place */
1420 if (NULL != pg->peers[pg_iter].daemon->username)
1421 GNUNET_asprintf (&arg, "%s@%s:%s/blacklist", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path);
1423 GNUNET_asprintf (&arg, "%s:%s/blacklist", pg->peers[pg_iter].daemon->hostname, temp_service_path);
1424 pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp",
1425 "scp", mytemp, arg, NULL);
1428 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1429 _("Copying file with command scp %s %s\n"), mytemp, arg);
1433 GNUNET_free (temp_service_path);
1434 GNUNET_free (mytemp);
1438 ret = GNUNET_SYSERR;
1439 while ((count < max_wait) && (ret != GNUNET_OK))
1442 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1446 _("Checking copy status of file %d\n"), pg_iter);
1448 if (pidarr[pg_iter] != 0) /* Check for already completed! */
1450 if (GNUNET_OS_process_status(pidarr[pg_iter], &type, &return_code) != GNUNET_OK)
1452 ret = GNUNET_SYSERR;
1454 else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0))
1456 ret = GNUNET_SYSERR;
1460 pidarr[pg_iter] = 0;
1462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1463 _("File %d copied\n"), pg_iter);
1469 if (ret == GNUNET_SYSERR)
1476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1477 _("Finished copying all blacklist files!\n"));
1479 GNUNET_free(pidarr);
1485 * Internal notification of a connection, kept so that we can ensure some connections
1486 * happen instead of flooding all testing daemons with requests to connect.
1488 static void internal_connect_notify (void *cls,
1489 const struct GNUNET_PeerIdentity *first,
1490 const struct GNUNET_PeerIdentity *second,
1491 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
1492 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
1493 struct GNUNET_TESTING_Daemon *first_daemon,
1494 struct GNUNET_TESTING_Daemon *second_daemon,
1497 struct GNUNET_TESTING_PeerGroup *pg = cls;
1498 outstanding_connects--;
1500 pg->notify_connection(pg->notify_connection_cls, first, second, first_cfg, second_cfg, first_daemon, second_daemon, emsg);
1504 static void schedule_connect(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1506 struct ConnectContext *connect_context = cls;
1508 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1511 if (outstanding_connects > MAX_OUTSTANDING_CONNECTIONS)
1513 #if VERBOSE_TESTING > 2
1514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1515 _("Delaying connect, we have too many outstanding connections!\n"));
1517 GNUNET_SCHEDULER_add_delayed(connect_context->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3), &schedule_connect, connect_context);
1521 #if VERBOSE_TESTING > 2
1522 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1523 _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
1525 outstanding_connects++;
1526 GNUNET_TESTING_daemons_connect (connect_context->first,
1527 connect_context->second,
1530 &internal_connect_notify,
1531 connect_context->pg);
1532 GNUNET_free(connect_context);
1537 * Iterator for actually scheduling connections to be created
1538 * between two peers.
1540 * @param cls closure, a GNUNET_TESTING_Daemon
1541 * @param key the key the second Daemon was stored under
1542 * @param value the GNUNET_TESTING_Daemon that the first is to connect to
1544 * @return GNUNET_YES to continue iteration
1547 connect_iterator (void *cls,
1548 const GNUNET_HashCode * key,
1551 struct PeerData *first = cls;
1552 struct GNUNET_TESTING_Daemon *second = value;
1553 struct ConnectContext *connect_context;
1555 connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
1556 connect_context->pg = first->pg;
1557 connect_context->first = first->daemon;
1558 connect_context->second = second;
1559 GNUNET_SCHEDULER_add_now(first->pg->sched, &schedule_connect, connect_context);
1565 * Iterator for copying all entries in the allowed hashmap to the
1568 * @param cls closure, a GNUNET_TESTING_Daemon
1569 * @param key the key the second Daemon was stored under
1570 * @param value the GNUNET_TESTING_Daemon that the first is to connect to
1572 * @return GNUNET_YES to continue iteration
1575 copy_topology_iterator (void *cls,
1576 const GNUNET_HashCode * key,
1579 struct PeerData *first = cls;
1581 GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(first->connect_peers, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1587 * Make the peers to connect the same as those that are allowed to be
1590 * @param pg the peer group
1593 copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg)
1595 unsigned int pg_iter;
1600 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1602 ret = GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].allowed_peers, ©_topology_iterator, &pg->peers[pg_iter]);
1603 if (GNUNET_SYSERR == ret)
1604 return GNUNET_SYSERR;
1606 total = total + ret;
1614 * Connect the topology as specified by the PeerConnection's
1615 * of each peer in the peer group
1617 * @param pg the peer group we are dealing with
1619 * @return the number of connections that will be attempted
1622 connect_topology (struct GNUNET_TESTING_PeerGroup *pg)
1624 unsigned int pg_iter;
1628 struct PeerConnection *connection_iter;
1629 struct ConnectContext *connect_context;
1633 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1635 ret = GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &connect_iterator, &pg->peers[pg_iter]);
1636 if (GNUNET_SYSERR == ret)
1637 return GNUNET_SYSERR;
1639 total = total + ret;
1643 while (connection_iter != NULL)
1645 connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
1646 connect_context->pg = pg;
1647 connect_context->first = ;
1648 connect_context->second = connection_iter->daemon;
1649 GNUNET_SCHEDULER_add_now(pg->sched, &schedule_connect, connect_context);
1650 connection_iter = connection_iter->next;
1659 * Takes a peer group and creates a topology based on the
1660 * one specified. Creates a topology means generates friend
1661 * files for the peers so they can only connect to those allowed
1662 * by the topology. This will only have an effect once peers
1663 * are started if the FRIENDS_ONLY option is set in the base
1664 * config. Also takes an optional restrict topology which
1665 * disallows direct TCP connections UNLESS they are specified in
1666 * the restricted topology.
1668 * @param pg the peer group struct representing the running peers
1669 * @param topology which topology to connect the peers in
1670 * @param restrict_topology allow only direct TCP connections in this topology
1671 * use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions
1673 * @return the maximum number of connections were all allowed peers
1674 * connected to each other
1677 GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg,
1678 enum GNUNET_TESTING_Topology topology,
1679 enum GNUNET_TESTING_Topology restrict_topology)
1682 int num_connections;
1683 int unblacklisted_connections;
1685 GNUNET_assert (pg->notify_connection != NULL);
1690 case GNUNET_TESTING_TOPOLOGY_CLIQUE:
1692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1693 _("Creating clique topology\n"));
1695 num_connections = create_clique (pg, &add_allowed_connections);
1697 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
1699 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1700 _("Creating small world (ring) topology\n"));
1702 num_connections = create_small_world_ring (pg, &add_allowed_connections);
1704 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
1706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1707 _("Creating small world (2d-torus) topology\n"));
1709 num_connections = create_small_world (pg, &add_allowed_connections);
1711 case GNUNET_TESTING_TOPOLOGY_RING:
1713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1714 _("Creating ring topology\n"));
1716 num_connections = create_ring (pg, &add_allowed_connections);
1718 case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
1720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1721 _("Creating 2d torus topology\n"));
1723 num_connections = create_2d_torus (pg, &add_allowed_connections);
1725 case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
1727 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1728 _("Creating Erdos-Renyi topology\n"));
1730 num_connections = create_erdos_renyi (pg, &add_allowed_connections);
1732 case GNUNET_TESTING_TOPOLOGY_INTERNAT:
1734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1735 _("Creating InterNAT topology\n"));
1737 num_connections = create_nated_internet (pg, &add_allowed_connections);
1739 case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
1741 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1742 _("Creating Scale Free topology\n"));
1744 num_connections = create_scale_free (pg, &add_allowed_connections);
1746 case GNUNET_TESTING_TOPOLOGY_NONE:
1747 num_connections = 0;
1750 num_connections = 0;
1753 if (num_connections < 1)
1754 return GNUNET_SYSERR;
1756 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
1758 ret = create_and_copy_friend_files(pg);
1761 if (ret != GNUNET_OK)
1764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1765 _("Failed during friend file copying!\n"));
1767 return GNUNET_SYSERR;
1772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1773 _("Friend files created/copied successfully!\n"));
1778 * Use the create clique method to initially set all connections
1781 create_clique (pg, &blacklist_connections);
1782 unblacklisted_connections = 0;
1784 * Un-blacklist connections as per the topology specified
1786 switch (restrict_topology)
1788 case GNUNET_TESTING_TOPOLOGY_CLIQUE:
1790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1791 _("Blacklisting all but clique topology\n"));
1793 unblacklisted_connections = create_clique (pg, &unblacklist_connections);
1795 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
1797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1798 _("Blacklisting all but small world (ring) topology\n"));
1800 unblacklisted_connections = create_small_world_ring (pg, &unblacklist_connections);
1802 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
1804 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1805 _("Blacklisting all but small world (2d-torus) topology\n"));
1807 unblacklisted_connections = create_small_world (pg, &unblacklist_connections);
1809 case GNUNET_TESTING_TOPOLOGY_RING:
1811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1812 _("Blacklisting all but ring topology\n"));
1814 unblacklisted_connections = create_ring (pg, &unblacklist_connections);
1816 case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
1818 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1819 _("Blacklisting all but 2d torus topology\n"));
1821 unblacklisted_connections = create_2d_torus (pg, &unblacklist_connections);
1823 case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
1825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1826 _("Blacklisting all but Erdos-Renyi topology\n"));
1828 unblacklisted_connections = create_erdos_renyi (pg, &unblacklist_connections);
1830 case GNUNET_TESTING_TOPOLOGY_INTERNAT:
1832 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1833 _("Blacklisting all but InterNAT topology\n"));
1835 unblacklisted_connections = create_nated_internet (pg, &unblacklist_connections);
1837 case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
1839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1840 _("Blacklisting all but Scale Free topology\n"));
1842 unblacklisted_connections = create_scale_free (pg, &unblacklist_connections);
1844 case GNUNET_TESTING_TOPOLOGY_NONE:
1850 if (unblacklisted_connections > 0)
1852 ret = create_and_copy_blacklist_files(pg);
1853 if (ret != GNUNET_OK)
1856 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1857 _("Failed during blacklist file copying!\n"));
1859 return GNUNET_SYSERR;
1864 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1865 _("Blacklist files created/copied successfully!\n"));
1871 return num_connections;
1874 struct RandomContext
1879 struct GNUNET_TESTING_PeerGroup *pg;
1882 * uid of the first peer
1887 * Peer data for first peer.
1889 struct PeerData *first;
1892 * Random percentage to use
1897 struct MinimumContext
1902 struct GNUNET_TESTING_PeerGroup *pg;
1905 * uid of the first peer
1910 * Peer data for first peer.
1912 struct PeerData *first;
1915 * Number of conns per peer
1917 unsigned int num_to_add;
1920 * Permuted array of all possible connections. Only add the Nth
1921 * peer if it's in the Nth position.
1923 unsigned int *pg_array;
1926 * What number is the current element we are iterating over?
1928 unsigned int current;
1936 struct GNUNET_TESTING_PeerGroup *pg;
1939 * uid of the first peer
1944 * uid of the second peer
1946 uint32_t second_uid;
1949 * Peer data for first peer.
1951 struct PeerData *first;
1954 * Which peer has been chosen as the one to add?
1956 unsigned int chosen;
1959 * What number is the current element we are iterating over?
1961 unsigned int current;
1965 * Iterator for choosing random peers to connect.
1967 * @param cls closure, a RandomContext
1968 * @param key the key the second Daemon was stored under
1969 * @param value the GNUNET_TESTING_Daemon that the first is to connect to
1971 * @return GNUNET_YES to continue iteration
1974 random_connect_iterator (void *cls,
1975 const GNUNET_HashCode * key,
1978 struct RandomContext *random_ctx = cls;
1979 double random_number;
1980 uint32_t second_pos;
1981 GNUNET_HashCode first_hash;
1982 random_number = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
1983 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
1984 if (random_number < random_ctx->percentage)
1986 GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(random_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1988 /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */
1989 uid_from_hash(key, &second_pos);
1990 hash_from_uid(random_ctx->first_uid, &first_hash);
1991 GNUNET_assert(random_ctx->pg->total > second_pos);
1992 GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(random_ctx->pg->peers[second_pos].connect_peers, &first_hash, random_ctx->first->daemon));
1998 * Iterator for adding at least X peers to a peers connection set.
2000 * @param cls closure, MinimumContext
2001 * @param key the key the second Daemon was stored under
2002 * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2004 * @return GNUNET_YES to continue iteration
2007 minimum_connect_iterator (void *cls,
2008 const GNUNET_HashCode * key,
2011 struct MinimumContext *min_ctx = cls;
2012 uint32_t second_pos;
2013 GNUNET_HashCode first_hash;
2016 if (GNUNET_CONTAINER_multihashmap_size(min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add)
2018 for (i = 0; i < min_ctx->num_to_add; i++)
2020 if (min_ctx->pg_array[i] == min_ctx->current)
2022 GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(min_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2023 uid_from_hash(key, &second_pos);
2024 hash_from_uid(min_ctx->first_uid, &first_hash);
2025 GNUNET_assert(min_ctx->pg->total > second_pos);
2026 GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(min_ctx->pg->peers[second_pos].connect_peers_working_set, &first_hash, min_ctx->first->daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2027 /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */
2028 GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(min_ctx->pg->peers[second_pos].connect_peers, &first_hash, min_ctx->first->daemon));
2035 return GNUNET_NO; /* We can stop iterating, we have enough peers! */
2041 * Iterator for adding peers to a connection set based on a depth first search.
2043 * @param cls closure, MinimumContext
2044 * @param key the key the second daemon was stored under
2045 * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2047 * @return GNUNET_YES to continue iteration
2050 dfs_connect_iterator (void *cls,
2051 const GNUNET_HashCode * key,
2054 struct DFSContext *dfs_ctx = cls;
2055 GNUNET_HashCode first_hash;
2057 if (dfs_ctx->current == dfs_ctx->chosen)
2059 GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(dfs_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2060 uid_from_hash(key, &dfs_ctx->second_uid);
2061 hash_from_uid(dfs_ctx->first_uid, &first_hash);
2062 GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(dfs_ctx->pg->peers[dfs_ctx->second_uid].connect_peers_working_set, &first_hash, dfs_ctx->first->daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2063 GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(dfs_ctx->pg->peers[dfs_ctx->second_uid].connect_peers, &first_hash, dfs_ctx->first->daemon));
2064 /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */
2065 return GNUNET_NO; /* We have found our peer, don't iterate more */
2074 * From the set of connections possible, choose percentage percent of connections
2075 * to actually connect.
2077 * @param pg the peergroup we are dealing with
2078 * @param percentage what percent of total connections to make
2081 choose_random_connections(struct GNUNET_TESTING_PeerGroup *pg, double percentage)
2083 struct RandomContext random_ctx;
2086 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2088 random_ctx.first_uid = pg_iter;
2089 random_ctx.first = &pg->peers[pg_iter];
2090 random_ctx.percentage = percentage;
2092 pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(pg->total);
2093 GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &random_connect_iterator, &random_ctx);
2094 /* Now remove the old connections */
2095 GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2096 /* And replace with the random set */
2097 pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2102 * From the set of connections possible, choose at least num connections per
2105 * @param pg the peergroup we are dealing with
2106 * @param num how many connections at least should each peer have (if possible)?
2109 choose_minimum(struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
2111 struct MinimumContext minimum_ctx;
2114 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2116 pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
2119 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2121 minimum_ctx.first_uid = pg_iter;
2122 minimum_ctx.pg_array = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers));
2123 minimum_ctx.first = &pg->peers[pg_iter];
2124 minimum_ctx.pg = pg;
2125 minimum_ctx.num_to_add = num;
2126 minimum_ctx.current = 0;
2127 pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(pg->total);
2128 GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &minimum_connect_iterator, &minimum_ctx);
2131 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2133 /* Remove the "old" connections */
2134 GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2135 /* And replace with the working set */
2136 pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2137 fprintf(stderr, "Finished! Hashmap size %u\n", GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers));
2143 static unsigned int count_workingset_connections(struct GNUNET_TESTING_PeerGroup *pg)
2146 unsigned int pg_iter;
2150 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2152 count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
2159 static unsigned int count_allowed_connections(struct GNUNET_TESTING_PeerGroup *pg)
2162 unsigned int pg_iter;
2166 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2168 count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers);
2175 * From the set of connections possible, choose at least num connections per
2176 * peer based on depth first traversal of peer connections. If DFS leaves
2177 * peers unconnected, ensure those peers get connections.
2179 * @param pg the peergroup we are dealing with
2180 * @param num how many connections at least should each peer have (if possible)?
2183 perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
2185 struct DFSContext dfs_ctx;
2188 uint32_t starting_peer;
2189 uint32_t least_connections;
2190 GNUNET_HashCode second_hash;
2192 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2194 pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
2199 while ((count_workingset_connections(pg) < num * pg->total) && (count_allowed_connections(pg) > 0))
2201 if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */
2203 least_connections = -1; /* Set to very high number */
2204 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2206 if (GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set) < least_connections)
2208 starting_peer = pg_iter;
2209 least_connections = GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
2214 if (GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers) == 0) /* Ensure there is at least one peer left to connect! */
2220 /* Choose a random peer from the chosen peers set of connections to add */
2221 dfs_ctx.chosen = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers));
2222 dfs_ctx.first_uid = starting_peer;
2223 dfs_ctx.first = &pg->peers[starting_peer];
2225 dfs_ctx.current = 0;
2227 GNUNET_CONTAINER_multihashmap_iterate(pg->peers[starting_peer].connect_peers, &dfs_connect_iterator, &dfs_ctx);
2228 /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */
2229 hash_from_uid(dfs_ctx.second_uid, &second_hash);
2230 GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(pg->peers[starting_peer].connect_peers, &second_hash, pg->peers[dfs_ctx.second_uid].daemon));
2231 starting_peer = dfs_ctx.second_uid;
2234 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2239 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2241 /* Remove the "old" connections */
2242 GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2243 /* And replace with the working set */
2244 pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2245 fprintf(stderr, "Finished! Hashmap size %u\n", GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers));
2251 * @param pg the peer group struct representing the running peers
2252 * @param topology which topology to connect the peers in
2253 * @param options options for connecting the topology
2254 * @param option_modifier modifier for options that take a parameter
2256 * There are many ways to connect peers that are supported by this function.
2257 * To connect peers in the same topology that was created via the
2258 * GNUNET_TESTING_create_topology, the topology variable must be set to
2259 * GNUNET_TESTING_TOPOLOGY_NONE. If the topology variable is specified,
2260 * a new instance of that topology will be generated and attempted to be
2261 * connected. This could result in some connections being impossible,
2262 * because some topologies are non-deterministic.
2266 GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
2267 enum GNUNET_TESTING_Topology topology,
2268 enum GNUNET_TESTING_TopologyOption options,
2269 double option_modifier)
2271 int num_connections;
2275 case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2278 _("Creating clique topology\n"));
2280 num_connections = create_clique (pg, &add_actual_connections);
2282 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2285 _("Creating small world (ring) topology\n"));
2287 num_connections = create_small_world_ring (pg, &add_actual_connections);
2289 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2292 _("Creating small world (2d-torus) topology\n"));
2294 num_connections = create_small_world (pg, &add_actual_connections);
2296 case GNUNET_TESTING_TOPOLOGY_RING:
2298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2299 _("Creating ring topology\n"));
2301 num_connections = create_ring (pg, &add_actual_connections);
2303 case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2306 _("Creating 2d torus topology\n"));
2308 num_connections = create_2d_torus (pg, &add_actual_connections);
2310 case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2313 _("Creating Erdos-Renyi topology\n"));
2315 num_connections = create_erdos_renyi (pg, &add_actual_connections);
2317 case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2320 _("Creating InterNAT topology\n"));
2322 num_connections = create_nated_internet (pg, &add_actual_connections);
2324 case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
2326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2327 _("Creating Scale Free topology\n"));
2329 num_connections = create_scale_free (pg, &add_actual_connections);
2331 case GNUNET_TESTING_TOPOLOGY_NONE:
2332 num_connections = copy_allowed_topology(pg);
2335 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Unknown topology specification, can't connect peers!\n");
2336 return GNUNET_SYSERR;
2341 case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM: /* Create a random subset of total connections based on parameter */
2342 choose_random_connections(pg, option_modifier);
2344 case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM: /* Create at least X connections per peer (if possible!) */
2345 choose_minimum(pg, (unsigned int)option_modifier);
2347 case GNUNET_TESTING_TOPOLOGY_OPTION_DFS: /* Choose a random starting point, randomly walk graph, try to get each peer X connections */
2348 perform_dfs(pg, (int)option_modifier);
2350 case GNUNET_TESTING_TOPOLOGY_OPTION_NONE:
2352 case GNUNET_TESTING_TOPOLOGY_OPTION_ALL:
2358 return connect_topology(pg);
2362 * Function which continues a peer group starting up
2363 * after successfully generating hostkeys for each peer.
2365 * @param pg the peer group to continue starting
2369 GNUNET_TESTING_daemons_continue_startup(struct GNUNET_TESTING_PeerGroup *pg)
2373 for (i = 0; i < pg->total; i++)
2375 GNUNET_TESTING_daemon_continue_startup(pg->peers[i].daemon);
2380 * Start count gnunetd processes with the same set of transports and
2381 * applications. The port numbers (any option called "PORT") will be
2382 * adjusted to ensure that no two peers running on the same system
2383 * have the same port(s) in their respective configurations.
2385 * @param sched scheduler to use
2386 * @param cfg configuration template to use
2387 * @param total number of daemons to start
2388 * @param timeout total time allowed for peers to start
2389 * @param hostkey_callback function to call on each peers hostkey generation
2390 * if NULL, peers will be started by this call, if non-null,
2391 * GNUNET_TESTING_daemons_continue_startup must be called after
2392 * successful hostkey generation
2393 * @param hostkey_cls closure for hostkey callback
2394 * @param cb function to call on each daemon that was started
2395 * @param cb_cls closure for cb
2396 * @param connect_callback function to call each time two hosts are connected
2397 * @param connect_callback_cls closure for connect_callback
2398 * @param hostnames space-separated list of hostnames to use; can be NULL (to run
2399 * everything on localhost).
2400 * @return NULL on error, otherwise handle to control peer group
2402 struct GNUNET_TESTING_PeerGroup *
2403 GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
2404 const struct GNUNET_CONFIGURATION_Handle *cfg,
2406 struct GNUNET_TIME_Relative timeout,
2407 GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback,
2409 GNUNET_TESTING_NotifyDaemonRunning cb,
2411 GNUNET_TESTING_NotifyConnection
2412 connect_callback, void *connect_callback_cls,
2413 const char *hostnames)
2415 struct GNUNET_TESTING_PeerGroup *pg;
2419 const char *hostname;
2420 char *baseservicehome;
2421 char *newservicehome;
2423 struct GNUNET_CONFIGURATION_Handle *pcfg;
2425 unsigned int hostcnt;
2434 pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
2438 pg->cb_cls = cb_cls;
2439 pg->notify_connection = connect_callback;
2440 pg->notify_connection_cls = connect_callback_cls;
2442 pg->max_timeout = GNUNET_TIME_relative_to_absolute(timeout);
2443 pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
2444 if (NULL != hostnames)
2447 /* skip leading spaces */
2448 while ((0 != *hostnames) && (isspace (*hostnames)))
2451 while ('\0' != *rpos)
2453 if (isspace (*rpos))
2457 pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
2459 start = GNUNET_strdup (hostnames);
2461 while ('\0' != *pos)
2466 if (strlen (start) > 0)
2468 pg->hosts[off].minport = LOW_PORT;
2469 pg->hosts[off++].hostname = start;
2475 if (strlen (start) > 0)
2477 pg->hosts[off].minport = LOW_PORT;
2478 pg->hosts[off++].hostname = start;
2482 GNUNET_free (start);
2483 GNUNET_free (pg->hosts);
2487 minport = 0; /* make gcc happy */
2494 for (off = 0; off < total; off++)
2498 hostname = pg->hosts[off % hostcnt].hostname;
2499 pcfg = make_config (cfg, &pg->hosts[off % hostcnt].minport, hostname);
2504 pcfg = make_config (cfg, &minport, hostname);
2509 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2511 ("Could not create configuration for peer number %u on `%s'!\n"),
2512 off, hostname == NULL ? "localhost" : hostname);
2517 GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME",
2520 GNUNET_asprintf (&newservicehome,
2521 "%s/%d/", baseservicehome, off);
2522 GNUNET_free (baseservicehome);
2526 tmpdir = getenv ("TMPDIR");
2527 tmpdir = tmpdir ? tmpdir : "/tmp";
2528 GNUNET_asprintf (&newservicehome,
2531 "gnunet-testing-test-test", off);
2533 GNUNET_CONFIGURATION_set_value_string (pcfg,
2535 "SERVICEHOME", newservicehome);
2536 GNUNET_free (newservicehome);
2537 pg->peers[off].cfg = pcfg;
2538 pg->peers[off].allowed_peers = GNUNET_CONTAINER_multihashmap_create(total);
2539 pg->peers[off].connect_peers = GNUNET_CONTAINER_multihashmap_create(total);
2540 pg->peers[off].blacklisted_peers = GNUNET_CONTAINER_multihashmap_create(total);
2541 pg->peers[off].pg = pg;
2542 pg->peers[off].daemon = GNUNET_TESTING_daemon_start (sched,
2549 if (NULL == pg->peers[off].daemon)
2550 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2551 _("Could not start peer number %u!\n"), off);
2558 * Get a daemon by number, so callers don't have to do nasty
2559 * offsetting operation.
2561 struct GNUNET_TESTING_Daemon *
2562 GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position)
2564 if (position < pg->total)
2565 return pg->peers[position].daemon;
2571 * Prototype of a function that will be called when a
2572 * particular operation was completed the testing library.
2574 * @param id id of the peer that was restarted
2575 * @param cfg handle to the configuration of the peer
2576 * @param d handle to the daemon that was restarted
2577 * @param emsg NULL on success
2579 void restart_callback (void *cls,
2580 const struct GNUNET_PeerIdentity *id,
2581 const struct GNUNET_CONFIGURATION_Handle *cfg,
2582 struct GNUNET_TESTING_Daemon *d,
2585 struct RestartContext *restart_context = cls;
2589 restart_context->peers_restarted++;
2593 restart_context->peers_restart_failed++;
2596 if (restart_context->peers_restarted == restart_context->peer_group->total)
2598 restart_context->callback(restart_context->callback_cls, NULL);
2599 GNUNET_free(restart_context);
2601 else if (restart_context->peers_restart_failed + restart_context->peers_restarted == restart_context->peer_group->total)
2603 restart_context->callback(restart_context->callback_cls, "Failed to restart peers!");
2604 GNUNET_free(restart_context);
2610 * Restart all peers in the given group.
2612 * @param pg the handle to the peer group
2613 * @param timeout how long to wait on failure
2614 * @param callback function to call on completion (or failure)
2615 * @param callback_cls closure for the callback function
2618 GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_NotifyCompletion callback, void *callback_cls)
2620 struct RestartContext *restart_context;
2625 restart_context = GNUNET_malloc(sizeof(struct RestartContext));
2626 restart_context->peer_group = pg;
2627 restart_context->peers_restarted = 0;
2628 restart_context->callback = callback;
2629 restart_context->callback_cls = callback_cls;
2631 for (off = 0; off < pg->total; off++)
2633 GNUNET_TESTING_daemon_restart (pg->peers[off].daemon, &restart_callback, restart_context);
2639 * Shutdown all peers started in the given group.
2641 * @param pg handle to the peer group
2642 * @param timeout how long to wait for shutdown
2646 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, struct GNUNET_TIME_Relative timeout)
2650 for (off = 0; off < pg->total; off++)
2652 /* FIXME: should we wait for our
2653 continuations to be called here? This
2654 would require us to take a continuation
2657 if (NULL != pg->peers[off].daemon)
2658 GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, timeout, NULL, NULL, GNUNET_YES);
2659 if (NULL != pg->peers[off].cfg)
2660 GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
2662 if (pg->peers[off].allowed_peers != NULL)
2663 GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].allowed_peers);
2664 if (pg->peers[off].connect_peers != NULL)
2665 GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].connect_peers);
2666 if (pg->peers[off].blacklisted_peers != NULL)
2667 GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].blacklisted_peers);
2670 GNUNET_free (pg->peers);
2671 if (NULL != pg->hosts)
2673 GNUNET_free (pg->hosts[0].hostname);
2674 GNUNET_free (pg->hosts);
2680 /* end of testing_group.c */