From: Nathan S. Evans Date: Thu, 11 Feb 2010 13:37:09 +0000 (+0000) Subject: testing changes, including real topology test (only for clique, and not that great... X-Git-Tag: initial-import-from-subversion-38251~22740 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=0bcffe690a5345324d7be4099a4bec157ec1282b;p=oweals%2Fgnunet.git testing changes, including real topology test (only for clique, and not that great of a test). Need to verify it will run on other machines... also need to commit it since it currently works for me --- diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am index 4ddcc2b97..934ecc612 100644 --- a/src/testing/Makefile.am +++ b/src/testing/Makefile.am @@ -60,4 +60,5 @@ test_testing_topology_clique_LDADD = \ 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 diff --git a/src/testing/test_testing_connect.c b/src/testing/test_testing_connect.c index 70fcccd98..5cd6274ea 100644 --- a/src/testing/test_testing_connect.c +++ b/src/testing/test_testing_connect.c @@ -64,6 +64,12 @@ end1_cb (void *cls, const char *emsg) 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, @@ -75,8 +81,7 @@ 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); } diff --git a/src/testing/test_testing_data_topology_clique.conf b/src/testing/test_testing_data_topology_clique.conf index a015b9b66..6f9a7739e 100644 --- a/src/testing/test_testing_data_topology_clique.conf +++ b/src/testing/test_testing_data_topology_clique.conf @@ -8,8 +8,9 @@ PORT = 2564 [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 @@ -26,8 +27,10 @@ PORT = 2569 [core] PORT = 2570 +#DEBUG = YES [testing] -NUM_PEERS = 6 +NUM_PEERS = 2 WEAKRANDOM = YES TOPOLOGY = 0 +F2F = YES diff --git a/src/testing/test_testing_topology_clique.c b/src/testing/test_testing_topology_clique.c index 3d37d542b..a51d77f98 100644 --- a/src/testing/test_testing_topology_clique.c +++ b/src/testing/test_testing_topology_clique.c @@ -23,10 +23,10 @@ */ #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? */ @@ -38,7 +38,9 @@ static int ok; static unsigned long long num_peers; -static int total_connections; +static unsigned int total_connections; + +static unsigned int expected_connections; static int peers_left; @@ -50,15 +52,238 @@ const struct GNUNET_CONFIGURATION_Handle *main_cfg; 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, @@ -75,14 +300,17 @@ 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 @@ -90,78 +318,37 @@ topology_callback (void *cls, { 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 @@ -178,11 +365,9 @@ create_topology () } 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); } @@ -259,7 +444,7 @@ run (void *cls, 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 @@ -271,7 +456,7 @@ check () 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; } diff --git a/src/testing/testing.c b/src/testing/testing.c index 8ceaace75..bddd0f30c 100644 --- a/src/testing/testing.c +++ b/src/testing/testing.c @@ -54,160 +54,6 @@ */ #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 @@ -793,11 +639,21 @@ struct ConnectContext */ 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. */ @@ -830,9 +686,60 @@ struct ConnectContext */ 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 @@ -846,16 +753,33 @@ notify_connect_result (void *cls, { 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); } @@ -868,74 +792,48 @@ notify_connect_result (void *cls, * @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 * @@ -947,6 +845,32 @@ GNUNET_TESTING_daemon_get_shortname (struct GNUNET_TESTING_Daemon *d) 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. * @@ -965,6 +889,7 @@ GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, void *cb_cls) { struct ConnectContext *ctx; + static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} }; if ((d1->server == NULL) || (d2->server == NULL)) { @@ -979,6 +904,8 @@ GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, 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", @@ -986,6 +913,24 @@ GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, 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) @@ -1004,6 +949,7 @@ GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, "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) @@ -1020,9 +966,13 @@ GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, 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); } diff --git a/src/testing/testing_group.c b/src/testing/testing_group.c index 424dada34..fd1338e1e 100644 --- a/src/testing/testing_group.c +++ b/src/testing/testing_group.c @@ -46,6 +46,20 @@ #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. */ @@ -63,6 +77,12 @@ struct PeerData * 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; }; @@ -202,6 +222,79 @@ make_config (const struct GNUNET_CONFIGURATION_Handle *cfg, uint16_t * port) 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) { @@ -221,12 +314,12 @@ 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);*/ } } @@ -234,6 +327,111 @@ create_clique (struct GNUNET_TESTING_PeerGroup *pg) } +/* + * 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 @@ -247,7 +445,6 @@ create_clique (struct GNUNET_TESTING_PeerGroup *pg) int GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg) { - /* Put stuff at home in here... */ unsigned long long topology_num; int ret; @@ -330,6 +527,11 @@ GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg) 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 { @@ -374,6 +576,7 @@ GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched, const char *hostname; char *baseservicehome; char *newservicehome; + char *tmpdir; struct GNUNET_CONFIGURATION_Handle *pcfg; unsigned int off; unsigned int hostcnt; @@ -475,7 +678,9 @@ GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched, } 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); @@ -496,6 +701,18 @@ GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched, 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. @@ -513,6 +730,7 @@ GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg) 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)