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, 180)
56 struct PeerConnection *next;
59 * Pointer to daemon handle
61 struct GNUNET_TESTING_Daemon *daemon;
66 * Data we keep per peer.
71 * (Initial) configuration of the host.
72 * (initial because clients could change
73 * it and we would not know about those
76 struct GNUNET_CONFIGURATION_Handle *cfg;
79 * Handle for controlling the daemon.
81 struct GNUNET_TESTING_Daemon *daemon;
84 * Linked list of peer connections (simply indexes of PeerGroup)
85 * FIXME: Question, store pointer or integer? Pointer for now...
87 struct PeerConnection *connected_peers;
92 * Data we keep per host.
102 * Lowest port that we have not yet used
110 * Handle to a group of GNUnet peers.
112 struct GNUNET_TESTING_PeerGroup
117 struct GNUNET_SCHEDULER_Handle *sched;
120 * Configuration template.
122 const struct GNUNET_CONFIGURATION_Handle *cfg;
125 * Function to call on each started daemon.
127 GNUNET_TESTING_NotifyDaemonRunning cb;
135 * Function to call on each topology connection created
137 GNUNET_TESTING_NotifyConnection notify_connection;
140 * Callback for notify_connection
142 void *notify_connection_cls;
145 * NULL-terminated array of information about
148 struct HostData *hosts;
151 * Array of "total" peers.
153 struct PeerData *peers;
156 * Number of peers in this group.
165 struct GNUNET_CONFIGURATION_Handle *ret;
170 struct ConnectContext
172 struct GNUNET_TESTING_Daemon *first;
174 struct GNUNET_TESTING_Daemon *second;
176 struct GNUNET_TESTING_PeerGroup *pg;
180 * Number of connects we are waiting on, allows us to rate limit
183 static int outstanding_connects;
186 * Function to iterate over options. Copies
187 * the options to the target configuration,
188 * updating PORT values as needed.
191 * @param section name of the section
192 * @param option name of the option
193 * @param value value of the option
196 update_config (void *cls,
197 const char *section, const char *option, const char *value)
199 struct UpdateContext *ctx = cls;
203 if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival)))
205 GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++);
208 GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value);
213 * Create a new configuration using the given configuration
214 * as a template; however, each PORT in the existing cfg
215 * must be renumbered by incrementing "*port". If we run
216 * out of "*port" numbers, return NULL.
218 * @param cfg template configuration
219 * @param port port numbers to use, update to reflect
220 * port numbers that were used
221 * @return new configuration, NULL on error
223 static struct GNUNET_CONFIGURATION_Handle *
224 make_config (const struct GNUNET_CONFIGURATION_Handle *cfg, uint16_t * port)
226 struct UpdateContext uc;
233 uc.ret = GNUNET_CONFIGURATION_create ();
235 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
236 if (uc.nport >= HIGH_PORT)
239 GNUNET_CONFIGURATION_destroy (uc.ret);
243 if (GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "control_host", &control_host) == GNUNET_OK)
245 GNUNET_asprintf(&allowed_hosts, "%s; 127.0.0.1;", control_host);
246 fprintf(stderr, "FOUND CONTROL_HOST OPTION %s, setting to %s\n", control_host, allowed_hosts);
247 GNUNET_CONFIGURATION_set_value_string(uc.ret, "core", "ACCEPT_FROM", allowed_hosts);
248 GNUNET_free(allowed_hosts);
251 *port = (uint16_t) uc.nport;
256 * Add entries to the peers connected list
258 * @param pg the peer group we are working with
259 * @param first index of the first peer
260 * @param second index of the second peer
262 * @return the number of connections added (can be 0, 1 or 2)
264 * FIXME: add both, or only add one?
265 * - if both are added, then we have to keep track
266 * when connecting so we don't double connect
267 * - if only one is added, we need to iterate over
268 * both lists to find out if connection already exists
269 * - having both allows the whitelisting/friend file
270 * creation to be easier
272 * -- For now, add both, we have to iterate over each to
273 * check for duplicates anyways, so we'll take the performance
274 * hit assuming we don't have __too__ many connections
278 add_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
281 struct PeerConnection *first_iter;
282 struct PeerConnection *second_iter;
285 struct PeerConnection *new_first;
286 struct PeerConnection *new_second;
288 first_iter = pg->peers[first].connected_peers;
289 add_first = GNUNET_YES;
290 while (first_iter != NULL)
292 if (first_iter->daemon == pg->peers[second].daemon)
293 add_first = GNUNET_NO;
294 first_iter = first_iter->next;
297 second_iter = pg->peers[second].connected_peers;
298 add_second = GNUNET_YES;
299 while (second_iter != NULL)
301 if (second_iter->daemon == pg->peers[first].daemon)
302 add_second = GNUNET_NO;
303 second_iter = second_iter->next;
309 new_first = GNUNET_malloc(sizeof(struct PeerConnection));
310 new_first->daemon = pg->peers[second].daemon;
311 new_first->next = pg->peers[first].connected_peers;
312 pg->peers[first].connected_peers = new_first;
318 new_second = GNUNET_malloc(sizeof(struct PeerConnection));
319 new_second->daemon = pg->peers[first].daemon;
320 new_second->next = pg->peers[second].connected_peers;
321 pg->peers[second].connected_peers = new_second;
329 create_small_world_ring(struct GNUNET_TESTING_PeerGroup *pg)
334 unsigned int randomPeer;
335 double random, logNModifier, percentage;
336 unsigned int smallWorldConnections;
342 int connect_attempts;
344 logNModifier = 0.5; /* FIXME: default value? */
345 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
350 if (sscanf(p_string, "%lf", &logNModifier) != 1)
351 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
352 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
356 GNUNET_free (p_string);
358 percentage = 0.5; /* FIXME: default percentage? */
359 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
364 if (sscanf(p_string, "%lf", &percentage) != 1)
365 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
366 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
370 GNUNET_free (p_string);
372 natLog = log (pg->total);
373 connsPerPeer = ceil (natLog * logNModifier);
375 if (connsPerPeer % 2 == 1)
378 smallWorldConnections = 0;
379 connect_attempts = 0;
380 for (i = 0; i < pg->total; i++)
383 max = i + connsPerPeer / 2;
384 min = i - connsPerPeer / 2;
386 if (max > pg->total - 1)
388 max = max - pg->total;
394 min = pg->total - 1 + min;
398 for (j = 0; j < connsPerPeer / 2; j++)
400 random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
401 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
402 if (random < percentage)
404 /* Connect to uniformly selected random peer */
406 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
408 while ((((randomPeer < max) && (randomPeer > min))
409 && (useAnd == 0)) || (((randomPeer > min)
410 || (randomPeer < max))
414 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
417 smallWorldConnections +=
418 add_connections (pg, i, randomPeer);
422 nodeToConnect = i + j + 1;
423 if (nodeToConnect > pg->total - 1)
425 nodeToConnect = nodeToConnect - pg->total;
428 add_connections (pg, i, nodeToConnect);
434 connect_attempts += smallWorldConnections;
436 return connect_attempts;
441 create_nated_internet (struct GNUNET_TESTING_PeerGroup *pg)
443 unsigned int outer_count, inner_count;
445 int connect_attempts;
446 double nat_percentage;
449 nat_percentage = 0.6; /* FIXME: default percentage? */
450 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
455 if (sscanf(p_string, "%lf", &nat_percentage) != 1)
456 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
457 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
461 GNUNET_free (p_string);
466 cutoff = (unsigned int) (nat_percentage * pg->total);
468 connect_attempts = 0;
470 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
472 for (inner_count = outer_count + 1; inner_count < pg->total;
475 if ((outer_count > cutoff) || (inner_count > cutoff))
478 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
479 "Connecting peer %d to peer %d\n",
480 outer_count, inner_count);
482 connect_attempts += add_connections(pg, outer_count, inner_count);
487 return connect_attempts;
494 create_small_world (struct GNUNET_TESTING_PeerGroup *pg)
496 unsigned int i, j, k;
500 unsigned int toggle = 1;
501 unsigned int nodeToConnect;
503 unsigned int node1Row;
504 unsigned int node1Col;
505 unsigned int node2Row;
506 unsigned int node2Col;
507 unsigned int distance;
508 double probability, random, percentage;
509 unsigned int smallWorldConnections;
511 int connect_attempts;
512 square = floor (sqrt (pg->total));
516 percentage = 0.5; /* FIXME: default percentage? */
517 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
522 if (sscanf(p_string, "%lf", &percentage) != 1)
523 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
524 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
528 GNUNET_free (p_string);
530 probability = 0.5; /* FIXME: default percentage? */
531 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
536 if (sscanf(p_string, "%lf", &probability) != 1)
537 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
538 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
542 GNUNET_free (p_string);
544 if (square * square != pg->total)
546 while (rows * cols < pg->total)
557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
558 _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
562 connect_attempts = 0;
563 /* Rows and columns are all sorted out, now iterate over all nodes and connect each
564 * to the node to its right and above. Once this is over, we'll have our torus!
565 * Special case for the last node (if the rows and columns are not equal), connect
566 * to the first in the row to maintain topology.
568 for (i = 0; i < pg->total; i++)
570 /* First connect to the node to the right */
571 if (((i + 1) % cols != 0) && (i + 1 != pg->total))
572 nodeToConnect = i + 1;
573 else if (i + 1 == pg->total)
574 nodeToConnect = rows * cols - cols;
576 nodeToConnect = i - cols + 1;
578 connect_attempts += add_connections (pg, i, nodeToConnect);
581 nodeToConnect = (rows * cols) - cols + i;
583 nodeToConnect = i - cols;
585 if (nodeToConnect < pg->total)
586 connect_attempts += add_connections (pg, i, nodeToConnect);
588 natLog = log (pg->total);
590 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
591 _("natural log of %d is %d, will run %d iterations\n"),
592 pg->total, natLog, (int) (natLog * percentage));
593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Total connections added thus far: %u!\n"), connect_attempts);
595 smallWorldConnections = 0;
596 for (i = 0; i < (int) (natLog * percentage); i++)
598 for (j = 0; j < pg->total; j++)
600 /* Determine the row and column of node at position j on the 2d torus */
602 node1Col = j - (node1Row * cols);
603 for (k = 0; k < pg->total; k++)
605 /* Determine the row and column of node at position k on the 2d torus */
607 node2Col = k - (node2Row * cols);
608 /* Simple Cartesian distance */
609 distance = abs (node1Row - node2Row) + abs (node1Col - node2Col);
612 /* Calculate probability as 1 over the square of the distance */
613 probability = 1.0 / (distance * distance);
614 /* Choose a random value between 0 and 1 */
615 random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
616 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
617 /* If random < probability, then connect the two nodes */
618 if (random < probability)
619 smallWorldConnections += add_connections (pg, j, k);
625 connect_attempts += smallWorldConnections;
627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
628 _("Total connections added for small world: %d!\n"),
629 smallWorldConnections);
631 return connect_attempts;
637 create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg)
640 unsigned int outer_count;
641 unsigned int inner_count;
642 int connect_attempts;
646 probability = 0.5; /* FIXME: default percentage? */
647 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
652 if (sscanf(p_string, "%lf", &probability) != 1)
653 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
654 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
658 GNUNET_free (p_string);
660 connect_attempts = 0;
661 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
663 for (inner_count = outer_count + 1; inner_count < pg->total;
666 temp_rand = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
667 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
670 _("rand is %f probability is %f\n"), temp_rand,
673 if (temp_rand < probability)
675 connect_attempts += add_connections (pg, outer_count, inner_count);
680 return connect_attempts;
684 create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg)
690 unsigned int toggle = 1;
691 unsigned int nodeToConnect;
692 int connect_attempts;
694 connect_attempts = 0;
696 square = floor (sqrt (pg->total));
700 if (square * square != pg->total)
702 while (rows * cols < pg->total)
713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
714 _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
717 /* Rows and columns are all sorted out, now iterate over all nodes and connect each
718 * to the node to its right and above. Once this is over, we'll have our torus!
719 * Special case for the last node (if the rows and columns are not equal), connect
720 * to the first in the row to maintain topology.
722 for (i = 0; i < pg->total; i++)
724 /* First connect to the node to the right */
725 if (((i + 1) % cols != 0) && (i + 1 != pg->total))
726 nodeToConnect = i + 1;
727 else if (i + 1 == pg->total)
728 nodeToConnect = rows * cols - cols;
730 nodeToConnect = i - cols + 1;
732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
733 "Connecting peer %d to peer %d\n",
736 connect_attempts += add_connections(pg, i, nodeToConnect);
738 /* Second connect to the node immediately above */
740 nodeToConnect = (rows * cols) - cols + i;
742 nodeToConnect = i - cols;
744 if (nodeToConnect < pg->total)
747 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
748 "Connecting peer %d to peer %d\n",
751 connect_attempts += add_connections(pg, i, nodeToConnect);
756 return connect_attempts;
762 create_clique (struct GNUNET_TESTING_PeerGroup *pg)
764 unsigned int outer_count;
765 unsigned int inner_count;
766 int connect_attempts;
768 connect_attempts = 0;
770 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
772 for (inner_count = outer_count + 1; inner_count < pg->total;
776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
777 "Connecting peer %d to peer %d\n",
778 outer_count, inner_count);
780 connect_attempts += add_connections(pg, outer_count, inner_count);
784 return connect_attempts;
789 create_ring (struct GNUNET_TESTING_PeerGroup *pg)
792 int connect_attempts;
794 connect_attempts = 0;
796 /* Connect each peer to the next highest numbered peer */
797 for (count = 0; count < pg->total - 1; count++)
800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
801 "Connecting peer %d to peer %d\n",
804 connect_attempts += add_connections(pg, count, count + 1);
807 /* Connect the last peer to the first peer */
808 connect_attempts += add_connections(pg, pg->total - 1, 0);
810 return connect_attempts;
815 * Create the friend files based on the PeerConnection's
816 * of each peer in the peer group, and copy the files
817 * to the appropriate place
819 * @param pg the peer group we are dealing with
822 create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
824 FILE *temp_friend_handle;
825 unsigned int pg_iter;
826 struct PeerConnection *connection_iter;
827 struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
828 char *temp_service_path;
831 struct GNUNET_PeerIdentity *temppeer;
833 enum GNUNET_OS_ProcessStatusType type;
834 unsigned long return_code;
839 pidarr = GNUNET_malloc(sizeof(pid_t) * pg->total);
840 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
842 mytemp = GNUNET_DISK_mktemp("friends");
843 temp_friend_handle = fopen (mytemp, "wt");
844 connection_iter = pg->peers[pg_iter].connected_peers;
845 while (connection_iter != NULL)
847 temppeer = &connection_iter->daemon->id;
848 GNUNET_CRYPTO_hash_to_enc(&temppeer->hashPubKey, &peer_enc);
849 fprintf(temp_friend_handle, "%s\n", (char *)&peer_enc);
850 connection_iter = connection_iter->next;
853 fclose(temp_friend_handle);
856 GNUNET_CONFIGURATION_get_value_string(pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path))
858 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
859 _("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
862 if (UNLINK (mytemp) != 0)
863 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp);
864 GNUNET_free (mytemp);
868 if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
870 GNUNET_asprintf (&arg, "%s/friends", temp_service_path);
871 pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
872 "mv", mytemp, arg, NULL);
874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
875 _("Copying file with command cp %s %s\n"), mytemp, arg);
880 else /* Remote, scp the file to the correct place */
882 if (NULL != pg->peers[pg_iter].daemon->username)
883 GNUNET_asprintf (&arg, "%s@%s:%s/friends", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path);
885 GNUNET_asprintf (&arg, "%s:%s/friends", pg->peers[pg_iter].daemon->hostname, temp_service_path);
886 pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp",
887 "scp", mytemp, arg, NULL);
890 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
891 _("Copying file with command scp %s %s\n"), mytemp, arg);
895 GNUNET_free (temp_service_path);
896 GNUNET_free (mytemp);
901 while ((count < max_wait) && (ret != GNUNET_OK))
904 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
907 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
908 _("Checking copy status of file %d\n"), pg_iter);
910 if (pidarr[pg_iter] != 0) /* Check for already completed! */
912 if (GNUNET_OS_process_status(pidarr[pg_iter], &type, &return_code) != GNUNET_OK)
916 else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0))
924 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
925 _("File %d copied\n"), pg_iter);
931 if (ret == GNUNET_SYSERR)
942 * Internal notification of a connection, kept so that we can ensure some connections
943 * happen instead of flooding all testing daemons with requests to connect.
945 static void internal_connect_notify (void *cls,
946 const struct GNUNET_PeerIdentity *first,
947 const struct GNUNET_PeerIdentity *second,
948 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
949 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
950 struct GNUNET_TESTING_Daemon *first_daemon,
951 struct GNUNET_TESTING_Daemon *second_daemon,
954 struct GNUNET_TESTING_PeerGroup *pg = cls;
955 outstanding_connects--;
957 pg->notify_connection(pg->notify_connection_cls, first, second, first_cfg, second_cfg, first_daemon, second_daemon, emsg);
961 static void schedule_connect(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
963 struct ConnectContext *connect_context = cls;
965 if (outstanding_connects > MAX_OUTSTANDING_CONNECTIONS)
968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
969 _("Delaying connect, we have too many outstanding connections!\n"));
971 GNUNET_SCHEDULER_add_delayed(connect_context->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3), &schedule_connect, connect_context);
976 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
977 _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
979 outstanding_connects++;
980 GNUNET_TESTING_daemons_connect (connect_context->first,
981 connect_context->second,
983 &internal_connect_notify,
984 connect_context->pg);
985 GNUNET_free(connect_context);
990 * Connect the topology as specified by the PeerConnection's
991 * of each peer in the peer group
993 * @param pg the peer group we are dealing with
996 connect_topology (struct GNUNET_TESTING_PeerGroup *pg)
998 unsigned int pg_iter;
999 struct PeerConnection *connection_iter;
1000 struct ConnectContext *connect_context;
1002 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1004 connection_iter = pg->peers[pg_iter].connected_peers;
1005 while (connection_iter != NULL)
1007 connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
1008 connect_context->pg = pg;
1009 connect_context->first = pg->peers[pg_iter].daemon;
1010 connect_context->second = connection_iter->daemon;
1012 GNUNET_SCHEDULER_add_now(pg->sched, &schedule_connect, connect_context);
1013 /*GNUNET_TESTING_daemons_connect (pg->peers[pg_iter].daemon,
1014 connection_iter->daemon,
1016 pg->notify_connection,
1017 pg->notify_connection_cls);*/
1018 connection_iter = connection_iter->next;
1020 /*if (outstanding_connects > MAX_OUTSTANDING_CONNECTS)
1023 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1024 _("Sleeping to give peers a chance to connect!\n"));
1034 * Takes a peer group and attempts to create a topology based on the
1035 * one specified in the configuration file. Returns the number of connections
1036 * that will attempt to be created, but this will happen asynchronously(?) so
1037 * the caller will have to keep track (via the callback) of whether or not
1038 * the connection actually happened.
1040 * @param pg the peer group struct representing the running peers
1042 * @return the number of connections should be created by the topology, so the
1043 * caller knows how many to wait for (if it so chooses)
1047 GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg)
1049 unsigned long long topology_num;
1051 int num_connections;
1053 GNUNET_assert (pg->notify_connection != NULL);
1056 GNUNET_CONFIGURATION_get_value_number (pg->cfg, "testing", "topology",
1059 switch (topology_num)
1061 case GNUNET_TESTING_TOPOLOGY_CLIQUE:
1063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1064 _("Creating clique topology (may take a bit!)\n"));
1066 num_connections = create_clique (pg);
1068 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
1070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1071 _("Creating small world (ring) topology (may take a bit!)\n"));
1073 num_connections = create_small_world_ring (pg);
1075 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
1077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1078 _("Creating small world (2d-torus) topology (may take a bit!)\n"));
1080 num_connections = create_small_world (pg);
1082 case GNUNET_TESTING_TOPOLOGY_RING:
1084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1085 _("Creating ring topology (may take a bit!)\n"));
1087 num_connections = create_ring (pg);
1089 case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
1091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1092 _("Creating 2d torus topology (may take a bit!)\n"));
1094 num_connections = create_2d_torus (pg);
1096 case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
1098 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1099 _("Creating Erdos-Renyi topology (may take a bit!)\n"));
1101 num_connections = create_erdos_renyi (pg);
1103 case GNUNET_TESTING_TOPOLOGY_INTERNAT:
1105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1106 _("Creating InterNAT topology (may take a bit!)\n"));
1108 num_connections = create_nated_internet (pg);
1110 case GNUNET_TESTING_TOPOLOGY_NONE:
1111 num_connections = 0;
1114 num_connections = 0;
1117 if (num_connections < 1)
1118 return GNUNET_SYSERR;
1120 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
1121 ret = create_and_copy_friend_files(pg);
1122 if (ret == GNUNET_OK)
1123 connect_topology(pg);
1127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1128 _("Failed during friend file copying!\n"));
1130 return GNUNET_SYSERR;
1135 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1136 _("No topology specified, was one intended?\n"));
1137 return GNUNET_SYSERR;
1140 return num_connections;
1144 * Start count gnunetd processes with the same set of transports and
1145 * applications. The port numbers (any option called "PORT") will be
1146 * adjusted to ensure that no two peers running on the same system
1147 * have the same port(s) in their respective configurations.
1149 * @param sched scheduler to use
1150 * @param cfg configuration template to use
1151 * @param total number of daemons to start
1152 * @param cb function to call on each daemon that was started
1153 * @param cb_cls closure for cb
1154 * @param connect_callback function to call each time two hosts are connected
1155 * @param connect_callback_cls closure for connect_callback
1156 * @param hostnames space-separated list of hostnames to use; can be NULL (to run
1157 * everything on localhost).
1158 * @return NULL on error, otherwise handle to control peer group
1160 struct GNUNET_TESTING_PeerGroup *
1161 GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
1162 const struct GNUNET_CONFIGURATION_Handle *cfg,
1164 GNUNET_TESTING_NotifyDaemonRunning cb,
1166 GNUNET_TESTING_NotifyConnection
1167 connect_callback, void *connect_callback_cls,
1168 const char *hostnames)
1170 struct GNUNET_TESTING_PeerGroup *pg;
1174 const char *hostname;
1175 char *baseservicehome;
1176 char *newservicehome;
1178 struct GNUNET_CONFIGURATION_Handle *pcfg;
1180 unsigned int hostcnt;
1189 pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
1193 pg->cb_cls = cb_cls;
1194 pg->notify_connection = connect_callback;
1195 pg->notify_connection_cls = connect_callback_cls;
1197 pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
1198 if (NULL != hostnames)
1201 /* skip leading spaces */
1202 while ((0 != *hostnames) && (isspace (*hostnames)))
1205 while ('\0' != *rpos)
1207 if (isspace (*rpos))
1211 pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
1213 start = GNUNET_strdup (hostnames);
1215 while ('\0' != *pos)
1220 if (strlen (start) > 0)
1222 pg->hosts[off].minport = LOW_PORT;
1223 pg->hosts[off++].hostname = start;
1229 if (strlen (start) > 0)
1231 pg->hosts[off].minport = LOW_PORT;
1232 pg->hosts[off++].hostname = start;
1236 GNUNET_free (start);
1237 GNUNET_free (pg->hosts);
1241 minport = 0; /* make gcc happy */
1248 for (off = 0; off < total; off++)
1252 hostname = pg->hosts[off % hostcnt].hostname;
1253 pcfg = make_config (cfg, &pg->hosts[off % hostcnt].minport);
1258 pcfg = make_config (cfg, &minport);
1262 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1264 ("Could not create configuration for peer number %u on `%s'!\n"),
1265 off, hostname == NULL ? "localhost" : hostname);
1270 GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME",
1273 GNUNET_asprintf (&newservicehome,
1274 "%s/%d/", baseservicehome, off);
1275 GNUNET_free (baseservicehome);
1279 tmpdir = getenv ("TMPDIR");
1280 tmpdir = tmpdir ? tmpdir : "/tmp";
1281 GNUNET_asprintf (&newservicehome,
1284 "gnunet-testing-test-test", off);
1286 GNUNET_CONFIGURATION_set_value_string (pcfg,
1288 "SERVICEHOME", newservicehome);
1289 GNUNET_free (newservicehome);
1290 pg->peers[off].cfg = pcfg;
1291 pg->peers[off].daemon = GNUNET_TESTING_daemon_start (sched,
1295 if (NULL == pg->peers[off].daemon)
1296 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1297 _("Could not start peer number %u!\n"), off);
1303 * Get a daemon by number, so callers don't have to do nasty
1304 * offsetting operation.
1306 struct GNUNET_TESTING_Daemon *
1307 GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position)
1309 if (position < pg->total)
1310 return pg->peers[position].daemon;
1316 * Shutdown all peers started in the given group.
1318 * @param pg handle to the peer group
1321 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg)
1324 struct PeerConnection *pos;
1325 struct PeerConnection *next;
1327 for (off = 0; off < pg->total; off++)
1329 /* FIXME: should we wait for our
1330 continuations to be called here? This
1331 would require us to take a continuation
1334 if (NULL != pg->peers[off].daemon)
1335 GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, NULL, NULL);
1336 if (NULL != pg->peers[off].cfg)
1337 GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
1339 pos = pg->peers[off].connected_peers;
1348 GNUNET_free (pg->peers);
1349 if (NULL != pg->hosts)
1351 GNUNET_free (pg->hosts[0].hostname);
1352 GNUNET_free (pg->hosts);
1358 /* end of testing_group.c */