diff options
author | Bertrand Marc <beberking@gmail.com> | 2012-05-02 21:43:37 +0200 |
---|---|---|
committer | Bertrand Marc <beberking@gmail.com> | 2012-05-02 21:43:37 +0200 |
commit | 2b81464a43485fcc8ce079fafdee7b7a171835f4 (patch) | |
tree | 394774c0f735199b57d51a2d3840356317853fe1 /src/testing/testing_group.c |
Imported Upstream version 0.9.2upstream/0.9.2
Diffstat (limited to 'src/testing/testing_group.c')
-rw-r--r-- | src/testing/testing_group.c | 7170 |
1 files changed, 7170 insertions, 0 deletions
diff --git a/src/testing/testing_group.c b/src/testing/testing_group.c new file mode 100644 index 0000000..2d0e9ef --- /dev/null +++ b/src/testing/testing_group.c @@ -0,0 +1,7170 @@ +/* + This file is part of GNUnet + (C) 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file testing/testing_group.c + * @brief convenience API for writing testcases for GNUnet + * @author Nathan Evans + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_arm_service.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" + +#define VERBOSE_TESTING GNUNET_NO + +#define VERBOSE_TOPOLOGY GNUNET_NO + +#define DEBUG_CHURN GNUNET_EXTRA_LOGGING + +#define USE_START_HELPER GNUNET_YES + +#define OLD 1 + +/* Before connecting peers, send all of the HELLOs */ +#define USE_SEND_HELLOS GNUNET_NO + +#define TOPOLOGY_HACK GNUNET_YES + + +/** + * Lowest port used for GNUnet testing. Should be high enough to not + * conflict with other applications running on the hosts but be low + * enough to not conflict with client-ports (typically starting around + * 32k). + */ +#define LOW_PORT 12000 + +/** + * Highest port used for GNUnet testing. Should be low enough to not + * conflict with the port range for "local" ports (client apps; see + * /proc/sys/net/ipv4/ip_local_port_range on Linux for example). + */ +#define HIGH_PORT 56000 + +/* Maximum time to delay connect attempt */ +#define MAX_CONNECT_DELAY 300 + +/** + * Which list of peers do we need to modify? + */ +enum PeerLists +{ + /** Modify allowed peers */ + ALLOWED, + + /** Modify connect peers */ + CONNECT, + + /** Modify blacklist peers */ + BLACKLIST, + + /** Modify workingset peers */ + WORKING_SET +}; + +/** + * Prototype of a function called whenever two peers would be connected + * in a certain topology. + */ +typedef unsigned int (*GNUNET_TESTING_ConnectionProcessor) (struct + GNUNET_TESTING_PeerGroup + * pg, + unsigned int first, + unsigned int second, + enum PeerLists list, + unsigned int check); + +/** + * Context for handling churning a peer group + */ +struct ChurnContext +{ + /** + * The peergroup we are dealing with. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * Name of the service to churn on/off, NULL + * to churn entire peer. + */ + char *service; + + /** + * Callback used to notify of churning finished + */ + GNUNET_TESTING_NotifyCompletion cb; + + /** + * Closure for callback + */ + void *cb_cls; + + /** + * Number of peers that still need to be started + */ + unsigned int num_to_start; + + /** + * Number of peers that still need to be stopped + */ + unsigned int num_to_stop; + + /** + * Number of peers that failed to start + */ + unsigned int num_failed_start; + + /** + * Number of peers that failed to stop + */ + unsigned int num_failed_stop; +}; + +struct RestartContext +{ + /** + * The group of peers being restarted + */ + struct GNUNET_TESTING_PeerGroup *peer_group; + + /** + * How many peers have been restarted thus far + */ + unsigned int peers_restarted; + + /** + * How many peers got an error when restarting + */ + unsigned int peers_restart_failed; + + /** + * The function to call once all peers have been restarted + */ + GNUNET_TESTING_NotifyCompletion callback; + + /** + * Closure for callback function + */ + void *callback_cls; + +}; + +struct SendHelloContext +{ + /** + * Global handle to the peer group. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * The data about this specific peer. + */ + struct PeerData *peer; + + /** + * The next HELLO that needs sent to this peer. + */ + struct PeerConnection *peer_pos; + + /** + * Are we connected to CORE yet? + */ + unsigned int core_ready; + + /** + * How many attempts should we make for failed connections? + */ + unsigned int connect_attempts; + + /** + * Task for scheduling core connect requests to be sent. + */ + GNUNET_SCHEDULER_TaskIdentifier core_connect_task; +}; + +struct ShutdownContext +{ + struct GNUNET_TESTING_PeerGroup *pg; + /** + * Total peers to wait for + */ + unsigned int total_peers; + + /** + * Number of peers successfully shut down + */ + unsigned int peers_down; + + /** + * Number of peers failed to shut down + */ + unsigned int peers_failed; + + /** + * Number of peers we have started shutting + * down. If too many, wait on them. + */ + unsigned int outstanding; + + /** + * Timeout for shutdown. + */ + struct GNUNET_TIME_Relative timeout; + + /** + * Callback to call when all peers either + * shutdown or failed to shutdown + */ + GNUNET_TESTING_NotifyCompletion cb; + + /** + * Closure for cb + */ + void *cb_cls; + + /** + * Should we delete all of the files from the peers? + */ + int delete_files; +}; + +/** + * Individual shutdown context for a particular peer. + */ +struct PeerShutdownContext +{ + /** + * Pointer to the high level shutdown context. + */ + struct ShutdownContext *shutdown_ctx; + + /** + * The daemon handle for the peer to shut down. + */ + struct GNUNET_TESTING_Daemon *daemon; +}; + +/** + * Individual shutdown context for a particular peer. + */ +struct PeerRestartContext +{ + /** + * Pointer to the high level restart context. + */ + struct ChurnRestartContext *churn_restart_ctx; + + /** + * The daemon handle for the peer to shut down. + */ + struct GNUNET_TESTING_Daemon *daemon; +}; + +struct ServiceStartContext +{ + struct GNUNET_TESTING_PeerGroup *pg; + unsigned int remaining; + GNUNET_TESTING_NotifyCompletion cb; + unsigned int outstanding; + char *service; + struct GNUNET_TIME_Relative timeout; + void *cb_cls; +}; + +/** + * Individual shutdown context for a particular peer. + */ +struct PeerServiceStartContext +{ + /** + * Pointer to the high level start context. + */ + struct ServiceStartContext *start_ctx; + + /** + * The daemon handle for the peer to start the service on. + */ + struct GNUNET_TESTING_Daemon *daemon; +}; + +struct CreateTopologyContext +{ + + /** + * Function to call with number of connections + */ + GNUNET_TESTING_NotifyConnections cont; + + /** + * Closure for connection notification + */ + void *cls; +}; + +enum States +{ + /** Waiting to read number of peers */ + NUM_PEERS, + + /** Should find next peer index */ + PEER_INDEX, + + /** Should find colon */ + COLON, + + /** Should read other peer index, space, or endline */ + OTHER_PEER_INDEX +}; + +#if OLD +struct PeerConnection +{ + /** + * Doubly Linked list + */ + struct PeerConnection *prev; + + /* + * Doubly Linked list + */ + struct PeerConnection *next; + + /* + * Index of daemon in pg->peers + */ + uint32_t index; + +}; +#endif + +struct InternalStartContext +{ + /** + * Pointer to peerdata + */ + struct PeerData *peer; + + /** + * Timeout for peer startup + */ + struct GNUNET_TIME_Relative timeout; + + /** + * Client callback for hostkey notification + */ + GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback; + + /** + * Closure for hostkey_callback + */ + void *hostkey_cls; + + /** + * Client callback for peer start notification + */ + GNUNET_TESTING_NotifyDaemonRunning start_cb; + + /** + * Closure for cb + */ + void *start_cb_cls; + + /** + * Hostname, where to start the peer + */ + const char *hostname; + + /** + * Username to use when connecting to the + * host via ssh. + */ + const char *username; + + /** + * Pointer to starting memory location of a hostkey + */ + const char *hostkey; + + /** + * Port to use for ssh. + */ + uint16_t sshport; + +}; + +struct ChurnRestartContext +{ + /** + * PeerGroup that we are working with. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * Number of restarts currently in flight. + */ + unsigned int outstanding; + + /** + * Handle to the underlying churn context. + */ + struct ChurnContext *churn_ctx; + + /** + * How long to allow the operation to take. + */ + struct GNUNET_TIME_Relative timeout; +}; + +struct OutstandingSSH +{ + struct OutstandingSSH *next; + + struct OutstandingSSH *prev; + + /** + * Number of current ssh connections. + */ + uint32_t outstanding; + + /** + * The hostname of this peer. + */ + const char *hostname; +}; + +/** + * Data we keep per peer. + */ +struct PeerData +{ + /** + * (Initial) configuration of the host. + * (initial because clients could change + * it and we would not know about those + * updates). + */ + struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Handle for controlling the daemon. + */ + struct GNUNET_TESTING_Daemon *daemon; + + /** + * The peergroup this peer belongs to. + */ + struct GNUNET_TESTING_PeerGroup *pg; + +#if OLD + /** + * Linked list of allowed peer connections. + */ + struct PeerConnection *allowed_peers_head; + + /** + * Linked list of allowed peer connections. + */ + struct PeerConnection *allowed_peers_tail; + + /** + * Linked list of blacklisted peer connections. + */ + struct PeerConnection *blacklisted_peers_head; + + /** + * Linked list of blacklisted peer connections. + */ + struct PeerConnection *blacklisted_peers_tail; + + /** + * Linked list of connect peer connections. + */ + struct PeerConnection *connect_peers_head; + + /** + * Linked list of connect peer connections. + */ + struct PeerConnection *connect_peers_tail; + + /** + * Linked list of connect peer connections. + */ + struct PeerConnection *connect_peers_working_set_head; + + /** + * Linked list of connect peer connections. + */ + struct PeerConnection *connect_peers_working_set_tail; + +#else + /** + * Hash map of allowed peer connections (F2F created topology) + */ + struct GNUNET_CONTAINER_MultiHashMap *allowed_peers; + + /** + * Hash map of blacklisted peers + */ + struct GNUNET_CONTAINER_MultiHashMap *blacklisted_peers; + + /** + * Hash map of peer connections + */ + struct GNUNET_CONTAINER_MultiHashMap *connect_peers; + + /** + * Temporary hash map of peer connections + */ + struct GNUNET_CONTAINER_MultiHashMap *connect_peers_working_set; +#endif + + /** + * Temporary variable for topology creation, should be reset before + * creating any topology so the count is valid once finished. + */ + int num_connections; + + /** + * Context to keep track of peers being started, to + * stagger hostkey generation and peer startup. + */ + struct InternalStartContext internal_context; + + /** + * Task ID for the queued internal_continue_startup task + */ + GNUNET_SCHEDULER_TaskIdentifier startup_task; + +}; + +/** + * Linked list of per-host data. + */ +struct HostData +{ + /** + * Name of the host. + */ + char *hostname; + + /** + * SSH username to use when connecting to this host. + */ + char *username; + + /** + * SSH port to use when connecting to this host. + */ + uint16_t sshport; + + /** + * Lowest port that we have not yet used + * for GNUnet. + */ + uint16_t minport; +}; + +struct TopologyIterateContext +{ + /** + * The peergroup we are working with. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * Callback for notifying of two connected peers. + */ + GNUNET_TESTING_NotifyTopology topology_cb; + + /** + * Closure for topology_cb + */ + void *cls; + + /** + * Number of peers currently connected to. + */ + unsigned int connected; + + /** + * Number of peers we have finished iterating. + */ + unsigned int completed; + + /** + * Number of peers total. + */ + unsigned int total; +}; + +struct StatsIterateContext +{ + /** + * The peergroup that we are dealing with. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * Continuation to call once all stats information has been retrieved. + */ + GNUNET_STATISTICS_Callback cont; + + /** + * Proc function to call on each value received. + */ + GNUNET_TESTING_STATISTICS_Iterator proc; + + /** + * Closure for topology_cb + */ + void *cls; + + /** + * Number of peers currently connected to. + */ + unsigned int connected; + + /** + * Number of peers we have finished iterating. + */ + unsigned int completed; + + /** + * Number of peers total. + */ + unsigned int total; +}; + +struct CoreContext +{ + void *iter_context; + struct GNUNET_TESTING_Daemon *daemon; +}; + +struct StatsCoreContext +{ + void *iter_context; + struct GNUNET_TESTING_Daemon *daemon; + /** + * Handle to the statistics service. + */ + struct GNUNET_STATISTICS_Handle *stats_handle; + + /** + * Handle for getting statistics. + */ + struct GNUNET_STATISTICS_GetHandle *stats_get_handle; +}; + +struct ConnectTopologyContext +{ + /** + * How many connections are left to create. + */ + unsigned int remaining_connections; + + /** + * Handle to group of peers. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * How long to try this connection before timing out. + */ + struct GNUNET_TIME_Relative connect_timeout; + + /** + * How many times to retry connecting the two peers. + */ + unsigned int connect_attempts; + + /** + * Temp value set for each iteration. + */ + //struct PeerData *first; + + /** + * Notification that all peers are connected. + */ + GNUNET_TESTING_NotifyCompletion notify_connections_done; + + /** + * Closure for notify. + */ + void *notify_cls; +}; + +struct ConnectContext; + +/** + * Handle to a group of GNUnet peers. + */ +struct GNUNET_TESTING_PeerGroup +{ + /** + * Configuration template. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + struct ConnectContext *cc_head; + + struct ConnectContext *cc_tail; + + /** + * Function to call on each started daemon. + */ + //GNUNET_TESTING_NotifyDaemonRunning cb; + + /** + * Closure for cb. + */ + //void *cb_cls; + + /* + * Function to call on each topology connection created + */ + GNUNET_TESTING_NotifyConnection notify_connection; + + /* + * Callback for notify_connection + */ + void *notify_connection_cls; + + /** + * Array of information about hosts. + */ + struct HostData *hosts; + + /** + * Number of hosts (size of HostData) + */ + unsigned int num_hosts; + + /** + * Array of "total" peers. + */ + struct PeerData *peers; + + /** + * Number of peers in this group. + */ + unsigned int total; + + /** + * At what time should we fail the peer startup process? + */ + struct GNUNET_TIME_Absolute max_timeout; + + /** + * How many peers are being started right now? + */ + unsigned int starting; + + /** + * How many peers have already been started? + */ + unsigned int started; + + /** + * Number of possible connections to peers + * at a time. + */ + unsigned int max_outstanding_connections; + + /** + * Number of ssh connections to peers (max). + */ + unsigned int max_concurrent_ssh; + + /** + * Number of connects we are waiting on, allows us to rate limit + * connect attempts. + */ + unsigned int outstanding_connects; + + /** + * Number of HELLOs we have yet to send. + */ + unsigned int remaining_hellos; + + /** + * How many connects have already been scheduled? + */ + unsigned int total_connects_scheduled; + + /** + * Hostkeys loaded from a file. + */ + char *hostkey_data; + + /** + * Head of DLL to keep track of the number of outstanding + * ssh connections per peer. + */ + struct OutstandingSSH *ssh_head; + + /** + * Tail of DLL to keep track of the number of outstanding + * ssh connections per peer. + */ + struct OutstandingSSH *ssh_tail; + + /** + * Stop scheduling peers connecting. + */ + unsigned int stop_connects; + + /** + * Connection context for peer group. + */ + struct ConnectTopologyContext ct_ctx; +}; + +struct UpdateContext +{ + /** + * The altered configuration. + */ + struct GNUNET_CONFIGURATION_Handle *ret; + + /** + * The original configuration to alter. + */ + const struct GNUNET_CONFIGURATION_Handle *orig; + + /** + * The hostname that this peer will run on. + */ + const char *hostname; + + /** + * The next possible port to assign. + */ + unsigned int nport; + + /** + * Unique number for unix domain sockets. + */ + unsigned int upnum; + + /** + * Unique number for this peer/host to offset + * things that are grouped by host. + */ + unsigned int fdnum; +}; + +struct ConnectContext +{ + + struct ConnectContext *next; + + struct ConnectContext *prev; + + /** + * Index of peer to connect second to. + */ + uint32_t first_index; + + /** + * Index of peer to connect first to. + */ + uint32_t second_index; + + /** + * Task associated with the attempt to connect. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * Context in 'testing.c', to cancel connection attempt. + */ + struct GNUNET_TESTING_ConnectContext *cc; + + /** + * Higher level topology connection context. + */ + struct ConnectTopologyContext *ct_ctx; + + /** + * Whether this connection has been accounted for in the schedule_connect call. + */ + int counted; +}; + +struct UnblacklistContext +{ + /** + * The peergroup + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * uid of the first peer + */ + uint32_t first_uid; +}; + +struct RandomContext +{ + /** + * The peergroup + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * uid of the first peer + */ + uint32_t first_uid; + + /** + * Peer data for first peer. + */ + struct PeerData *first; + + /** + * Random percentage to use + */ + double percentage; +}; + +struct MinimumContext +{ + /** + * The peergroup + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * uid of the first peer + */ + uint32_t first_uid; + + /** + * Peer data for first peer. + */ + struct PeerData *first; + + /** + * Number of conns per peer + */ + unsigned int num_to_add; + + /** + * Permuted array of all possible connections. Only add the Nth + * peer if it's in the Nth position. + */ + unsigned int *pg_array; + + /** + * What number is the current element we are iterating over? + */ + unsigned int current; +}; + +struct DFSContext +{ + /** + * The peergroup + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * uid of the first peer + */ + uint32_t first_uid; + + /** + * uid of the second peer + */ + uint32_t second_uid; + + /** + * Peer data for first peer. + */ + struct PeerData *first; + + /** + * Which peer has been chosen as the one to add? + */ + unsigned int chosen; + + /** + * What number is the current element we are iterating over? + */ + unsigned int current; +}; + +/** + * Simple struct to keep track of progress, and print a + * nice little percentage meter for long running tasks. + */ +struct ProgressMeter +{ + unsigned int total; + + unsigned int modnum; + + unsigned int dotnum; + + unsigned int completed; + + int print; + + char *startup_string; +}; + +#if !OLD +/** + * Convert unique ID to hash code. + * + * @param uid unique ID to convert + * @param hash set to uid (extended with zeros) + */ +static void +hash_from_uid (uint32_t uid, GNUNET_HashCode * hash) +{ + memset (hash, 0, sizeof (GNUNET_HashCode)); + *((uint32_t *) hash) = uid; +} + +/** + * Convert hash code to unique ID. + * + * @param uid unique ID to convert + * @param hash set to uid (extended with zeros) + */ +static void +uid_from_hash (const GNUNET_HashCode * hash, uint32_t * uid) +{ + memcpy (uid, hash, sizeof (uint32_t)); +} +#endif + +#if USE_SEND_HELLOS +static struct GNUNET_CORE_MessageHandler no_handlers[] = { + {NULL, 0, 0} +}; +#endif + +/** + * Create a meter to keep track of the progress of some task. + * + * @param total the total number of items to complete + * @param start_string a string to prefix the meter with (if printing) + * @param print GNUNET_YES to print the meter, GNUNET_NO to count + * internally only + * + * @return the progress meter + */ +static struct ProgressMeter * +create_meter (unsigned int total, char *start_string, int print) +{ + struct ProgressMeter *ret; + + ret = GNUNET_malloc (sizeof (struct ProgressMeter)); + ret->print = print; + ret->total = total; + ret->modnum = total / 4; + if (ret->modnum == 0) /* Divide by zero check */ + ret->modnum = 1; + ret->dotnum = (total / 50) + 1; + if (start_string != NULL) + ret->startup_string = GNUNET_strdup (start_string); + else + ret->startup_string = GNUNET_strdup (""); + + return ret; +} + +/** + * Update progress meter (increment by one). + * + * @param meter the meter to update and print info for + * + * @return GNUNET_YES if called the total requested, + * GNUNET_NO if more items expected + */ +static int +update_meter (struct ProgressMeter *meter) +{ + if (meter->print == GNUNET_YES) + { + if (meter->completed % meter->modnum == 0) + { + if (meter->completed == 0) + { + FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string); + } + else + FPRINTF (stdout, "%d%%", + (int) (((float) meter->completed / meter->total) * 100)); + } + else if (meter->completed % meter->dotnum == 0) + FPRINTF (stdout, "%s", "."); + + if (meter->completed + 1 == meter->total) + FPRINTF (stdout, "%d%%]\n", 100); + fflush (stdout); + } + meter->completed++; + + if (meter->completed == meter->total) + return GNUNET_YES; + if (meter->completed > meter->total) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Progress meter overflow!!\n"); + return GNUNET_NO; +} + +/** + * Reset progress meter. + * + * @param meter the meter to reset + * + * @return GNUNET_YES if meter reset, + * GNUNET_SYSERR on error + */ +static int +reset_meter (struct ProgressMeter *meter) +{ + if (meter == NULL) + return GNUNET_SYSERR; + + meter->completed = 0; + return GNUNET_YES; +} + +/** + * Release resources for meter + * + * @param meter the meter to free + */ +static void +free_meter (struct ProgressMeter *meter) +{ + GNUNET_free_non_null (meter->startup_string); + GNUNET_free (meter); +} + +/** + * Get a topology from a string input. + * + * @param topology where to write the retrieved topology + * @param topology_string The string to attempt to + * get a configuration value from + * @return GNUNET_YES if topology string matched a + * known topology, GNUNET_NO if not + */ +int +GNUNET_TESTING_topology_get (enum GNUNET_TESTING_Topology *topology, + const char *topology_string) +{ + /** + * Strings representing topologies in enum + */ + static const char *topology_strings[] = { + /** + * A clique (everyone connected to everyone else). + */ + "CLIQUE", + + /** + * Small-world network (2d torus plus random links). + */ + "SMALL_WORLD", + + /** + * Small-world network (ring plus random links). + */ + "SMALL_WORLD_RING", + + /** + * Ring topology. + */ + "RING", + + /** + * 2-d torus. + */ + "2D_TORUS", + + /** + * Random graph. + */ + "ERDOS_RENYI", + + /** + * Certain percentage of peers are unable to communicate directly + * replicating NAT conditions + */ + "INTERNAT", + + /** + * Scale free topology. + */ + "SCALE_FREE", + + /** + * Straight line topology. + */ + "LINE", + + /** + * All peers are disconnected. + */ + "NONE", + + /** + * Read the topology from a file. + */ + "FROM_FILE", + + NULL + }; + + int curr = 0; + + if (topology_string == NULL) + return GNUNET_NO; + while (topology_strings[curr] != NULL) + { + if (strcasecmp (topology_strings[curr], topology_string) == 0) + { + *topology = curr; + return GNUNET_YES; + } + curr++; + } + *topology = GNUNET_TESTING_TOPOLOGY_NONE; + return GNUNET_NO; +} + +/** + * Get connect topology option from string input. + * + * @param topology_option where to write the retrieved topology + * @param topology_string The string to attempt to + * get a configuration value from + * @return GNUNET_YES if string matched a known + * topology option, GNUNET_NO if not + */ +int +GNUNET_TESTING_topology_option_get (enum GNUNET_TESTING_TopologyOption + *topology_option, + const char *topology_string) +{ + /** + * Options for connecting a topology as strings. + */ + static const char *topology_option_strings[] = { + /** + * Try to connect all peers specified in the topology. + */ + "CONNECT_ALL", + + /** + * Choose a random subset of connections to create. + */ + "CONNECT_RANDOM_SUBSET", + + /** + * Create at least X connections for each peer. + */ + "CONNECT_MINIMUM", + + /** + * Using a depth first search, create one connection + * per peer. If any are missed (graph disconnected) + * start over at those peers until all have at least one + * connection. + */ + "CONNECT_DFS", + + /** + * Find the N closest peers to each allowed peer in the + * topology and make sure a connection to those peers + * exists in the connect topology. + */ + "CONNECT_CLOSEST", + + /** + * No options specified. + */ + "CONNECT_NONE", + + NULL + }; + int curr = 0; + + if (topology_string == NULL) + return GNUNET_NO; + while (NULL != topology_option_strings[curr]) + { + if (strcasecmp (topology_option_strings[curr], topology_string) == 0) + { + *topology_option = curr; + return GNUNET_YES; + } + curr++; + } + *topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_NONE; + return GNUNET_NO; +} + +/** + * Function to iterate over options. Copies + * the options to the target configuration, + * updating PORT values as needed. + * + * @param cls closure + * @param section name of the section + * @param option name of the option + * @param value value of the option + */ +static void +update_config (void *cls, const char *section, const char *option, + const char *value) +{ + struct UpdateContext *ctx = cls; + unsigned int ival; + char cval[12]; + char uval[128]; + char *single_variable; + char *per_host_variable; + unsigned long long num_per_host; + + GNUNET_asprintf (&single_variable, "single_%s_per_host", section); + GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section); + + if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival))) + { + if ((ival != 0) && + (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", + single_variable))) + { + GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++); + value = cval; + } + else if ((ival != 0) && + (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", + single_variable)) && + GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing", + per_host_variable, + &num_per_host)) + { + GNUNET_snprintf (cval, sizeof (cval), "%u", + ival + ctx->fdnum % num_per_host); + value = cval; + } + + /* FIXME: REMOVE FOREVER HACK HACK HACK */ + if (0 == strcasecmp (section, "transport-tcp")) + GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, + |