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_YES
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
58 struct PeerConnection *next;
61 * Pointer to daemon handle
63 struct GNUNET_TESTING_Daemon *daemon;
68 * Data we keep per peer.
73 * (Initial) configuration of the host.
74 * (initial because clients could change
75 * it and we would not know about those
78 struct GNUNET_CONFIGURATION_Handle *cfg;
81 * Handle for controlling the daemon.
83 struct GNUNET_TESTING_Daemon *daemon;
86 * Linked list of peer connections (simply indexes of PeerGroup)
88 struct PeerConnection *connected_peers;
91 * Total number of connections this peer has
98 * Data we keep per host.
108 * Lowest port that we have not yet used
116 * Handle to a group of GNUnet peers.
118 struct GNUNET_TESTING_PeerGroup
123 struct GNUNET_SCHEDULER_Handle *sched;
126 * Configuration template.
128 const struct GNUNET_CONFIGURATION_Handle *cfg;
131 * Function to call on each started daemon.
133 GNUNET_TESTING_NotifyDaemonRunning cb;
141 * Function to call on each topology connection created
143 GNUNET_TESTING_NotifyConnection notify_connection;
146 * Callback for notify_connection
148 void *notify_connection_cls;
151 * NULL-terminated array of information about
154 struct HostData *hosts;
157 * Array of "total" peers.
159 struct PeerData *peers;
162 * Number of peers in this group.
171 struct GNUNET_CONFIGURATION_Handle *ret;
173 const char *hostname;
177 struct ConnectContext
179 struct GNUNET_TESTING_Daemon *first;
181 struct GNUNET_TESTING_Daemon *second;
183 struct GNUNET_TESTING_PeerGroup *pg;
187 * Number of connects we are waiting on, allows us to rate limit
190 static int outstanding_connects;
194 * Function to iterate over options. Copies
195 * the options to the target configuration,
196 * updating PORT values as needed.
199 * @param section name of the section
200 * @param option name of the option
201 * @param value value of the option
204 update_config (void *cls,
205 const char *section, const char *option, const char *value)
207 struct UpdateContext *ctx = cls;
211 if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival)))
213 GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++);
217 if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL))
219 value = ctx->hostname;
222 GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value);
227 * Create a new configuration using the given configuration
228 * as a template; however, each PORT in the existing cfg
229 * must be renumbered by incrementing "*port". If we run
230 * out of "*port" numbers, return NULL.
232 * @param cfg template configuration
233 * @param port port numbers to use, update to reflect
234 * port numbers that were used
235 * @param hostname hostname of the controlling host, to allow control connections from
237 * @return new configuration, NULL on error
239 static struct GNUNET_CONFIGURATION_Handle *
240 make_config (const struct GNUNET_CONFIGURATION_Handle *cfg, uint16_t * port, const char *hostname)
242 struct UpdateContext uc;
249 uc.ret = GNUNET_CONFIGURATION_create ();
250 uc.hostname = hostname;
252 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
253 if (uc.nport >= HIGH_PORT)
256 GNUNET_CONFIGURATION_destroy (uc.ret);
260 if (GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "control_host", &control_host) == GNUNET_OK)
262 GNUNET_asprintf(&allowed_hosts, "%s; 127.0.0.1;", control_host);
263 GNUNET_CONFIGURATION_set_value_string(uc.ret, "core", "ACCEPT_FROM", allowed_hosts);
264 GNUNET_free_non_null(control_host);
265 GNUNET_free(allowed_hosts);
269 /* arm needs to know to allow connections from the host on which it is running,
270 * otherwise gnunet-arm is unable to connect to it in some instances */
271 if (hostname != NULL)
273 GNUNET_asprintf(&allowed_hosts, "%s; 127.0.0.1;", hostname);
274 GNUNET_CONFIGURATION_set_value_string(uc.ret, "arm", "ACCEPT_FROM", allowed_hosts);
275 GNUNET_free(allowed_hosts);
278 *port = (uint16_t) uc.nport;
283 * Add entries to the peers connected list
285 * @param pg the peer group we are working with
286 * @param first index of the first peer
287 * @param second index of the second peer
289 * @return the number of connections added (can be 0, 1 or 2)
291 * FIXME: add both, or only add one?
292 * - if both are added, then we have to keep track
293 * when connecting so we don't double connect
294 * - if only one is added, we need to iterate over
295 * both lists to find out if connection already exists
296 * - having both allows the whitelisting/friend file
297 * creation to be easier
299 * -- For now, add both, we have to iterate over each to
300 * check for duplicates anyways, so we'll take the performance
301 * hit assuming we don't have __too__ many connections
305 add_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
308 struct PeerConnection *first_iter;
309 struct PeerConnection *second_iter;
312 struct PeerConnection *new_first;
313 struct PeerConnection *new_second;
315 first_iter = pg->peers[first].connected_peers;
316 add_first = GNUNET_YES;
317 while (first_iter != NULL)
319 if (first_iter->daemon == pg->peers[second].daemon)
320 add_first = GNUNET_NO;
321 first_iter = first_iter->next;
324 second_iter = pg->peers[second].connected_peers;
325 add_second = GNUNET_YES;
326 while (second_iter != NULL)
328 if (second_iter->daemon == pg->peers[first].daemon)
329 add_second = GNUNET_NO;
330 second_iter = second_iter->next;
336 new_first = GNUNET_malloc(sizeof(struct PeerConnection));
337 new_first->daemon = pg->peers[second].daemon;
338 new_first->next = pg->peers[first].connected_peers;
339 pg->peers[first].connected_peers = new_first;
340 pg->peers[first].num_connections++;
346 new_second = GNUNET_malloc(sizeof(struct PeerConnection));
347 new_second->daemon = pg->peers[first].daemon;
348 new_second->next = pg->peers[second].connected_peers;
349 pg->peers[second].connected_peers = new_second;
350 pg->peers[first].num_connections++;
358 * Scale free network construction as described in:
360 * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999.
362 * Start with a network of "one" peer, then progressively add
363 * peers up to the total number. At each step, iterate over
364 * all possible peers and connect new peer based on number of
365 * existing connections of the target peer.
367 * @param pg the peer group we are dealing with
369 * @return the number of connections created
372 create_scale_free (struct GNUNET_TESTING_PeerGroup *pg)
375 unsigned int total_connections;
376 unsigned int outer_count;
378 unsigned int previous_total_connections;
382 GNUNET_assert(pg->total > 1);
384 /* Add a connection between the first two nodes */
385 total_connections = add_connections(pg, 0, 1);
387 for (outer_count = 1; outer_count < pg->total; outer_count++)
389 previous_total_connections = total_connections;
390 for (i = 0; i < outer_count; i++)
392 probability = pg->peers[i].num_connections / (double)previous_total_connections;
393 random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
394 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
397 "Considering connecting peer %d to peer %d\n",
400 if (random < probability)
403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
404 "Connecting peer %d to peer %d\n",
407 total_connections += add_connections(pg, outer_count, i);
412 return total_connections;
416 create_small_world_ring(struct GNUNET_TESTING_PeerGroup *pg)
421 unsigned int randomPeer;
422 double random, logNModifier, percentage;
423 unsigned int smallWorldConnections;
429 int connect_attempts;
431 logNModifier = 0.5; /* FIXME: default value? */
432 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
437 if (sscanf(p_string, "%lf", &logNModifier) != 1)
438 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
439 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
443 GNUNET_free (p_string);
445 percentage = 0.5; /* FIXME: default percentage? */
446 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
451 if (sscanf(p_string, "%lf", &percentage) != 1)
452 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
453 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
457 GNUNET_free (p_string);
459 natLog = log (pg->total);
460 connsPerPeer = ceil (natLog * logNModifier);
462 if (connsPerPeer % 2 == 1)
465 smallWorldConnections = 0;
466 connect_attempts = 0;
467 for (i = 0; i < pg->total; i++)
470 max = i + connsPerPeer / 2;
471 min = i - connsPerPeer / 2;
473 if (max > pg->total - 1)
475 max = max - pg->total;
481 min = pg->total - 1 + min;
485 for (j = 0; j < connsPerPeer / 2; j++)
487 random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
488 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
489 if (random < percentage)
491 /* Connect to uniformly selected random peer */
493 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
495 while ((((randomPeer < max) && (randomPeer > min))
496 && (useAnd == 0)) || (((randomPeer > min)
497 || (randomPeer < max))
501 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
504 smallWorldConnections +=
505 add_connections (pg, i, randomPeer);
509 nodeToConnect = i + j + 1;
510 if (nodeToConnect > pg->total - 1)
512 nodeToConnect = nodeToConnect - pg->total;
515 add_connections (pg, i, nodeToConnect);
521 connect_attempts += smallWorldConnections;
523 return connect_attempts;
528 create_nated_internet (struct GNUNET_TESTING_PeerGroup *pg)
530 unsigned int outer_count, inner_count;
532 int connect_attempts;
533 double nat_percentage;
536 nat_percentage = 0.6; /* FIXME: default percentage? */
537 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
542 if (sscanf(p_string, "%lf", &nat_percentage) != 1)
543 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
544 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
548 GNUNET_free (p_string);
553 cutoff = (unsigned int) (nat_percentage * pg->total);
555 connect_attempts = 0;
557 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
559 for (inner_count = outer_count + 1; inner_count < pg->total;
562 if ((outer_count > cutoff) || (inner_count > cutoff))
565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
566 "Connecting peer %d to peer %d\n",
567 outer_count, inner_count);
569 connect_attempts += add_connections(pg, outer_count, inner_count);
574 return connect_attempts;
581 create_small_world (struct GNUNET_TESTING_PeerGroup *pg)
583 unsigned int i, j, k;
587 unsigned int toggle = 1;
588 unsigned int nodeToConnect;
590 unsigned int node1Row;
591 unsigned int node1Col;
592 unsigned int node2Row;
593 unsigned int node2Col;
594 unsigned int distance;
595 double probability, random, percentage;
596 unsigned int smallWorldConnections;
598 int connect_attempts;
599 square = floor (sqrt (pg->total));
603 percentage = 0.5; /* FIXME: default percentage? */
604 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
609 if (sscanf(p_string, "%lf", &percentage) != 1)
610 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
611 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
615 GNUNET_free (p_string);
617 probability = 0.5; /* FIXME: default percentage? */
618 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
623 if (sscanf(p_string, "%lf", &probability) != 1)
624 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
625 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
629 GNUNET_free (p_string);
631 if (square * square != pg->total)
633 while (rows * cols < pg->total)
644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
645 _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
649 connect_attempts = 0;
650 /* Rows and columns are all sorted out, now iterate over all nodes and connect each
651 * to the node to its right and above. Once this is over, we'll have our torus!
652 * Special case for the last node (if the rows and columns are not equal), connect
653 * to the first in the row to maintain topology.
655 for (i = 0; i < pg->total; i++)
657 /* First connect to the node to the right */
658 if (((i + 1) % cols != 0) && (i + 1 != pg->total))
659 nodeToConnect = i + 1;
660 else if (i + 1 == pg->total)
661 nodeToConnect = rows * cols - cols;
663 nodeToConnect = i - cols + 1;
665 connect_attempts += add_connections (pg, i, nodeToConnect);
668 nodeToConnect = (rows * cols) - cols + i;
670 nodeToConnect = i - cols;
672 if (nodeToConnect < pg->total)
673 connect_attempts += add_connections (pg, i, nodeToConnect);
675 natLog = log (pg->total);
676 #if VERBOSE_TESTING > 2
677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
678 _("natural log of %d is %d, will run %d iterations\n"),
679 pg->total, natLog, (int) (natLog * percentage));
680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Total connections added thus far: %u!\n"), connect_attempts);
682 smallWorldConnections = 0;
683 for (i = 0; i < (int) (natLog * percentage); i++)
685 for (j = 0; j < pg->total; j++)
687 /* Determine the row and column of node at position j on the 2d torus */
689 node1Col = j - (node1Row * cols);
690 for (k = 0; k < pg->total; k++)
692 /* Determine the row and column of node at position k on the 2d torus */
694 node2Col = k - (node2Row * cols);
695 /* Simple Cartesian distance */
696 distance = abs (node1Row - node2Row) + abs (node1Col - node2Col);
699 /* Calculate probability as 1 over the square of the distance */
700 probability = 1.0 / (distance * distance);
701 /* Choose a random value between 0 and 1 */
702 random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
703 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
704 /* If random < probability, then connect the two nodes */
705 if (random < probability)
706 smallWorldConnections += add_connections (pg, j, k);
712 connect_attempts += smallWorldConnections;
713 #if VERBOSE_TESTING > 2
714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
715 _("Total connections added for small world: %d!\n"),
716 smallWorldConnections);
718 return connect_attempts;
724 create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg)
727 unsigned int outer_count;
728 unsigned int inner_count;
729 int connect_attempts;
733 probability = 0.5; /* FIXME: default percentage? */
734 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
739 if (sscanf(p_string, "%lf", &probability) != 1)
740 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
741 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
745 GNUNET_free (p_string);
747 connect_attempts = 0;
748 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
750 for (inner_count = outer_count + 1; inner_count < pg->total;
753 temp_rand = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
754 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
757 _("rand is %f probability is %f\n"), temp_rand,
760 if (temp_rand < probability)
762 connect_attempts += add_connections (pg, outer_count, inner_count);
767 return connect_attempts;
771 create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg)
777 unsigned int toggle = 1;
778 unsigned int nodeToConnect;
779 int connect_attempts;
781 connect_attempts = 0;
783 square = floor (sqrt (pg->total));
787 if (square * square != pg->total)
789 while (rows * cols < pg->total)
800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
801 _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
804 /* Rows and columns are all sorted out, now iterate over all nodes and connect each
805 * to the node to its right and above. Once this is over, we'll have our torus!
806 * Special case for the last node (if the rows and columns are not equal), connect
807 * to the first in the row to maintain topology.
809 for (i = 0; i < pg->total; i++)
811 /* First connect to the node to the right */
812 if (((i + 1) % cols != 0) && (i + 1 != pg->total))
813 nodeToConnect = i + 1;
814 else if (i + 1 == pg->total)
815 nodeToConnect = rows * cols - cols;
817 nodeToConnect = i - cols + 1;
819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
820 "Connecting peer %d to peer %d\n",
823 connect_attempts += add_connections(pg, i, nodeToConnect);
825 /* Second connect to the node immediately above */
827 nodeToConnect = (rows * cols) - cols + i;
829 nodeToConnect = i - cols;
831 if (nodeToConnect < pg->total)
834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
835 "Connecting peer %d to peer %d\n",
838 connect_attempts += add_connections(pg, i, nodeToConnect);
843 return connect_attempts;
849 create_clique (struct GNUNET_TESTING_PeerGroup *pg)
851 unsigned int outer_count;
852 unsigned int inner_count;
853 int connect_attempts;
855 connect_attempts = 0;
857 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
859 for (inner_count = outer_count + 1; inner_count < pg->total;
863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
864 "Connecting peer %d to peer %d\n",
865 outer_count, inner_count);
867 connect_attempts += add_connections(pg, outer_count, inner_count);
871 return connect_attempts;
876 create_ring (struct GNUNET_TESTING_PeerGroup *pg)
879 int connect_attempts;
881 connect_attempts = 0;
883 /* Connect each peer to the next highest numbered peer */
884 for (count = 0; count < pg->total - 1; count++)
887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
888 "Connecting peer %d to peer %d\n",
891 connect_attempts += add_connections(pg, count, count + 1);
894 /* Connect the last peer to the first peer */
895 connect_attempts += add_connections(pg, pg->total - 1, 0);
897 return connect_attempts;
902 * Create the friend files based on the PeerConnection's
903 * of each peer in the peer group, and copy the files
904 * to the appropriate place
906 * @param pg the peer group we are dealing with
909 create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
911 FILE *temp_friend_handle;
912 unsigned int pg_iter;
913 struct PeerConnection *connection_iter;
914 struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
915 char *temp_service_path;
918 struct GNUNET_PeerIdentity *temppeer;
920 enum GNUNET_OS_ProcessStatusType type;
921 unsigned long return_code;
926 pidarr = GNUNET_malloc(sizeof(pid_t) * pg->total);
927 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
929 mytemp = GNUNET_DISK_mktemp("friends");
930 temp_friend_handle = fopen (mytemp, "wt");
931 connection_iter = pg->peers[pg_iter].connected_peers;
932 while (connection_iter != NULL)
934 temppeer = &connection_iter->daemon->id;
935 GNUNET_CRYPTO_hash_to_enc(&temppeer->hashPubKey, &peer_enc);
936 fprintf(temp_friend_handle, "%s\n", (char *)&peer_enc);
937 connection_iter = connection_iter->next;
940 fclose(temp_friend_handle);
943 GNUNET_CONFIGURATION_get_value_string(pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path))
945 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
946 _("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
949 if (UNLINK (mytemp) != 0)
950 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp);
951 GNUNET_free (mytemp);
955 if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
957 GNUNET_asprintf (&arg, "%s/friends", temp_service_path);
958 pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
959 "mv", mytemp, arg, NULL);
961 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
962 _("Copying file with command cp %s %s\n"), mytemp, arg);
967 else /* Remote, scp the file to the correct place */
969 if (NULL != pg->peers[pg_iter].daemon->username)
970 GNUNET_asprintf (&arg, "%s@%s:%s/friends", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path);
972 GNUNET_asprintf (&arg, "%s:%s/friends", pg->peers[pg_iter].daemon->hostname, temp_service_path);
973 pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp",
974 "scp", mytemp, arg, NULL);
977 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
978 _("Copying file with command scp %s %s\n"), mytemp, arg);
982 GNUNET_free (temp_service_path);
983 GNUNET_free (mytemp);
988 while ((count < max_wait) && (ret != GNUNET_OK))
991 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
994 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
995 _("Checking copy status of file %d\n"), pg_iter);
997 if (pidarr[pg_iter] != 0) /* Check for already completed! */
999 if (GNUNET_OS_process_status(pidarr[pg_iter], &type, &return_code) != GNUNET_OK)
1001 ret = GNUNET_SYSERR;
1003 else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0))
1005 ret = GNUNET_SYSERR;
1009 pidarr[pg_iter] = 0;
1011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1012 _("File %d copied\n"), pg_iter);
1018 if (ret == GNUNET_SYSERR)
1025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1026 _("Finished copying all friend files!\n"));
1028 GNUNET_free(pidarr);
1033 * Internal notification of a connection, kept so that we can ensure some connections
1034 * happen instead of flooding all testing daemons with requests to connect.
1036 static void internal_connect_notify (void *cls,
1037 const struct GNUNET_PeerIdentity *first,
1038 const struct GNUNET_PeerIdentity *second,
1039 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
1040 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
1041 struct GNUNET_TESTING_Daemon *first_daemon,
1042 struct GNUNET_TESTING_Daemon *second_daemon,
1045 struct GNUNET_TESTING_PeerGroup *pg = cls;
1046 outstanding_connects--;
1048 pg->notify_connection(pg->notify_connection_cls, first, second, first_cfg, second_cfg, first_daemon, second_daemon, emsg);
1052 static void schedule_connect(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1054 struct ConnectContext *connect_context = cls;
1056 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1059 if (outstanding_connects > MAX_OUTSTANDING_CONNECTIONS)
1061 #if VERBOSE_TESTING > 2
1062 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1063 _("Delaying connect, we have too many outstanding connections!\n"));
1065 GNUNET_SCHEDULER_add_delayed(connect_context->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3), &schedule_connect, connect_context);
1069 #if VERBOSE_TESTING > 2
1070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1071 _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
1073 outstanding_connects++;
1074 GNUNET_TESTING_daemons_connect (connect_context->first,
1075 connect_context->second,
1078 &internal_connect_notify,
1079 connect_context->pg);
1080 GNUNET_free(connect_context);
1085 * Connect the topology as specified by the PeerConnection's
1086 * of each peer in the peer group
1088 * @param pg the peer group we are dealing with
1091 connect_topology (struct GNUNET_TESTING_PeerGroup *pg)
1093 unsigned int pg_iter;
1094 struct PeerConnection *connection_iter;
1095 struct ConnectContext *connect_context;
1097 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1099 connection_iter = pg->peers[pg_iter].connected_peers;
1100 while (connection_iter != NULL)
1102 connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
1103 connect_context->pg = pg;
1104 connect_context->first = pg->peers[pg_iter].daemon;
1105 connect_context->second = connection_iter->daemon;
1106 GNUNET_SCHEDULER_add_now(pg->sched, &schedule_connect, connect_context);
1107 connection_iter = connection_iter->next;
1114 * Takes a peer group and attempts to create a topology based on the
1115 * one specified in the configuration file. Returns the number of connections
1116 * that will attempt to be created, but this will happen asynchronously(?) so
1117 * the caller will have to keep track (via the callback) of whether or not
1118 * the connection actually happened.
1120 * @param pg the peer group struct representing the running peers
1121 * @param topology which topology to connect the peers in
1123 * @return the number of connections should be created by the topology, so the
1124 * caller knows how many to wait for (if it so chooses)
1128 GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg, enum GNUNET_TESTING_Topology topology)
1131 int num_connections;
1133 GNUNET_assert (pg->notify_connection != NULL);
1138 case GNUNET_TESTING_TOPOLOGY_CLIQUE:
1140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1141 _("Creating clique topology\n"));
1143 num_connections = create_clique (pg);
1145 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
1147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1148 _("Creating small world (ring) topology\n"));
1150 num_connections = create_small_world_ring (pg);
1152 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
1154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1155 _("Creating small world (2d-torus) topology\n"));
1157 num_connections = create_small_world (pg);
1159 case GNUNET_TESTING_TOPOLOGY_RING:
1161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1162 _("Creating ring topology\n"));
1164 num_connections = create_ring (pg);
1166 case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
1168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1169 _("Creating 2d torus topology\n"));
1171 num_connections = create_2d_torus (pg);
1173 case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
1175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1176 _("Creating Erdos-Renyi topology\n"));
1178 num_connections = create_erdos_renyi (pg);
1180 case GNUNET_TESTING_TOPOLOGY_INTERNAT:
1182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1183 _("Creating InterNAT topology\n"));
1185 num_connections = create_nated_internet (pg);
1187 case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
1189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1190 _("Creating Scale Free topology\n"));
1192 num_connections = create_scale_free (pg);
1194 case GNUNET_TESTING_TOPOLOGY_NONE:
1195 num_connections = 0;
1198 num_connections = 0;
1201 if (num_connections < 1)
1202 return GNUNET_SYSERR;
1204 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
1205 ret = create_and_copy_friend_files(pg);
1206 if (ret == GNUNET_OK)
1207 connect_topology(pg);
1211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1212 _("Failed during friend file copying!\n"));
1214 return GNUNET_SYSERR;
1217 return num_connections;
1221 * Start count gnunetd processes with the same set of transports and
1222 * applications. The port numbers (any option called "PORT") will be
1223 * adjusted to ensure that no two peers running on the same system
1224 * have the same port(s) in their respective configurations.
1226 * @param sched scheduler to use
1227 * @param cfg configuration template to use
1228 * @param total number of daemons to start
1229 * @param cb function to call on each daemon that was started
1230 * @param cb_cls closure for cb
1231 * @param connect_callback function to call each time two hosts are connected
1232 * @param connect_callback_cls closure for connect_callback
1233 * @param hostnames space-separated list of hostnames to use; can be NULL (to run
1234 * everything on localhost).
1235 * @return NULL on error, otherwise handle to control peer group
1237 struct GNUNET_TESTING_PeerGroup *
1238 GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
1239 const struct GNUNET_CONFIGURATION_Handle *cfg,
1241 GNUNET_TESTING_NotifyDaemonRunning cb,
1243 GNUNET_TESTING_NotifyConnection
1244 connect_callback, void *connect_callback_cls,
1245 const char *hostnames)
1247 struct GNUNET_TESTING_PeerGroup *pg;
1251 const char *hostname;
1252 char *baseservicehome;
1253 char *newservicehome;
1255 struct GNUNET_CONFIGURATION_Handle *pcfg;
1257 unsigned int hostcnt;
1266 pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
1270 pg->cb_cls = cb_cls;
1271 pg->notify_connection = connect_callback;
1272 pg->notify_connection_cls = connect_callback_cls;
1274 pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
1275 if (NULL != hostnames)
1278 /* skip leading spaces */
1279 while ((0 != *hostnames) && (isspace (*hostnames)))
1282 while ('\0' != *rpos)
1284 if (isspace (*rpos))
1288 pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
1290 start = GNUNET_strdup (hostnames);
1292 while ('\0' != *pos)
1297 if (strlen (start) > 0)
1299 pg->hosts[off].minport = LOW_PORT;
1300 pg->hosts[off++].hostname = start;
1306 if (strlen (start) > 0)
1308 pg->hosts[off].minport = LOW_PORT;
1309 pg->hosts[off++].hostname = start;
1313 GNUNET_free (start);
1314 GNUNET_free (pg->hosts);
1318 minport = 0; /* make gcc happy */
1325 for (off = 0; off < total; off++)
1329 hostname = pg->hosts[off % hostcnt].hostname;
1330 pcfg = make_config (cfg, &pg->hosts[off % hostcnt].minport, hostname);
1335 pcfg = make_config (cfg, &minport, hostname);
1340 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1342 ("Could not create configuration for peer number %u on `%s'!\n"),
1343 off, hostname == NULL ? "localhost" : hostname);
1348 GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME",
1351 GNUNET_asprintf (&newservicehome,
1352 "%s/%d/", baseservicehome, off);
1353 GNUNET_free (baseservicehome);
1357 tmpdir = getenv ("TMPDIR");
1358 tmpdir = tmpdir ? tmpdir : "/tmp";
1359 GNUNET_asprintf (&newservicehome,
1362 "gnunet-testing-test-test", off);
1364 GNUNET_CONFIGURATION_set_value_string (pcfg,
1366 "SERVICEHOME", newservicehome);
1367 GNUNET_free (newservicehome);
1368 pg->peers[off].cfg = pcfg;
1369 pg->peers[off].daemon = GNUNET_TESTING_daemon_start (sched,
1373 if (NULL == pg->peers[off].daemon)
1374 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1375 _("Could not start peer number %u!\n"), off);
1381 * Get a daemon by number, so callers don't have to do nasty
1382 * offsetting operation.
1384 struct GNUNET_TESTING_Daemon *
1385 GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position)
1387 if (position < pg->total)
1388 return pg->peers[position].daemon;
1394 * Shutdown all peers started in the given group.
1396 * @param pg handle to the peer group
1399 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg)
1402 struct PeerConnection *pos;
1403 struct PeerConnection *next;
1405 for (off = 0; off < pg->total; off++)
1407 /* FIXME: should we wait for our
1408 continuations to be called here? This
1409 would require us to take a continuation
1412 if (NULL != pg->peers[off].daemon)
1413 GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, NULL, NULL);
1414 if (NULL != pg->peers[off].cfg)
1415 GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
1417 pos = pg->peers[off].connected_peers;
1426 GNUNET_free (pg->peers);
1427 if (NULL != pg->hosts)
1429 GNUNET_free (pg->hosts[0].hostname);
1430 GNUNET_free (pg->hosts);
1436 /* end of testing_group.c */