#define MAX_CONCURRENT_SHUTDOWN 10
-#define CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
+#define CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 200)
-#define CONNECT_ATTEMPTS 8
+#define CONNECT_ATTEMPTS 21
/**
* Prototype of a function called whenever two peers would be connected
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
{
struct ConnectTopologyContext *ct_ctx;
};
+struct UnblacklistContext
+{
+ /**
+ * The peergroup
+ */
+ struct GNUNET_TESTING_PeerGroup *pg;
+
+ /**
+ * uid of the first peer
+ */
+ uint32_t first_uid;
+};
+
/**
* Convert unique ID to hash code.
*
*/
"NONE",
+ /**
+ * Read the topology from a file.
+ */
+ "FROM_FILE",
+
NULL
};
"/tmp/test-service-%s-%u", section, ctx->upnum++);
value = uval;
}
- else if (GNUNET_YES ==
+ else if ((GNUNET_YES ==
GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing",
per_host_variable,
- &num_per_host))
+ &num_per_host)) && (num_per_host > 0))
+
{
GNUNET_snprintf (uval,
sizeof (uval),
/**
* Create a topology given a peer group (set of running peers)
- * and a connection processor.
+ * and a connection processor. Creates a small world topology
+ * according to the rewired ring construction. The basic
+ * behavior is that a ring topology is created, but with some
+ * probability instead of connecting a peer to the next
+ * neighbor in the ring a connection will be created to a peer
+ * selected uniformly at random. We use the TESTING
+ * PERCENTAGE option to specify what number of
+ * connections each peer should have. Default is 2,
+ * which makes the ring, any given number is multiplied by
+ * the log of the network size; i.e. a PERCENTAGE of 2 makes
+ * each peer have on average 2logn connections. The additional
+ * connections are made at increasing distance around the ring
+ * from the original peer, or to random peers based on the re-
+ * wiring probability. The TESTING
+ * PROBABILITY option is used as the probability that a given
+ * connection is rewired.
*
* @param pg the peergroup to create the topology on
* @param proc the connection processor to call to actually set
int nodeToConnect;
unsigned int natLog;
unsigned int randomPeer;
- double random, logNModifier, percentage;
+ double random, logNModifier, probability;
unsigned int smallWorldConnections;
int connsPerPeer;
char *p_string;
logNModifier = 0.5; /* FIXME: default value? */
if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg,
"TESTING",
- "LOGNMODIFIER",
+ "PERCENTAGE",
&p_string))
{
if (sscanf (p_string, "%lf", &logNModifier) != 1)
p_string, "LOGNMODIFIER", "TESTING");
GNUNET_free (p_string);
}
- percentage = 0.5; /* FIXME: default percentage? */
+ probability = 0.5; /* FIXME: default percentage? */
if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg,
"TESTING",
- "PERCENTAGE",
+ "PROBABILITY",
&p_string))
{
- if (sscanf (p_string, "%lf", &percentage) != 1)
+ if (sscanf (p_string, "%lf", &probability) != 1)
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
_
("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
if (connsPerPeer % 2 == 1)
connsPerPeer += 1;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Target is %d connections per peer."), connsPerPeer);
+
smallWorldConnections = 0;
connect_attempts = 0;
for (i = 0; i < pg->total; i++)
((double)
GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
UINT64_MAX) / ((double) UINT64_MAX));
- if (random < percentage)
+ if (random < probability)
{
/* Connect to uniformly selected random peer */
randomPeer =
nat_percentage = 0.6; /* FIXME: default percentage? */
if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg,
"TESTING",
- "NATPERCENTAGE",
+ "PERCENTAGE",
&p_string))
{
if (sscanf (p_string, "%lf", &nat_percentage) != 1)
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
_
("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
- p_string, "NATPERCENTAGE", "TESTING");
+ p_string, "PERCENTAGE", "TESTING");
GNUNET_free (p_string);
}
return connect_attempts;
}
+/**
+ * Iterator over hash map entries.
+ *
+ * @param cls closure the peer group
+ * @param key the key stored in the hashmap is the
+ * index of the peer to connect to
+ * @param value value in the hash map, handle to the peer daemon
+ * @return GNUNET_YES if we should continue to
+ * iterate,
+ * GNUNET_NO if not.
+ */
+static int
+unblacklist_iterator (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct UnblacklistContext *un_ctx = cls;
+ uint32_t second_pos;
+
+ uid_from_hash (key, &second_pos);
+
+ unblacklist_connections(un_ctx->pg, un_ctx->first_uid, second_pos);
+
+ return GNUNET_YES;
+}
+
+/**
+ * Create a blacklist topology based on the allowed topology
+ * which disallows any connections not in the allowed topology
+ * at the transport level.
+ *
+ * @param pg the peergroup to create the topology on
+ * @param proc the connection processor to call to allow
+ * up connections between two peers
+ *
+ * @return the number of connections that were set up
+ *
+ */
+static unsigned int
+copy_allowed (struct GNUNET_TESTING_PeerGroup *pg,
+ GNUNET_TESTING_ConnectionProcessor proc)
+{
+ struct UnblacklistContext un_ctx;
+ unsigned int count;
+ unsigned int total;
+
+ un_ctx.pg = pg;
+ total = 0;
+ for (count = 0; count < pg->total - 1; count++)
+ {
+ un_ctx.first_uid = count;
+ total += GNUNET_CONTAINER_multihashmap_iterate(pg->peers[count].allowed_peers, &unblacklist_iterator, &un_ctx);
+ }
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Unblacklisted %u peers\n", total);
+ return total;
+}
+
/**
* Create a topology given a peer group (set of running peers)
* and a connection processor.
return connect_attempts;
}
+/**
+ * Create a topology given a peer group (set of running peers)
+ * and a connection processor.
+ *
+ * @param pg the peergroup to create the topology on
+ * @param filename the file to read topology information from
+ * @param proc the connection processor to call to actually set
+ * up connections between two peers
+ *
+ * @return the number of connections that were set up
+ *
+ */
+static unsigned int
+create_from_file (struct GNUNET_TESTING_PeerGroup *pg,
+ char *filename,
+ GNUNET_TESTING_ConnectionProcessor proc)
+{
+ int connect_attempts;
+ unsigned int first_peer_index;
+ unsigned int second_peer_index;
+ connect_attempts = 0;
+ struct stat frstat;
+ int count;
+ char *data;
+ char *buf;
+ unsigned int total_peers;
+
+ enum States curr_state;
+
+ if (GNUNET_OK != GNUNET_DISK_file_test (filename))
+ GNUNET_DISK_fn_write (filename, NULL, 0, GNUNET_DISK_PERM_USER_READ
+ | GNUNET_DISK_PERM_USER_WRITE);
+
+ if ((0 != STAT (filename, &frstat)) || (frstat.st_size == 0))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not open file specified for topology!");
+ return connect_attempts;
+ }
+
+ data = GNUNET_malloc_large (frstat.st_size);
+ GNUNET_assert(data != NULL);
+ if (frstat.st_size !=
+ GNUNET_DISK_fn_read (filename, data, frstat.st_size))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not read file %s specified for host list, ending test!", filename);
+ GNUNET_free (data);
+ return connect_attempts;
+ }
+
+ buf = data;
+ count = 0;
+ /* First line should contain a single integer, specifying the number of peers */
+ /* Each subsequent line should contain this format PEER_INDEX:OTHER_PEER_INDEX[,...] */
+ curr_state = NUM_PEERS;
+ while (count < frstat.st_size - 1)
+ {
+ if ((buf[count] == '\n') || (buf[count] == ' '))
+ {
+ count++;
+ continue;
+ }
+
+ switch (curr_state)
+ {
+ case NUM_PEERS:
+ if (1 != sscanf(&buf[count], "%u", &total_peers))
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to read number of peers from topology file!\n");
+ GNUNET_free_non_null(data);
+ return connect_attempts;
+ }
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Read %u total peers in topology\n", total_peers);
+ curr_state = PEER_INDEX;
+ while((buf[count] != '\n') && (count < frstat.st_size - 1))
+ count++;
+ count++;
+ break;
+ case PEER_INDEX:
+ if (1 != sscanf(&buf[count], "%u", &first_peer_index))
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to read peer index from topology file!\n");
+ GNUNET_free_non_null(data);
+ return connect_attempts;
+ }
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Read next peer index %u\n", first_peer_index);
+ while((buf[count] != ':') && (count < frstat.st_size - 1))
+ count++;
+ count++;
+ curr_state = OTHER_PEER_INDEX;
+ break;
+ case COLON:
+ if (1 == sscanf(&buf[count], ":"))
+ curr_state = OTHER_PEER_INDEX;
+ count++;
+ break;
+ case OTHER_PEER_INDEX:
+ if (1 != sscanf(&buf[count], "%u", &second_peer_index))
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to peer index from topology file!\n");
+ GNUNET_free_non_null(data);
+ return connect_attempts;
+ }
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Read second peer index %u\n", second_peer_index);
+ while((buf[count] != '\n') && (buf[count] != ' ') && (count < frstat.st_size - 1))
+ count++;
+ if (buf[count] == '\n')
+ {
+ curr_state = PEER_INDEX;
+ }
+ else if (buf[count] != ' ')
+ {
+ curr_state = OTHER_PEER_INDEX;
+ }
+ count++;
+ curr_state = OTHER_PEER_INDEX;
+ break;
+ default:
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Found bad data in topology file while in state %d!\n", curr_state);
+ GNUNET_break(0);
+ return connect_attempts;
+ }
+
+ }
+#if 0
+ /* Connect each peer to the next highest numbered peer */
+ for (count = 0; count < pg->total - 1; count++)
+ {
+#if VERBOSE_TESTING
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Connecting peer %d to peer %d\n", first_peer_index, second_peer_index);
+#endif
+ connect_attempts += proc (pg, first_peer_index, second_peer_index);
+ }
+#endif
+ return connect_attempts;
+}
+
/**
* Create a topology given a peer group (set of running peers)
* and a connection processor.
blacklist_file_iterator (void *cls, const GNUNET_HashCode * key, void *value)
{
struct BlacklistContext *blacklist_ctx = cls;
- //FILE *temp_blacklist_handle = cls;
struct GNUNET_TESTING_Daemon *peer = value;
struct GNUNET_PeerIdentity *temppeer;
struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
temppeer = &peer->id;
GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc);
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Writing entry %s:%s to file\n", blacklist_ctx->transport, (char *) &peer_enc);
fprintf (blacklist_ctx->temp_file_handle, "%s:%s\n",
blacklist_ctx->transport, (char *) &peer_enc);
unsigned int i;
char *pos;
char *temp_transports;
+ int entry_count;
procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total);
for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
{
temp_transports[i] = '\0';
blacklist_ctx.transport = pos;
- GNUNET_CONTAINER_multihashmap_iterate (pg->
+ entry_count = GNUNET_CONTAINER_multihashmap_iterate (pg->
peers
[pg_iter].blacklisted_peers,
&blacklist_file_iterator,
* of each peer in the peer group
*
* @param pg the peer group we are dealing with
+ * @param notify_callback callback to notify when finished
+ * @param notify_cls closure for notify callback
+ *
* @return the number of connections that will be attempted
*/
static int
* by the topology. This will only have an effect once peers
* are started if the FRIENDS_ONLY option is set in the base
* config. Also takes an optional restrict topology which
- * disallows connections based on a particular transport
+ * disallows connections based on particular transports
* UNLESS they are specified in the restricted topology.
*
* @param pg the peer group struct representing the running peers
* @param topology which topology to connect the peers in
- * @param restrict_topology allow only direct TCP connections in this topology
+ * @param restrict_topology disallow restrict_transports transport
+ * connections to peers NOT in this topology
* use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions
* @param restrict_transports space delimited list of transports to blacklist
* to create restricted topology
int ret;
unsigned int num_connections;
int unblacklisted_connections;
+ char *filename;
switch (topology)
{
#endif
num_connections = create_line (pg, &add_allowed_connections);
break;
+ case GNUNET_TESTING_TOPOLOGY_FROM_FILE:
+#if VERBOSE_TESTING
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Creating topology from file!\n"));
+#endif
+ if (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (pg->cfg, "testing", "topology_file",
+ &filename))
+ num_connections = create_from_file (pg, filename, &add_allowed_connections);
+ else
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Missing configuration option TESTING:TOPOLOGY_FILE for creating topology from file!");
+ num_connections = 0;
+ }
+ break;
case GNUNET_TESTING_TOPOLOGY_NONE:
#if VERBOSE_TESTING
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
}
/* Use the create clique method to initially set all connections as blacklisted. */
- if (restrict_topology != GNUNET_TESTING_TOPOLOGY_NONE)
- create_clique (pg, &blacklist_connections);
+ create_clique (pg, &blacklist_connections);
unblacklisted_connections = 0;
/* Un-blacklist connections as per the topology specified */
unblacklisted_connections = create_line (pg, &unblacklist_connections);
break;
case GNUNET_TESTING_TOPOLOGY_NONE:
+ case GNUNET_TESTING_TOPOLOGY_FROM_FILE:
#if VERBOSE_TESTING
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
_
("Creating no blacklist topology (all peers can connect at transport level)\n"));
#endif
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _
+ ("Creating blacklist topology from allowed\n"));
+ unblacklisted_connections = copy_allowed (pg, &unblacklist_connections);
default:
break;
}
if ((unblacklisted_connections > 0) && (restrict_transports != NULL))
{
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Creating blacklist with `%s'", restrict_transports);
ret = create_and_copy_blacklist_files (pg, restrict_transports);
if (ret != GNUNET_OK)
{
outstanding_connects);
#endif
topology_context->connected++;
+
if (GNUNET_OK !=
- GNUNET_CORE_iterate_peers (core_context->daemon->server,
+ GNUNET_CORE_iterate_peers (core_context->daemon->cfg,
&internal_topology_callback,
core_context))
- internal_topology_callback (core_context, NULL, NULL);
-
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Topology iteration failed.\n");
+ internal_topology_callback (core_context, NULL, NULL);
+ }
}
}
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (specific_peer->cfg, "statistics",
"port", &port))
- return GNUNET_NO;
+ {
+ GNUNET_free(unix_domain_socket);
+ return GNUNET_NO;
+ }
if (specific_peer->daemon->hostname != NULL)
GNUNET_asprintf (&to_match, "%s%s%llu", specific_peer->daemon->hostname,
*
* @param cls closure
* @param id identifier for the daemon, NULL on error
+ * @param cfg config
* @param d handle for the daemon
* @param emsg error message (NULL on success)
*/
* @param cb_cls closure for cb
* @param connect_callback function to call each time two hosts are connected
* @param connect_callback_cls closure for connect_callback
- * @param hostnames linked list of hosts to use to start peers on (NULL to run on localhost only)
+ * @param hostnames linked list of host structs to use to start peers on
+ * (NULL to run on localhost only)
*
* @return NULL on error, otherwise handle to control peer group
*/