EXTRA_DIST = \
test_testing_data.conf \
test_testing_connect_peer1.conf \
- test_testing_connect_peer2.conf
+ test_testing_connect_peer2.conf \
+ test_testing_data_topology_clique.conf
d2 = NULL;
}
+static void
+finish_testing(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+ GNUNET_TESTING_daemon_stop (d1, &end1_cb, NULL);
+ d1 = NULL;
+}
static void
my_connect_complete (void *cls,
struct GNUNET_TESTING_Daemon *second_daemon,
const char *emsg)
{
- GNUNET_TESTING_daemon_stop (d1, &end1_cb, NULL);
- d1 = NULL;
+ GNUNET_SCHEDULER_add_now (sched, &finish_testing, NULL);
}
[transport]
PORT = 2565
PLUGINS = tcp
-#PREFIX = xterm -e xterm -T transport -e gdb -x cmd --args
+#PREFIX = xterm -e xterm -T transport -e gdb --args
#PREFIX = valgrind --tool=memcheck --log-file=logs%p
+#DEBUG = YES
[arm]
PORT = 2566
[core]
PORT = 2570
+#DEBUG = YES
[testing]
-NUM_PEERS = 6
+NUM_PEERS = 2
WEAKRANDOM = YES
TOPOLOGY = 0
+F2F = YES
*/
#include "platform.h"
#include "gnunet_testing_lib.h"
+#include "gnunet_core_service.h"
#define VERBOSE GNUNET_NO
-
/**
* How long until we give up on connecting the peers?
*/
static unsigned long long num_peers;
-static int total_connections;
+static unsigned int total_connections;
+
+static unsigned int expected_connections;
static int peers_left;
GNUNET_SCHEDULER_TaskIdentifier die_task;
+static struct GNUNET_CORE_Handle *peer1handle;
+
+static struct GNUNET_CORE_Handle *peer2handle;
+
+#define MTYPE 12345
static void
finish_testing ()
{
GNUNET_assert (pg != NULL);
+
+ if (peer1handle != NULL)
+ GNUNET_CORE_disconnect(peer1handle);
+ if (peer2handle != NULL)
+ GNUNET_CORE_disconnect(peer2handle);
+
GNUNET_TESTING_daemons_stop (pg);
ok = 0;
}
+static int
+process_mtype (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ struct GNUNET_TIME_Relative latency,
+ uint32_t distance)
+{
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Receiving message from `%4s'.\n", GNUNET_i2s (peer));
+#endif
+ GNUNET_SCHEDULER_cancel (sched, die_task);
+ GNUNET_SCHEDULER_add_now (sched, &finish_testing, NULL);
+ return GNUNET_OK;
+}
+
+
+static void
+connect_notify (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ struct GNUNET_TIME_Relative latency,
+ uint32_t distance)
+{
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Encrypted connection established to peer `%4s' with latency %llu\n",
+ GNUNET_i2s (peer), latency.value);
+#endif
+}
+
+
+static void
+disconnect_notify (void *cls,
+ const struct GNUNET_PeerIdentity *peer)
+{
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Encrypted connection to `%4s' cut\n", GNUNET_i2s (peer));
+#endif
+}
+
+
+static int
+inbound_notify (void *cls,
+ const struct GNUNET_PeerIdentity *other,
+ const struct GNUNET_MessageHeader *message,
+ struct GNUNET_TIME_Relative latency,
+ uint32_t distance)
+{
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Core provides inbound data from `%4s'.\n", GNUNET_i2s (other));
+#endif
+ return GNUNET_OK;
+}
+
+
+static int
+outbound_notify (void *cls,
+ const struct GNUNET_PeerIdentity *other,
+ const struct GNUNET_MessageHeader *message,
+ struct GNUNET_TIME_Relative latency,
+ uint32_t distance)
+{
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Core notifies about outbound data for `%4s'.\n",
+ GNUNET_i2s (other));
+#endif
+ return GNUNET_OK;
+}
+
+static void
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "End badly was called... stopping daemons.\n");
+#endif
+
+ if (peer1handle != NULL)
+ {
+ GNUNET_CORE_disconnect(peer1handle);
+ peer1handle = NULL;
+ }
+ if (peer2handle != NULL)
+ {
+ GNUNET_CORE_disconnect(peer2handle);
+ peer2handle = NULL;
+ }
+
+ if (pg != NULL)
+ {
+ GNUNET_TESTING_daemons_stop (pg);
+ ok = 7331; /* Opposite of leet */
+ }
+ else
+ ok = 401; /* Never got peers started */
+}
+
+static size_t
+transmit_ready (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_MessageHeader *m;
+
+ GNUNET_assert (buf != NULL);
+ m = (struct GNUNET_MessageHeader *) buf;
+ m->type = htons (MTYPE);
+ m->size = htons (sizeof (struct GNUNET_MessageHeader));
+ GNUNET_SCHEDULER_cancel(sched, die_task);
+ die_task =
+ GNUNET_SCHEDULER_add_delayed (sched,
+ TIMEOUT, &end_badly, "from transmit ready");
+
+ return sizeof (struct GNUNET_MessageHeader);
+}
+
+
+static struct GNUNET_CORE_MessageHandler handlers[] = {
+ {&process_mtype, MTYPE, sizeof (struct GNUNET_MessageHeader)},
+ {NULL, 0, 0}
+};
+
+
+static void
+init_notify (void *cls,
+ struct GNUNET_CORE_Handle *server,
+ const struct GNUNET_PeerIdentity *my_identity,
+ const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
+{
+ struct GNUNET_TESTING_Daemon *connected_peer = cls;
+ struct GNUNET_TESTING_Daemon *peer1;
+ struct GNUNET_TESTING_Daemon *peer2;
+
+ peer1 = GNUNET_TESTING_daemon_get(pg, 0);
+ peer2 = GNUNET_TESTING_daemon_get(pg, 1);
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Core connection to `%4s' established, setting up handles\n",
+ GNUNET_i2s (my_identity));
+#endif
+
+ if (connected_peer == peer1)
+ {
+ peer1handle = server;
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting core to peer 2\n");
+#endif
+ /* connect p2 */
+ GNUNET_CORE_connect (sched,
+ peer2->cfg,
+ TIMEOUT,
+ peer2,
+ &init_notify,
+ NULL,
+ &connect_notify,
+ &disconnect_notify,
+ &inbound_notify,
+ GNUNET_YES,
+ &outbound_notify, GNUNET_YES, handlers);
+ }
+ else
+ {
+ GNUNET_assert(connected_peer == peer2);
+ peer2handle = server;
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Asking core (1) for transmission to peer `%4s'\n",
+ GNUNET_i2s (&peer2->id));
+#endif
+
+ if (NULL == GNUNET_CORE_notify_transmit_ready (peer1->server,
+ 0,
+ TIMEOUT,
+ &peer2->id,
+ sizeof (struct GNUNET_MessageHeader),
+ &transmit_ready, &peer1))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
+ GNUNET_i2s (&peer2->id));
+ }
+
+ }
+}
+
+
+static void
+send_test_messages ()
+{
+ struct GNUNET_TESTING_Daemon *peer1;
+ struct GNUNET_TESTING_Daemon *peer2;
+
+ peer1 = GNUNET_TESTING_daemon_get(pg, 0);
+ peer2 = GNUNET_TESTING_daemon_get(pg, 1);
+
+ die_task = GNUNET_SCHEDULER_add_delayed (sched,
+ TIMEOUT,
+ &end_badly, "from send test messages");
+
+ /* Send a message from peer 1 to peer 2 */
+ GNUNET_CORE_connect (sched,
+ peer1->cfg,
+ TIMEOUT,
+ peer1,
+ &init_notify,
+ NULL,
+ &connect_notify,
+ &disconnect_notify,
+ &inbound_notify,
+ GNUNET_YES, &outbound_notify, GNUNET_YES, handlers);
+}
void
topology_callback (void *cls,
* even though we know that X peers exist in i... But we may want to
* know about the peer for logging purposes here (I'm sure we will actually
* so the API may need changed). Question, should the API expose what
- * a peer group is, or provide convenience/accessor functions? */
+ * a peer group is, or provide convenience/accessor functions?
+ *
+ * For now, I've added accessor functions, which seems like a software
+ * engineering kind of solution, but who knows/cares. */
if (emsg == NULL)
{
total_connections++;
#if VERBOSE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s\n",
- GNUNET_TESTING_daemon_get_shortname (first_daemon),
- GNUNET_TESTING_daemon_get_shortname (second_daemon));
+ first_daemon->shortname,
+ second_daemon->shortname);
#endif
}
#if VERBOSE
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error %s\n",
- GNUNET_TESTING_daemon_get_shortname (first_daemon),
- GNUNET_TESTING_daemon_get_shortname (second_daemon), emsg);
+ first_daemon->shortname,
+ second_daemon->shortname, emsg);
}
#endif
- if (total_connections * 2 == num_peers * (num_peers - 1))
+ if (total_connections == expected_connections)
{
#if VERBOSE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Created %d total connections, which is our target number! Ending test.\n",
- total_connections * 2);
+ total_connections);
#endif
+
GNUNET_SCHEDULER_cancel (sched, die_task);
- finish_testing ();
+ die_task = GNUNET_SCHEDULER_add_now (sched, &send_test_messages, NULL);
}
else
{
#if VERBOSE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Have %d total connections, Need %d\n",
- total_connections * 2, num_peers * (num_peers - 1));
+ total_connections, expected_connections);
#endif
}
}
-static void
-end_badly ()
-{
- GNUNET_SCHEDULER_cancel (sched, die_task);
- if (pg != NULL)
- {
- GNUNET_TESTING_daemons_stop (pg);
- ok = 7331; /* Opposite of leet */
- }
- else
- ok = 401; /* Never got peers started */
-}
-
-
static void
create_topology ()
{
- int expected_connections; /* Is there any way we can use this to check
- how many connections we are expecting to
- finish the topology? It would be nice so
- that we could estimate completion time,
- but since GNUNET_TESTING_create_topology
- goes off and starts connecting we may get
- the topology callback before we have
- finished and not know how many! We could
- just never touch expected_connections,
- and if we get called back when it's still
- 0 then we know we can't believe it. I
- don't like this though, because it may
- technically be possible for all connections
- to have been created and the callback
- called without us setting
- expected_connections! Other options are
- doing a trial connection setup, or
- calculating the number of connections.
- Problem with calculating is that for random
- topologies this isn't reliable. Problem
- with counting is we then iterate over them
- twice instead of once. Probably the best
- option though. Grr, also doing trial
- connection set up means we need to call
- fake_topology_create and then
- real_topology_create which is also ugly.
- Then we need to maintain state inside pg as
- well, which I was trying to avoid. */
-
+ expected_connections = -1;
if ((pg != NULL) && (peers_left == 0))
{
/* create_topology will read the topology information from
}
GNUNET_SCHEDULER_cancel (sched, die_task);
-
die_task = GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS, 20),
- &finish_testing, NULL);
+ TIMEOUT,
+ &end_badly, NULL);
}
static int
check ()
{
- char *const argv[] = { "test-testing-topology",
+ char *const argv[] = { "test-testing-topology-clique",
"-c",
"test_testing_data_topology_clique.conf",
#if VERBOSE
GNUNET_GETOPT_OPTION_END
};
GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
- argv, "test-testing-topology", "nohelp",
+ argv, "test-testing-topology-clique", "nohelp",
options, &run, &ok);
return ok;
}
*/
#define MAX_EXEC_WAIT_RUNS 50
-/**
- * Phases of starting GNUnet on a system.
- */
-enum StartPhase
-{
- /**
- * Copy the configuration file to the target system.
- */
- SP_COPYING,
-
- /**
- * Configuration file has been copied, start ARM on target system.
- */
- SP_COPIED,
-
- /**
- * ARM has been started, check that it has properly daemonized and
- * then try to connect to the CORE service (which should be
- * auto-started by ARM).
- */
- SP_START_ARMING,
-
- /**
- * We're waiting for CORE to start.
- */
- SP_START_CORE,
-
- /**
- * Core has notified us that we've established a connection to the service.
- * The main FSM halts here and waits to be moved to UPDATE or CLEANUP.
- */
- SP_START_DONE,
-
- /**
- * We've been asked to terminate the instance and are now waiting for
- * the remote command to delete the configuration file to complete.
- */
- SP_CLEANUP,
-
- /**
- * We've received a configuration update and are currently waiting for
- * the copy process for the update to complete. Once it is, we will
- * return to "SP_START_DONE" (and rely on ARM to restart all affected
- * services).
- */
- SP_CONFIG_UPDATE
-};
-
-
-/**
- * Handle for a GNUnet daemon (technically a set of
- * daemons; the handle is really for the master ARM
- * daemon) started by the testing library.
- */
-struct GNUNET_TESTING_Daemon
-{
- /**
- * Our scheduler.
- */
- struct GNUNET_SCHEDULER_Handle *sched;
-
- /**
- * Our configuration.
- */
- struct GNUNET_CONFIGURATION_Handle *cfg;
-
- /**
- * Host to run GNUnet on.
- */
- char *hostname;
-
- /* Result of GNUNET_i2s of this peer, for printing */
- char *shortname;
-
- /**
- * Username we are using.
- */
- char *username;
-
- /**
- * Name of the configuration file
- */
- char *cfgfile;
-
- /**
- * Function to call when the peer is running.
- */
- GNUNET_TESTING_NotifyDaemonRunning cb;
-
- /**
- * Closure for cb.
- */
- void *cb_cls;
-
- /**
- * Arguments from "daemon_stop" call.
- */
- GNUNET_TESTING_NotifyCompletion dead_cb;
-
- /**
- * Closure for 'dead_cb'.
- */
- void *dead_cb_cls;
-
- /**
- * Arguments from "daemon_stop" call.
- */
- GNUNET_TESTING_NotifyCompletion update_cb;
-
- /**
- * Closure for 'update_cb'.
- */
- void *update_cb_cls;
-
- /**
- * Identity of this peer (once started).
- */
- struct GNUNET_PeerIdentity id;
-
- /**
- * Flag to indicate that we've already been asked
- * to terminate (but could not because some action
- * was still pending).
- */
- int dead;
-
- /**
- * PID of the process that we started last.
- */
- pid_t pid;
-
- /**
- * How many iterations have we been waiting for
- * the started process to complete?
- */
- unsigned int wait_runs;
-
- /**
- * In which phase are we during the start of
- * this process?
- */
- enum StartPhase phase;
-
- /**
- * ID of the current task.
- */
- GNUNET_SCHEDULER_TaskIdentifier task;
-
- /**
- * Handle to the server.
- */
- struct GNUNET_CORE_Handle *server;
-};
-
/**
* Function called after GNUNET_CORE_connect has succeeded
*/
struct GNUNET_TESTING_Daemon *d1;
+ /*
+ * Handle to core of first daemon (to check connect)
+ */
+ struct GNUNET_CORE_Handle * d1core;
+
/**
* Testing handle to the second daemon.
*/
struct GNUNET_TESTING_Daemon *d2;
+ /*
+ * Handle to core of second daemon (to check connect)
+ */
+ struct GNUNET_CORE_Handle * d2core;
+
/**
* Transport handle to the first daemon.
*/
*/
struct GNUNET_TIME_Absolute timeout;
+ /*
+ * Hello timeout task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier hello_send_task;
+
+ /*
+ * Connect timeout task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+ /**
+ * When should this operation be complete (or we must trigger
+ * a timeout).
+ */
+ struct GNUNET_TIME_Relative timeout_hello;
+
+ /*
+ * The current hello message we have (for d1)
+ */
+ struct GNUNET_MessageHeader *hello;
+
+ /*
+ * Was the connection successful?
+ */
+ int connected;
};
+/**
+ * Receive the HELLO from one peer, give it to the other
+ * and ask them to connect.
+ *
+ * @param cls "struct ConnectContext"
+ * @param message HELLO message of peer
+ */
+static void
+process_hello (void *cls, const struct GNUNET_MessageHeader *message)
+{
+ struct ConnectContext *ctx = cls;
+
+#if DEBUG_TESTING
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received `%s' from transport service of `%4s'\n",
+ "HELLO", GNUNET_i2s (&ctx->d1->id));
+#endif
+
+ GNUNET_assert (message != NULL);
+ GNUNET_free_non_null(ctx->hello);
+ ctx->hello = GNUNET_malloc(ntohs(message->size));
+ memcpy(ctx->hello, message, ntohs(message->size));
+
+}
+
+
/**
* Notify callback about success or failure of the attempt
* to connect the two peers
{
struct ConnectContext *ctx = cls;
+ GNUNET_TRANSPORT_get_hello_cancel (ctx->d1th, &process_hello, ctx);
+ GNUNET_SCHEDULER_cancel(ctx->d1->sched, ctx->hello_send_task);
+
if (ctx->cb != NULL)
{
- if ((tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT) != 0)
- ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->d1->cfg,
- ctx->d2->cfg, ctx->d1, ctx->d2,
- _("Peers failed to connect"));
+ if (ctx->connected == GNUNET_NO)
+ {
+ ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->d1->cfg,
+ ctx->d2->cfg, ctx->d1, ctx->d2,
+ _("Peers failed to connect"));
+ }
else
- ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->d1->cfg,
- ctx->d2->cfg, ctx->d1, ctx->d2, NULL);
+ {
+ ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->d1->cfg,
+ ctx->d2->cfg, ctx->d1, ctx->d2, NULL);
+ GNUNET_SCHEDULER_cancel(ctx->d1->sched, ctx->timeout_task);
+ }
}
+
+ ctx->ntr = NULL;
+ GNUNET_TRANSPORT_disconnect (ctx->d1th);
+ ctx->d1th = NULL;
+ GNUNET_TRANSPORT_disconnect (ctx->d2th);
+ ctx->d2th = NULL;
+ GNUNET_CORE_disconnect (ctx->d1core);
+ ctx->d1core = NULL;
+
GNUNET_free (ctx);
}
* @param buf where to copy the message, NULL on error
* @return number of bytes copied to buf
*/
-static size_t
-transmit_ready (void *cls, size_t size, void *buf)
+static void
+connect_notify (void *cls, const struct GNUNET_PeerIdentity * peer, struct GNUNET_TIME_Relative latency,
+ uint32_t distance)
{
struct ConnectContext *ctx = cls;
#if DEBUG_TESTING
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Core notified us about readiness to transmit message, connection must be up!\n");
+ "Core notified us about connection to a peer\n\n\n");
#endif
- ctx->ntr = NULL;
- GNUNET_TRANSPORT_disconnect (ctx->d1th);
- ctx->d1th = NULL;
- GNUNET_TRANSPORT_disconnect (ctx->d2th);
- ctx->d2th = NULL;
- GNUNET_SCHEDULER_add_continuation (ctx->d1->sched,
- ¬ify_connect_result,
- ctx,
- (buf == NULL) ?
- GNUNET_SCHEDULER_REASON_TIMEOUT :
- GNUNET_SCHEDULER_REASON_PREREQ_DONE);
- return 0;
-}
-
-
-#if 0
-static void
-timeout_hello_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- GNUNET_TRANSPORT_get_hello_cancel (ctx->d1th, &process_hello, ctx);
- GNUNET_TRANSPORT_disconnect (ctx->d1th);
- GNUNET_TRANSPORT_disconnect (ctx->d2th);
- if (NULL != ctx->cb)
- ctx->cb (ctx->cb_cls, _("Failed to receive `HELLO' from peer\n"));
- GNUNET_free (ctx);
-}
+ if (memcmp(&ctx->d2->id, peer, sizeof(struct GNUNET_PeerIdentity)) == 0)
+ {
+#if DEBUG_TESTING
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Core notified us about connection to peer %s\n\n\n", GNUNET_i2s(peer));
#endif
+ /*
+ * If we disconnect here, then the hello may never get sent (if it was delayed!)
+ * However I'm sure there was a reason it was here... so I'm just commenting.
+ */
+ ctx->connected = GNUNET_YES;
+ GNUNET_SCHEDULER_add_now (ctx->d1->sched,
+ ¬ify_connect_result,
+ ctx);
+ }
+}
-/**
- * Receive the HELLO from one peer, give it to the other
- * and ask them to connect.
- *
- * @param cls "struct ConnectContext"
- * @param message HELLO message of peer
- */
static void
-process_hello (void *cls, const struct GNUNET_MessageHeader *message)
+send_hello(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct ConnectContext *ctx = cls;
- /* first of all, stop the notification stuff */
- GNUNET_TRANSPORT_get_hello_cancel (ctx->d1th, &process_hello, ctx);
-#if DEBUG_TESTING
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received `%s' from transport service of `%4s'\n",
- "HELLO", GNUNET_i2s (&ctx->d1->id));
-#endif
- GNUNET_assert (message != NULL);
- GNUNET_TRANSPORT_offer_hello (ctx->d2th, message);
- ctx->ntr
- = GNUNET_CORE_notify_transmit_ready (ctx->d2->server,
- 0,
- GNUNET_TIME_absolute_get_remaining
- (ctx->timeout), &ctx->d1->id,
- sizeof (struct GNUNET_MessageHeader),
- &transmit_ready, ctx);
+ GNUNET_assert (ctx->hello != NULL);
+ GNUNET_TRANSPORT_offer_hello (ctx->d2th, ctx->hello);
+
+ ctx->timeout_hello = GNUNET_TIME_relative_multiply(ctx->timeout_hello, 2);
+ ctx->hello_send_task = GNUNET_SCHEDULER_add_delayed(ctx->d1->sched, ctx->timeout_hello, &send_hello, ctx);
}
+
+#if HIDDEN
/*
* Accessor function since we have hidden what GNUNET_TESTING_Daemon is
*
return d->shortname;
}
+char *
+GNUNET_TESTING_daemon_get_hostname (struct GNUNET_TESTING_Daemon *d)
+{
+ return d->hostname;
+}
+
+char *
+GNUNET_TESTING_daemon_get_username (struct GNUNET_TESTING_Daemon *d)
+{
+ return d->username;
+}
+
+struct GNUNET_PeerIdentity *
+GNUNET_TESTING_daemon_get_peer (struct GNUNET_TESTING_Daemon *d)
+{
+ return &d->id;
+}
+
+struct GNUNET_CONFIGURATION_Handle *
+GNUNET_TESTING_daemon_get_config (struct GNUNET_TESTING_Daemon *d)
+{
+ return d->cfg;
+}
+#endif
+
+
/**
* Establish a connection between two GNUnet daemons.
*
void *cb_cls)
{
struct ConnectContext *ctx;
+ static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} };
if ((d1->server == NULL) || (d2->server == NULL))
{
ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
ctx->cb = cb;
ctx->cb_cls = cb_cls;
+ ctx->timeout_hello = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 800);
+ ctx->connected = GNUNET_NO;
#if DEBUG_TESTING
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Asked to connect peer %s to peer %s\n",
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Connecting to transport service of peer %s\n", d1->shortname);
#endif
+
+ ctx->d1core = GNUNET_CORE_connect (d1->sched,
+ d1->cfg,
+ timeout,
+ ctx,
+ NULL,
+ NULL, &connect_notify, NULL,
+ NULL, GNUNET_NO,
+ NULL, GNUNET_NO, no_handlers);
+ if (ctx->d1core == NULL)
+ {
+ GNUNET_free (ctx);
+ if (NULL != cb)
+ cb (cb_cls, &d1->id, &d2->id, d1->cfg, d2->cfg, d1, d2,
+ _("Failed to connect to core service of first peer!\n"));
+ return;
+ }
+
ctx->d1th = GNUNET_TRANSPORT_connect (d1->sched,
d1->cfg, d1, NULL, NULL, NULL);
if (ctx->d1th == NULL)
"Connecting to transport service of peer %s\n", d2->shortname);
#endif
+
ctx->d2th = GNUNET_TRANSPORT_connect (d2->sched,
d2->cfg, d2, NULL, NULL, NULL);
if (ctx->d2th == NULL)
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Asking for hello from peer %s\n", GNUNET_i2s (&d1->id));
#endif
- /* FIXME: need to handle timeout: start timeout task
- as well here! (use 'timeout_hello_task') */
+
+ ctx->timeout_task = GNUNET_SCHEDULER_add_delayed (d1->sched,
+ timeout,
+ ¬ify_connect_result, ctx);
+
GNUNET_TRANSPORT_get_hello (ctx->d1th, &process_hello, ctx);
+ ctx->hello_send_task = GNUNET_SCHEDULER_add_delayed(ctx->d1->sched, ctx->timeout_hello, &send_hello, ctx);
}
#define CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+struct PeerConnection
+{
+ /*
+ * Linked list
+ */
+ struct PeerConnection *next;
+
+ /*
+ * Pointer to daemon handle
+ */
+ struct GNUNET_TESTING_Daemon *daemon;
+
+};
+
/**
* Data we keep per peer.
*/
* Handle for controlling the daemon.
*/
struct GNUNET_TESTING_Daemon *daemon;
+
+ /*
+ * Linked list of peer connections (simply indexes of PeerGroup)
+ * FIXME: Question, store pointer or integer? Pointer for now...
+ */
+ struct PeerConnection *connected_peers;
};
return uc.ret;
}
+/*
+ * Add entries to the peers connected list
+ *
+ * @param pg the peer group we are working with
+ * @param first index of the first peer
+ * @param second index of the second peer
+ *
+ * @return the number of connections added (can be 0 1 or 2)
+ *
+ * FIXME: add both, or only add one?
+ * - if both are added, then we have to keep track
+ * when connecting so we don't double connect
+ * - if only one is added, we need to iterate over
+ * both lists to find out if connection already exists
+ * - having both allows the whitelisting/friend file
+ * creation to be easier
+ *
+ * -- For now, add both, we have to iterate over each to
+ * check for duplicates anyways, so we'll take the performance
+ * hit assuming we don't have __too__ many connections
+ *
+ */
+static int
+add_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
+{
+ int added;
+ struct PeerConnection *first_iter;
+ struct PeerConnection *second_iter;
+ int add_first;
+ int add_second;
+ struct PeerConnection *new_first;
+ struct PeerConnection *new_second;
+
+ first_iter = pg->peers[first].connected_peers;
+ add_first = GNUNET_YES;
+ while (first_iter != NULL)
+ {
+ if (first_iter->daemon == pg->peers[second].daemon)
+ add_first = GNUNET_NO;
+ first_iter = first_iter->next;
+ }
+
+ second_iter = pg->peers[second].connected_peers;
+ add_second = GNUNET_YES;
+ while (second_iter != NULL)
+ {
+ if (second_iter->daemon == pg->peers[first].daemon)
+ add_second = GNUNET_NO;
+ second_iter = second_iter->next;
+ }
+
+ added = 0;
+ if (add_first)
+ {
+ new_first = GNUNET_malloc(sizeof(struct PeerConnection));
+ new_first->daemon = pg->peers[second].daemon;
+ new_first->next = pg->peers[first].connected_peers;
+ pg->peers[first].connected_peers = new_first;
+ added++;
+ }
+
+ if (add_second)
+ {
+ new_second = GNUNET_malloc(sizeof(struct PeerConnection));
+ new_second->daemon = pg->peers[first].daemon;
+ new_second->next = pg->peers[second].connected_peers;
+ pg->peers[second].connected_peers = new_second;
+ added++;
+ }
+
+ return added;
+}
+
static int
create_clique (struct GNUNET_TESTING_PeerGroup *pg)
{
"Connecting peer %d to peer %d\n",
outer_count, inner_count);
#endif
- GNUNET_TESTING_daemons_connect (pg->peers[outer_count].daemon,
+ connect_attempts += add_connections(pg, outer_count, inner_count);
+ /*GNUNET_TESTING_daemons_connect (pg->peers[outer_count].daemon,
pg->peers[inner_count].daemon,
CONNECT_TIMEOUT,
pg->notify_connection,
- pg->notify_connection_cls);
- connect_attempts++;
+ pg->notify_connection_cls);*/
}
}
}
+/*
+ * Create the friend files based on the PeerConnection's
+ * of each peer in the peer group, and copy the files
+ * to the appropriate place
+ *
+ * @param pg the peer group we are dealing with
+ */
+static void
+create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
+{
+ FILE *temp_friend_handle;
+ unsigned int pg_iter;
+ struct PeerConnection *connection_iter;
+ struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
+ char *temp_service_path;
+ pid_t pid;
+ char *arg;
+ struct GNUNET_PeerIdentity *temppeer;
+ const char * mytemp;
+
+ for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
+ {
+ mytemp = GNUNET_DISK_mktemp("friends");
+ temp_friend_handle = fopen (mytemp, "wt");
+ connection_iter = pg->peers[pg_iter].connected_peers;
+ while (connection_iter != NULL)
+ {
+ temppeer = &connection_iter->daemon->id;
+ GNUNET_CRYPTO_hash_to_enc(&temppeer->hashPubKey, &peer_enc);
+ fprintf(temp_friend_handle, "%s\n", (char *)&peer_enc);
+ connection_iter = connection_iter->next;
+ }
+
+ fclose(temp_friend_handle);
+
+ GNUNET_CONFIGURATION_get_value_string(pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path);
+
+ if (temp_service_path == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("No SERVICEHOME specified in peer configuration, can't copy friends file!\n"));
+ fclose(temp_friend_handle);
+ unlink(mytemp);
+ break;
+ }
+
+ if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
+ {
+ GNUNET_asprintf (&arg, "%s/friends", temp_service_path);
+ pid = GNUNET_OS_start_process ("mv",
+ "mv", mytemp, arg, NULL);
+#if VERBOSE_TESTING
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Copying file with command cp %s %s\n"), mytemp, arg);
+#endif
+ GNUNET_free(arg);
+ }
+ else /* Remote, scp the file to the correct place */
+ {
+ if (NULL != pg->peers[pg_iter].daemon->username)
+ GNUNET_asprintf (&arg, "%s@%s:%s/friends", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path);
+ else
+ GNUNET_asprintf (&arg, "%s:%s/friends", pg->peers[pg_iter].daemon->hostname, temp_service_path);
+ pid = GNUNET_OS_start_process ("scp",
+ "scp", mytemp, arg, NULL);
+#if VERBOSE_TESTING
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Copying file with command scp %s %s\n"), mytemp, arg);
+#endif
+ GNUNET_free(arg);
+ }
+
+ }
+}
+
+
+
+/*
+ * Connect the topology as specified by the PeerConnection's
+ * of each peer in the peer group
+ *
+ * @param pg the peer group we are dealing with
+ */
+static void
+connect_topology (struct GNUNET_TESTING_PeerGroup *pg)
+{
+ unsigned int pg_iter;
+ struct PeerConnection *connection_iter;
+
+ for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
+ {
+ connection_iter = pg->peers[pg_iter].connected_peers;
+ while (connection_iter != NULL)
+ {
+ GNUNET_TESTING_daemons_connect (pg->peers[pg_iter].daemon,
+ connection_iter->daemon,
+ CONNECT_TIMEOUT,
+ pg->notify_connection,
+ pg->notify_connection_cls);
+ connection_iter = connection_iter->next;
+ }
+ }
+}
+
+
/*
* Takes a peer group and attempts to create a topology based on the
* one specified in the configuration file. Returns the number of connections
int
GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg)
{
- /* Put stuff at home in here... */
unsigned long long topology_num;
int ret;
ret = GNUNET_SYSERR;
break;
}
+
+ if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
+ create_and_copy_friend_files(pg);
+
+ connect_topology(pg);
}
else
{
const char *hostname;
char *baseservicehome;
char *newservicehome;
+ char *tmpdir;
struct GNUNET_CONFIGURATION_Handle *pcfg;
unsigned int off;
unsigned int hostcnt;
}
else
{
- tempsize = snprintf (NULL, 0, "%s/%d/", "/tmp/gnunet-testing-test-test", off) + 1; /* FIXME: set a default path, or read the TMPDIR variable or something */
+ tmpdir = getenv ("TMPDIR");
+ tmpdir = tmpdir ? tmpdir : "/tmp";
+ tempsize = snprintf (NULL, 0, "%s/%s/%d/", tmpdir, "gnunet-testing-test-test", off) + 1;
newservicehome = GNUNET_malloc (tempsize);
snprintf (newservicehome, tempsize, "%s/%d/",
"/tmp/gnunet-testing-test-test", off);
return pg;
}
+/*
+ * Get a daemon by number, so callers don't have to do nasty
+ * offsetting operation.
+ */
+struct GNUNET_TESTING_Daemon *
+GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position)
+{
+ if (position < pg->total)
+ return pg->peers[position].daemon;
+ else
+ return NULL;
+}
/**
* Shutdown all peers started in the given group.
continuations to be called here? This
would require us to take a continuation
as well... */
+
if (NULL != pg->peers[off].daemon)
GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, NULL, NULL);
if (NULL != pg->peers[off].cfg)