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 CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 180)
54 struct PeerConnection *next;
57 * Pointer to daemon handle
59 struct GNUNET_TESTING_Daemon *daemon;
64 * Data we keep per peer.
69 * (Initial) configuration of the host.
70 * (initial because clients could change
71 * it and we would not know about those
74 struct GNUNET_CONFIGURATION_Handle *cfg;
77 * Handle for controlling the daemon.
79 struct GNUNET_TESTING_Daemon *daemon;
82 * Linked list of peer connections (simply indexes of PeerGroup)
83 * FIXME: Question, store pointer or integer? Pointer for now...
85 struct PeerConnection *connected_peers;
90 * Data we keep per host.
100 * Lowest port that we have not yet used
108 * Handle to a group of GNUnet peers.
110 struct GNUNET_TESTING_PeerGroup
115 struct GNUNET_SCHEDULER_Handle *sched;
118 * Configuration template.
120 const struct GNUNET_CONFIGURATION_Handle *cfg;
123 * Function to call on each started daemon.
125 GNUNET_TESTING_NotifyDaemonRunning cb;
133 * Function to call on each topology connection created
135 GNUNET_TESTING_NotifyConnection notify_connection;
138 * Callback for notify_connection
140 void *notify_connection_cls;
143 * NULL-terminated array of information about
146 struct HostData *hosts;
149 * Array of "total" peers.
151 struct PeerData *peers;
154 * Number of peers in this group.
163 struct GNUNET_CONFIGURATION_Handle *ret;
168 * Function to iterate over options. Copies
169 * the options to the target configuration,
170 * updating PORT values as needed.
173 * @param section name of the section
174 * @param option name of the option
175 * @param value value of the option
178 update_config (void *cls,
179 const char *section, const char *option, const char *value)
181 struct UpdateContext *ctx = cls;
185 if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival)))
187 GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++);
190 GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value);
195 * Create a new configuration using the given configuration
196 * as a template; however, each PORT in the existing cfg
197 * must be renumbered by incrementing "*port". If we run
198 * out of "*port" numbers, return NULL.
200 * @param cfg template configuration
201 * @param port port numbers to use, update to reflect
202 * port numbers that were used
203 * @return new configuration, NULL on error
205 static struct GNUNET_CONFIGURATION_Handle *
206 make_config (const struct GNUNET_CONFIGURATION_Handle *cfg, uint16_t * port)
208 struct UpdateContext uc;
213 uc.ret = GNUNET_CONFIGURATION_create ();
214 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
215 if (uc.nport >= HIGH_PORT)
218 GNUNET_CONFIGURATION_destroy (uc.ret);
221 *port = (uint16_t) uc.nport;
226 * Add entries to the peers connected list
228 * @param pg the peer group we are working with
229 * @param first index of the first peer
230 * @param second index of the second peer
232 * @return the number of connections added (can be 0, 1 or 2)
234 * FIXME: add both, or only add one?
235 * - if both are added, then we have to keep track
236 * when connecting so we don't double connect
237 * - if only one is added, we need to iterate over
238 * both lists to find out if connection already exists
239 * - having both allows the whitelisting/friend file
240 * creation to be easier
242 * -- For now, add both, we have to iterate over each to
243 * check for duplicates anyways, so we'll take the performance
244 * hit assuming we don't have __too__ many connections
248 add_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
251 struct PeerConnection *first_iter;
252 struct PeerConnection *second_iter;
255 struct PeerConnection *new_first;
256 struct PeerConnection *new_second;
258 first_iter = pg->peers[first].connected_peers;
259 add_first = GNUNET_YES;
260 while (first_iter != NULL)
262 if (first_iter->daemon == pg->peers[second].daemon)
263 add_first = GNUNET_NO;
264 first_iter = first_iter->next;
267 second_iter = pg->peers[second].connected_peers;
268 add_second = GNUNET_YES;
269 while (second_iter != NULL)
271 if (second_iter->daemon == pg->peers[first].daemon)
272 add_second = GNUNET_NO;
273 second_iter = second_iter->next;
279 new_first = GNUNET_malloc(sizeof(struct PeerConnection));
280 new_first->daemon = pg->peers[second].daemon;
281 new_first->next = pg->peers[first].connected_peers;
282 pg->peers[first].connected_peers = new_first;
288 new_second = GNUNET_malloc(sizeof(struct PeerConnection));
289 new_second->daemon = pg->peers[first].daemon;
290 new_second->next = pg->peers[second].connected_peers;
291 pg->peers[second].connected_peers = new_second;
299 create_small_world_ring(struct GNUNET_TESTING_PeerGroup *pg)
304 unsigned int randomPeer;
305 double random, logNModifier, percentage;
306 unsigned int smallWorldConnections;
312 int connect_attempts;
314 logNModifier = 0.5; /* FIXME: default value? */
315 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
320 if (sscanf(p_string, "%lf", &logNModifier) != 1)
321 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
322 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
326 GNUNET_free (p_string);
328 percentage = 0.5; /* FIXME: default percentage? */
329 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
334 if (sscanf(p_string, "%lf", &percentage) != 1)
335 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
336 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
340 GNUNET_free (p_string);
342 natLog = log (pg->total);
343 connsPerPeer = ceil (natLog * logNModifier);
345 if (connsPerPeer % 2 == 1)
348 smallWorldConnections = 0;
349 connect_attempts = 0;
350 for (i = 0; i < pg->total; i++)
353 max = i + connsPerPeer / 2;
354 min = i - connsPerPeer / 2;
356 if (max > pg->total - 1)
358 max = max - pg->total;
364 min = pg->total - 1 + min;
368 for (j = 0; j < connsPerPeer / 2; j++)
370 random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
371 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
372 if (random < percentage)
374 /* Connect to uniformly selected random peer */
376 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
378 while ((((randomPeer < max) && (randomPeer > min))
379 && (useAnd == 0)) || (((randomPeer > min)
380 || (randomPeer < max))
384 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
387 smallWorldConnections +=
388 add_connections (pg, i, randomPeer);
392 nodeToConnect = i + j + 1;
393 if (nodeToConnect > pg->total - 1)
395 nodeToConnect = nodeToConnect - pg->total;
398 add_connections (pg, i, nodeToConnect);
404 connect_attempts += smallWorldConnections;
406 return connect_attempts;
411 create_nated_internet (struct GNUNET_TESTING_PeerGroup *pg)
413 unsigned int outer_count, inner_count;
415 int connect_attempts;
416 double nat_percentage;
419 nat_percentage = 0.6; /* FIXME: default percentage? */
420 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
425 if (sscanf(p_string, "%lf", &nat_percentage) != 1)
426 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
427 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
431 GNUNET_free (p_string);
436 cutoff = (unsigned int) (nat_percentage * pg->total);
438 connect_attempts = 0;
440 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
442 for (inner_count = outer_count + 1; inner_count < pg->total;
445 if ((outer_count > cutoff) || (inner_count > cutoff))
448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
449 "Connecting peer %d to peer %d\n",
450 outer_count, inner_count);
452 connect_attempts += add_connections(pg, outer_count, inner_count);
457 return connect_attempts;
464 create_small_world (struct GNUNET_TESTING_PeerGroup *pg)
466 unsigned int i, j, k;
470 unsigned int toggle = 1;
471 unsigned int nodeToConnect;
473 unsigned int node1Row;
474 unsigned int node1Col;
475 unsigned int node2Row;
476 unsigned int node2Col;
477 unsigned int distance;
478 double probability, random, percentage;
479 unsigned int smallWorldConnections;
481 int connect_attempts;
482 square = floor (sqrt (pg->total));
486 percentage = 0.5; /* FIXME: default percentage? */
487 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
492 if (sscanf(p_string, "%lf", &percentage) != 1)
493 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
494 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
498 GNUNET_free (p_string);
500 probability = 0.5; /* FIXME: default percentage? */
501 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
506 if (sscanf(p_string, "%lf", &probability) != 1)
507 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
508 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
512 GNUNET_free (p_string);
514 if (square * square != pg->total)
516 while (rows * cols < pg->total)
527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
528 _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
532 connect_attempts = 0;
533 /* Rows and columns are all sorted out, now iterate over all nodes and connect each
534 * to the node to its right and above. Once this is over, we'll have our torus!
535 * Special case for the last node (if the rows and columns are not equal), connect
536 * to the first in the row to maintain topology.
538 for (i = 0; i < pg->total; i++)
540 /* First connect to the node to the right */
541 if (((i + 1) % cols != 0) && (i + 1 != pg->total))
542 nodeToConnect = i + 1;
543 else if (i + 1 == pg->total)
544 nodeToConnect = rows * cols - cols;
546 nodeToConnect = i - cols + 1;
548 connect_attempts += add_connections (pg, i, nodeToConnect);
551 nodeToConnect = (rows * cols) - cols + i;
553 nodeToConnect = i - cols;
555 if (nodeToConnect < pg->total)
556 connect_attempts += add_connections (pg, i, nodeToConnect);
558 natLog = log (pg->total);
560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
561 _("natural log of %d is %d, will run %d iterations\n"),
562 pg->total, natLog, (int) (natLog * percentage));
563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Total connections added thus far: %u!\n"), connect_attempts);
565 smallWorldConnections = 0;
566 for (i = 0; i < (int) (natLog * percentage); i++)
568 for (j = 0; j < pg->total; j++)
570 /* Determine the row and column of node at position j on the 2d torus */
572 node1Col = j - (node1Row * cols);
573 for (k = 0; k < pg->total; k++)
575 /* Determine the row and column of node at position k on the 2d torus */
577 node2Col = k - (node2Row * cols);
578 /* Simple Cartesian distance */
579 distance = abs (node1Row - node2Row) + abs (node1Col - node2Col);
582 /* Calculate probability as 1 over the square of the distance */
583 probability = 1.0 / (distance * distance);
584 /* Choose a random value between 0 and 1 */
585 random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
586 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
587 /* If random < probability, then connect the two nodes */
588 if (random < probability)
589 smallWorldConnections += add_connections (pg, j, k);
595 connect_attempts += smallWorldConnections;
597 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
598 _("Total connections added for small world: %d!\n"),
599 smallWorldConnections);
601 return connect_attempts;
607 create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg)
610 unsigned int outer_count;
611 unsigned int inner_count;
612 int connect_attempts;
615 connect_attempts = 0;
617 GNUNET_CONFIGURATION_get_value_string(pg->cfg, "TESTING", "PROBABILITY", &p_string);
618 if ((p_string == NULL) || (sscanf(p_string, "%lf", &probability) != 1))
619 probability = 0.5; /* FIXME: default probability? */
621 GNUNET_free_non_null (p_string);
622 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
624 for (inner_count = outer_count + 1; inner_count < pg->total;
627 temp_rand = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
628 (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
631 _("rand is %f probability is %f\n"), temp_rand,
634 if (temp_rand < probability)
636 connect_attempts += add_connections (pg, outer_count, inner_count);
641 return connect_attempts;
645 create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg)
651 unsigned int toggle = 1;
652 unsigned int nodeToConnect;
653 int connect_attempts;
655 connect_attempts = 0;
657 square = floor (sqrt (pg->total));
661 if (square * square != pg->total)
663 while (rows * cols < pg->total)
674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
675 _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
678 /* Rows and columns are all sorted out, now iterate over all nodes and connect each
679 * to the node to its right and above. Once this is over, we'll have our torus!
680 * Special case for the last node (if the rows and columns are not equal), connect
681 * to the first in the row to maintain topology.
683 for (i = 0; i < pg->total; i++)
685 /* First connect to the node to the right */
686 if (((i + 1) % cols != 0) && (i + 1 != pg->total))
687 nodeToConnect = i + 1;
688 else if (i + 1 == pg->total)
689 nodeToConnect = rows * cols - cols;
691 nodeToConnect = i - cols + 1;
693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
694 "Connecting peer %d to peer %d\n",
697 connect_attempts += add_connections(pg, i, nodeToConnect);
699 /* Second connect to the node immediately above */
701 nodeToConnect = (rows * cols) - cols + i;
703 nodeToConnect = i - cols;
705 if (nodeToConnect < pg->total)
708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
709 "Connecting peer %d to peer %d\n",
712 connect_attempts += add_connections(pg, i, nodeToConnect);
717 return connect_attempts;
723 create_clique (struct GNUNET_TESTING_PeerGroup *pg)
725 unsigned int outer_count;
726 unsigned int inner_count;
727 int connect_attempts;
729 connect_attempts = 0;
731 for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
733 for (inner_count = outer_count + 1; inner_count < pg->total;
737 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
738 "Connecting peer %d to peer %d\n",
739 outer_count, inner_count);
741 connect_attempts += add_connections(pg, outer_count, inner_count);
745 return connect_attempts;
750 create_ring (struct GNUNET_TESTING_PeerGroup *pg)
753 int connect_attempts;
755 connect_attempts = 0;
757 /* Connect each peer to the next highest numbered peer */
758 for (count = 0; count < pg->total - 1; count++)
761 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
762 "Connecting peer %d to peer %d\n",
765 connect_attempts += add_connections(pg, count, count + 1);
768 /* Connect the last peer to the first peer */
769 connect_attempts += add_connections(pg, pg->total - 1, 0);
771 return connect_attempts;
776 * Create the friend files based on the PeerConnection's
777 * of each peer in the peer group, and copy the files
778 * to the appropriate place
780 * @param pg the peer group we are dealing with
783 create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
785 FILE *temp_friend_handle;
786 unsigned int pg_iter;
787 struct PeerConnection *connection_iter;
788 struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
789 char *temp_service_path;
792 struct GNUNET_PeerIdentity *temppeer;
794 enum GNUNET_OS_ProcessStatusType type;
795 unsigned long return_code;
800 pidarr = GNUNET_malloc(sizeof(pid_t) * pg->total);
801 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
803 mytemp = GNUNET_DISK_mktemp("friends");
804 temp_friend_handle = fopen (mytemp, "wt");
805 connection_iter = pg->peers[pg_iter].connected_peers;
806 while (connection_iter != NULL)
808 temppeer = &connection_iter->daemon->id;
809 GNUNET_CRYPTO_hash_to_enc(&temppeer->hashPubKey, &peer_enc);
810 fprintf(temp_friend_handle, "%s\n", (char *)&peer_enc);
811 connection_iter = connection_iter->next;
814 fclose(temp_friend_handle);
817 GNUNET_CONFIGURATION_get_value_string(pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path))
819 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
820 _("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
823 if (UNLINK (mytemp) != 0)
824 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp);
825 GNUNET_free (mytemp);
829 if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
831 GNUNET_asprintf (&arg, "%s/friends", temp_service_path);
832 pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
833 "mv", mytemp, arg, NULL);
835 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
836 _("Copying file with command cp %s %s\n"), mytemp, arg);
841 else /* Remote, scp the file to the correct place */
843 if (NULL != pg->peers[pg_iter].daemon->username)
844 GNUNET_asprintf (&arg, "%s@%s:%s/friends", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path);
846 GNUNET_asprintf (&arg, "%s:%s/friends", pg->peers[pg_iter].daemon->hostname, temp_service_path);
847 pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp",
848 "scp", mytemp, arg, NULL);
851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
852 _("Copying file with command scp %s %s\n"), mytemp, arg);
856 GNUNET_free (temp_service_path);
857 GNUNET_free (mytemp);
862 while ((count < max_wait) && (ret != GNUNET_OK))
865 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
869 _("Checking copy status of file %d\n"), pg_iter);
871 if (pidarr[pg_iter] != 0) /* Check for already completed! */
873 if (GNUNET_OS_process_status(pidarr[pg_iter], &type, &return_code) != GNUNET_OK)
877 else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0))
885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
886 _("File %d copied\n"), pg_iter);
892 if (ret == GNUNET_SYSERR)
905 * Connect the topology as specified by the PeerConnection's
906 * of each peer in the peer group
908 * @param pg the peer group we are dealing with
911 connect_topology (struct GNUNET_TESTING_PeerGroup *pg)
913 unsigned int pg_iter;
914 struct PeerConnection *connection_iter;
918 for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
920 connection_iter = pg->peers[pg_iter].connected_peers;
921 while (connection_iter != NULL)
923 GNUNET_TESTING_daemons_connect (pg->peers[pg_iter].daemon,
924 connection_iter->daemon,
926 pg->notify_connection,
927 pg->notify_connection_cls);
928 connection_iter = connection_iter->next;
930 if (connect_count % 50 == 0)
933 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
934 _("Sleeping to give peers a chance to connect!\n"));
944 * Takes a peer group and attempts to create a topology based on the
945 * one specified in the configuration file. Returns the number of connections
946 * that will attempt to be created, but this will happen asynchronously(?) so
947 * the caller will have to keep track (via the callback) of whether or not
948 * the connection actually happened.
950 * @param pg the peer group struct representing the running peers
952 * @return the number of connections should be created by the topology, so the
953 * caller knows how many to wait for (if it so chooses)
957 GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg)
959 unsigned long long topology_num;
963 GNUNET_assert (pg->notify_connection != NULL);
966 GNUNET_CONFIGURATION_get_value_number (pg->cfg, "testing", "topology",
969 switch (topology_num)
971 case GNUNET_TESTING_TOPOLOGY_CLIQUE:
973 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
974 _("Creating clique topology (may take a bit!)\n"));
976 num_connections = create_clique (pg);
978 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
980 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
981 _("Creating small world (ring) topology (may take a bit!)\n"));
983 num_connections = create_small_world_ring (pg);
985 case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
987 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
988 _("Creating small world (2d-torus) topology (may take a bit!)\n"));
990 num_connections = create_small_world (pg);
992 case GNUNET_TESTING_TOPOLOGY_RING:
994 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
995 _("Creating ring topology (may take a bit!)\n"));
997 num_connections = create_ring (pg);
999 case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
1001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1002 _("Creating 2d torus topology (may take a bit!)\n"));
1004 num_connections = create_2d_torus (pg);
1006 case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
1008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1009 _("Creating Erdos-Renyi topology (may take a bit!)\n"));
1011 num_connections = create_erdos_renyi (pg);
1013 case GNUNET_TESTING_TOPOLOGY_INTERNAT:
1015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1016 _("Creating InterNAT topology (may take a bit!)\n"));
1018 num_connections = create_nated_internet (pg);
1020 case GNUNET_TESTING_TOPOLOGY_NONE:
1021 num_connections = 0;
1024 num_connections = 0;
1027 if (num_connections < 1)
1028 return GNUNET_SYSERR;
1030 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
1031 ret = create_and_copy_friend_files(pg);
1032 if (ret == GNUNET_OK)
1033 connect_topology(pg);
1037 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1038 _("Failed during friend file copying!\n"));
1040 return GNUNET_SYSERR;
1045 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1046 _("No topology specified, was one intended?\n"));
1049 return num_connections;
1053 * Start count gnunetd processes with the same set of transports and
1054 * applications. The port numbers (any option called "PORT") will be
1055 * adjusted to ensure that no two peers running on the same system
1056 * have the same port(s) in their respective configurations.
1058 * @param sched scheduler to use
1059 * @param cfg configuration template to use
1060 * @param total number of daemons to start
1061 * @param cb function to call on each daemon that was started
1062 * @param cb_cls closure for cb
1063 * @param connect_callback function to call each time two hosts are connected
1064 * @param connect_callback_cls closure for connect_callback
1065 * @param hostnames space-separated list of hostnames to use; can be NULL (to run
1066 * everything on localhost).
1067 * @return NULL on error, otherwise handle to control peer group
1069 struct GNUNET_TESTING_PeerGroup *
1070 GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
1071 const struct GNUNET_CONFIGURATION_Handle *cfg,
1073 GNUNET_TESTING_NotifyDaemonRunning cb,
1075 GNUNET_TESTING_NotifyConnection
1076 connect_callback, void *connect_callback_cls,
1077 const char *hostnames)
1079 struct GNUNET_TESTING_PeerGroup *pg;
1083 const char *hostname;
1084 char *baseservicehome;
1085 char *newservicehome;
1087 struct GNUNET_CONFIGURATION_Handle *pcfg;
1089 unsigned int hostcnt;
1097 pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
1101 pg->cb_cls = cb_cls;
1102 pg->notify_connection = connect_callback;
1103 pg->notify_connection_cls = connect_callback_cls;
1105 pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
1106 if (NULL != hostnames)
1109 /* skip leading spaces */
1110 while ((0 != *hostnames) && (isspace (*hostnames)))
1113 while ('\0' != *rpos)
1115 if (isspace (*rpos))
1119 pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
1121 start = GNUNET_strdup (hostnames);
1123 while ('\0' != *pos)
1128 if (strlen (start) > 0)
1130 pg->hosts[off].minport = LOW_PORT;
1131 pg->hosts[off++].hostname = start;
1137 if (strlen (start) > 0)
1139 pg->hosts[off].minport = LOW_PORT;
1140 pg->hosts[off++].hostname = start;
1144 GNUNET_free (start);
1145 GNUNET_free (pg->hosts);
1149 minport = 0; /* make gcc happy */
1156 for (off = 0; off < total; off++)
1160 hostname = pg->hosts[off % hostcnt].hostname;
1161 pcfg = make_config (cfg, &pg->hosts[off % hostcnt].minport);
1166 pcfg = make_config (cfg, &minport);
1170 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1172 ("Could not create configuration for peer number %u on `%s'!\n"),
1173 off, hostname == NULL ? "localhost" : hostname);
1178 GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME",
1181 GNUNET_asprintf (&newservicehome,
1182 "%s/%d/", baseservicehome, off);
1183 GNUNET_free (baseservicehome);
1187 tmpdir = getenv ("TMPDIR");
1188 tmpdir = tmpdir ? tmpdir : "/tmp";
1189 GNUNET_asprintf (&newservicehome,
1192 "gnunet-testing-test-test", off);
1194 GNUNET_CONFIGURATION_set_value_string (pcfg,
1196 "SERVICEHOME", newservicehome);
1197 GNUNET_free (newservicehome);
1198 pg->peers[off].cfg = pcfg;
1199 pg->peers[off].daemon = GNUNET_TESTING_daemon_start (sched,
1203 if (NULL == pg->peers[off].daemon)
1204 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1205 _("Could not start peer number %u!\n"), off);
1211 * Get a daemon by number, so callers don't have to do nasty
1212 * offsetting operation.
1214 struct GNUNET_TESTING_Daemon *
1215 GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position)
1217 if (position < pg->total)
1218 return pg->peers[position].daemon;
1224 * Shutdown all peers started in the given group.
1226 * @param pg handle to the peer group
1229 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg)
1232 struct PeerConnection *pos;
1233 struct PeerConnection *next;
1235 for (off = 0; off < pg->total; off++)
1237 /* FIXME: should we wait for our
1238 continuations to be called here? This
1239 would require us to take a continuation
1242 if (NULL != pg->peers[off].daemon)
1243 GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, NULL, NULL);
1244 if (NULL != pg->peers[off].cfg)
1245 GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
1247 pos = pg->peers[off].connected_peers;
1256 GNUNET_free (pg->peers);
1257 if (NULL != pg->hosts)
1259 GNUNET_free (pg->hosts[0].hostname);
1260 GNUNET_free (pg->hosts);
1266 /* end of testing_group.c */