From 7c0698d2296e00d9544f48819f24ed4319e3fad8 Mon Sep 17 00:00:00 2001 From: "Nathan S. Evans" Date: Tue, 22 Feb 2011 15:19:49 +0000 Subject: [PATCH] Testing and core related changes. --- src/core/core_api.c | 8 +- src/core/core_api_iterate_peers.c | 10 +- src/core/gnunet-service-core.c | 47 +- src/dht/gnunet-dht-driver.c | 54 +- src/dht/gnunet-service-dht.c | 4 +- src/fs/fs_test_lib.c | 1 + src/hostlist/hostlist-client.c | 2 +- src/include/gnunet_protocols.h | 15 +- src/include/gnunet_testing_lib.h | 21 +- src/include/gnunet_transport_service.h | 10 +- src/testing/test_testing_topology.c | 11 +- src/testing/testing.c | 380 ++++++++------ src/testing/testing_group.c | 690 +++++++++++++++++++++---- src/topology/gnunet-daemon-topology.c | 2 +- src/util/client.c | 1 + 15 files changed, 962 insertions(+), 294 deletions(-) diff --git a/src/core/core_api.c b/src/core/core_api.c index e9a38271b..16479b2d3 100644 --- a/src/core/core_api.c +++ b/src/core/core_api.c @@ -1733,8 +1733,12 @@ GNUNET_CORE_peer_request_connect (struct GNUNET_CORE_Handle *h, if (NULL != GNUNET_CONTAINER_multihashmap_get (h->peers, &peer->hashPubKey)) - return NULL; /* Already connected, means callback should have happened already! */ - + { +#if DEBUG_CORE + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peers are already connected!\n"); +#endif + return NULL; + } cm = GNUNET_malloc (sizeof (struct ControlMessage) + sizeof (struct ConnectMessage)); diff --git a/src/core/core_api_iterate_peers.c b/src/core/core_api_iterate_peers.c index 25ce5ebb0..967580f83 100644 --- a/src/core/core_api_iterate_peers.c +++ b/src/core/core_api_iterate_peers.c @@ -153,9 +153,13 @@ transmit_request(void *cls, msg = (struct GNUNET_MessageHeader *)buf; msg->size = htons (msize); - msg->type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS); if (peer != NULL) - memcpy(&msg[1], peer, sizeof(struct GNUNET_PeerIdentity)); + { + msg->type = htons (GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED); + memcpy(&msg[1], peer, sizeof(struct GNUNET_PeerIdentity)); + } + else + msg->type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS); return msize; } @@ -198,7 +202,7 @@ GNUNET_CORE_is_peer_connected (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_YES, &transmit_request, peer); - + GNUNET_assert(request_context->th != NULL); GNUNET_CLIENT_receive(client, &receive_info, request_context, GNUNET_TIME_relative_get_forever()); return GNUNET_OK; } diff --git a/src/core/gnunet-service-core.c b/src/core/gnunet-service-core.c index 44052709b..6be71242f 100644 --- a/src/core/gnunet-service-core.c +++ b/src/core/gnunet-service-core.c @@ -1498,7 +1498,6 @@ handle_client_iterate_peers (void *cls, { struct GNUNET_MessageHeader done_msg; struct GNUNET_SERVER_TransmitContext *tc; - struct GNUNET_PeerIdentity *peer; int msize; /* notify new client about existing neighbours */ @@ -1506,11 +1505,6 @@ handle_client_iterate_peers (void *cls, tc = GNUNET_SERVER_transmit_context_create (client); if (msize == sizeof(struct GNUNET_MessageHeader)) GNUNET_CONTAINER_multihashmap_iterate (neighbours, &queue_connect_message, tc); - else if (msize == sizeof(struct GNUNET_MessageHeader) + sizeof(struct GNUNET_PeerIdentity)) - { - peer = (struct GNUNET_PeerIdentity *)&message[1]; - GNUNET_CONTAINER_multihashmap_get_multiple(neighbours, &peer->hashPubKey, &queue_connect_message, tc); - } else GNUNET_break(0); @@ -1521,6 +1515,38 @@ handle_client_iterate_peers (void *cls, GNUNET_TIME_UNIT_FOREVER_REL); } +/** + * Handle CORE_ITERATE_PEERS request. + * + * @param cls unused + * @param client client sending the iteration request + * @param message iteration request message + */ +static void +handle_client_have_peer (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) + +{ + struct GNUNET_MessageHeader done_msg; + struct GNUNET_SERVER_TransmitContext *tc; + struct GNUNET_PeerIdentity *peer; + int msize; + /* notify new client about existing neighbours */ + + msize = ntohs(message->size); + tc = GNUNET_SERVER_transmit_context_create (client); + + peer = (struct GNUNET_PeerIdentity *)&message[1]; + GNUNET_CONTAINER_multihashmap_get_multiple(neighbours, &peer->hashPubKey, &queue_connect_message, tc); + + done_msg.size = htons (sizeof (struct GNUNET_MessageHeader)); + done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END); + GNUNET_SERVER_transmit_context_append_message (tc, &done_msg); + GNUNET_SERVER_transmit_context_run (tc, + GNUNET_TIME_UNIT_FOREVER_REL); +} + /** * Handle REQUEST_INFO request. @@ -2973,10 +2999,6 @@ handle_client_request_connect (void *cls, if ( (GNUNET_YES == n->is_connected) || (n->th != NULL) ) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Core received `%s' request for `%4s', already connected!\n", - "REQUEST_CONNECT", - GNUNET_i2s (&cm->peer)); if (GNUNET_YES == n->is_connected) GNUNET_STATISTICS_update (stats, gettext_noop ("# connection requests ignored (already connected)"), @@ -3004,10 +3026,12 @@ handle_client_request_connect (void *cls, 1, GNUNET_NO); +#if DEBUG_CORE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core received `%s' request for `%4s', will try to establish connection\n", "REQUEST_CONNECT", GNUNET_i2s (&cm->peer)); +#endif /* ask transport to connect to the peer */ n->th = GNUNET_TRANSPORT_notify_transmit_ready (transport, @@ -4662,6 +4686,9 @@ run (void *cls, {&handle_client_iterate_peers, NULL, GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS, sizeof (struct GNUNET_MessageHeader)}, + {&handle_client_have_peer, NULL, + GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED, + sizeof (struct GNUNET_MessageHeader) + sizeof(struct GNUNET_PeerIdentity)}, {&handle_client_request_info, NULL, GNUNET_MESSAGE_TYPE_CORE_REQUEST_INFO, sizeof (struct RequestInfoMessage)}, diff --git a/src/dht/gnunet-dht-driver.c b/src/dht/gnunet-dht-driver.c index 7e10e5a3a..98cf12fc7 100644 --- a/src/dht/gnunet-dht-driver.c +++ b/src/dht/gnunet-dht-driver.c @@ -34,9 +34,10 @@ #include "gnunet_dht_service.h" #include "dhtlog.h" #include "dht.h" +#include "gauger.h" /* Specific DEBUG hack, do not use normally (may leak memory, segfault, or eat children.) */ -#define ONLY_TESTING GNUNET_YES +#define ONLY_TESTING GNUNET_NO /* DEFINES */ #define VERBOSE GNUNET_NO @@ -687,6 +688,16 @@ static unsigned long long outstanding_gets; */ static unsigned long long gets_completed; +/** + * Total number of items to attempt to get. + */ +static unsigned long long cumulative_num_gets; + +/** + * How many gets are done? + */ +static unsigned long long cumulative_successful_gets; + /** * How many gets failed? */ @@ -1354,7 +1365,7 @@ static int iterate_min_heap_peers (void *cls, { timeout = GNUNET_TIME_absolute_get_remaining(find_peer_context->endtime); } - GNUNET_TESTING_daemons_connect(d1, d2, timeout, DEFAULT_RECONNECT_ATTEMPTS, NULL, NULL); + GNUNET_TESTING_daemons_connect(d1, d2, timeout, DEFAULT_RECONNECT_ATTEMPTS, GNUNET_YES, NULL, NULL); } if (GNUNET_TIME_absolute_get_remaining(find_peer_context->endtime).rel_value > 0) return GNUNET_YES; @@ -1793,6 +1804,9 @@ get_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) if (tc->reason == GNUNET_SCHEDULER_REASON_TIMEOUT) gets_failed++; + else + cumulative_successful_gets++; + GNUNET_assert(test_get->get_handle != NULL); GNUNET_DHT_get_stop(test_get->get_handle); test_get->get_handle = NULL; @@ -1889,6 +1903,7 @@ do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) GNUNET_assert(test_get->dht_handle != NULL); outstanding_gets++; + cumulative_num_gets++; /* Insert the data at the first peer */ test_get->get_handle = GNUNET_DHT_get_start(test_get->dht_handle, get_delay, @@ -2617,7 +2632,11 @@ topology_callback (void *cls, (second_daemon == repeat_connect_peer2)) { if (emsg != NULL) /* Peers failed to connect again! */ - return; + { + GNUNET_assert(repeat_connect_task == GNUNET_SCHEDULER_NO_TASK); + repeat_connect_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 60), &repeat_connect, NULL); + return; + } else /* Repeat peers actually connected! */ { if (repeat_connect_task != GNUNET_SCHEDULER_NO_TASK) @@ -2676,12 +2695,6 @@ topology_callback (void *cls, } #endif } -#if ONLY_TESTING - else if (repeat_connect_mode == GNUNET_YES) - { - repeat_connect_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 60), &repeat_connect, NULL); - } -#endif if (emsg == NULL) { @@ -2708,7 +2721,7 @@ topology_callback (void *cls, } #if ONLY_TESTING - if (repeat_connect_mode == GNUNET_YES) + if ((repeat_connect_mode == GNUNET_YES) ) return; #endif @@ -2728,6 +2741,27 @@ topology_callback (void *cls, dhtlog_handle->insert_topology(expected_connections); } + + total_duration = GNUNET_TIME_absolute_get_difference (connect_start_time, + GNUNET_TIME_absolute_get()).rel_value / 1000; + failed_conns_per_sec_total = (double)failed_connections / total_duration; + conns_per_sec_total = (double)total_connections / total_duration; + GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Overall connection info --- Total: %u, Total Failed %u/s\n", + total_connections, failed_connections); + GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n", + conns_per_sec_total, failed_conns_per_sec_total); + /** Comment out until gauger is ready */ + /** + GNUNET_asprintf(&temp_conn_string, "dht_peer_connection_speed"); + GNUNET_asprintf(&temp_failed_conn_string, "dht_peer_failed_connection_speed"); + + GAUGER_COUNTER(temp_conn_string, conns_per_sec_total, trial_to_run, DATE); + GAUGER_COUNTER(temp_failed_conn_string, failed_conns_per_sec_total, trial_to_run, DATE); + + GNUNET_free(temp_conn_string); + GNUNET_free(temp_failed_conn_string); + */ + GNUNET_SCHEDULER_cancel (die_task); if ((GNUNET_YES == dhtlog_minimal) && (NULL != dhtlog_handle)) diff --git a/src/dht/gnunet-service-dht.c b/src/dht/gnunet-service-dht.c index 72cd7e39f..f205abbae 100644 --- a/src/dht/gnunet-service-dht.c +++ b/src/dht/gnunet-service-dht.c @@ -2181,7 +2181,7 @@ route_result_message (struct GNUNET_MessageHeader *msg, if (GNUNET_YES == consider_peer (&new_peer)) { increment_stats (STAT_HELLOS_PROVIDED); - GNUNET_TRANSPORT_offer_hello (transport_handle, hello_msg); + GNUNET_TRANSPORT_offer_hello (transport_handle, hello_msg, NULL, NULL); GNUNET_CORE_peer_request_connect (coreAPI, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), @@ -2701,7 +2701,7 @@ handle_dht_find_peer (const struct GNUNET_MessageHeader *find_msg, if (GNUNET_YES == consider_peer (&peer_id)) { increment_stats (STAT_HELLOS_PROVIDED); - GNUNET_TRANSPORT_offer_hello (transport_handle, other_hello); + GNUNET_TRANSPORT_offer_hello (transport_handle, other_hello, NULL, NULL); GNUNET_CORE_peer_request_connect (coreAPI, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), diff --git a/src/fs/fs_test_lib.c b/src/fs/fs_test_lib.c index a3f33a522..4af4dae33 100644 --- a/src/fs/fs_test_lib.c +++ b/src/fs/fs_test_lib.c @@ -482,6 +482,7 @@ GNUNET_FS_TEST_daemons_connect (struct GNUNET_FS_TestDaemon *daemon1, daemon2->daemon, timeout, CONNECT_ATTEMPTS, + GNUNET_YES, ¬ify_connection, ncc); } diff --git a/src/hostlist/hostlist-client.c b/src/hostlist/hostlist-client.c index 4797a5544..d2fa65433 100644 --- a/src/hostlist/hostlist-client.c +++ b/src/hostlist/hostlist-client.c @@ -335,7 +335,7 @@ callback_download (void *ptr, 1, GNUNET_NO); stat_hellos_obtained++; - GNUNET_TRANSPORT_offer_hello (transport, msg); + GNUNET_TRANSPORT_offer_hello (transport, msg, NULL, NULL); } else { diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index d1b670aa3..60369086d 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h @@ -387,30 +387,35 @@ extern "C" */ #define GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END 79 +/** + * Check whether a given peer is currently connected to CORE. + */ +#define GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED 80 + /** * Session key exchange between peers. */ -#define GNUNET_MESSAGE_TYPE_CORE_SET_KEY 80 +#define GNUNET_MESSAGE_TYPE_CORE_SET_KEY 81 /** * Encapsulation for an encrypted message between peers. */ -#define GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE 81 +#define GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE 82 /** * Check that other peer is alive (challenge). */ -#define GNUNET_MESSAGE_TYPE_CORE_PING 82 +#define GNUNET_MESSAGE_TYPE_CORE_PING 83 /** * Confirmation that other peer is alive. */ -#define GNUNET_MESSAGE_TYPE_CORE_PONG 83 +#define GNUNET_MESSAGE_TYPE_CORE_PONG 84 /** * Request by the other peer to terminate the connection. */ -#define GNUNET_MESSAGE_TYPE_CORE_HANGUP 84 +#define GNUNET_MESSAGE_TYPE_CORE_HANGUP 85 /** * Message sent by datastore client on join. diff --git a/src/include/gnunet_testing_lib.h b/src/include/gnunet_testing_lib.h index 14a0bbd86..af57613c6 100644 --- a/src/include/gnunet_testing_lib.h +++ b/src/include/gnunet_testing_lib.h @@ -157,6 +157,11 @@ enum GNUNET_TESTING_StartPhase */ SP_START_CORE, + /** + * CORE is up, now make sure we get the HELLO for this peer. + */ + SP_GET_HELLO, + /** * 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. @@ -545,15 +550,19 @@ void GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d, * allowed to take? * @param max_connect_attempts how many times should we try to reconnect * (within timeout) + * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume + * the HELLO has already been exchanged * @param cb function to call at the end * @param cb_cls closure for cb */ -void GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, - struct GNUNET_TESTING_Daemon *d2, - struct GNUNET_TIME_Relative timeout, - unsigned int max_connect_attempts, - GNUNET_TESTING_NotifyConnection cb, - void *cb_cls); +void +GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, + struct GNUNET_TESTING_Daemon *d2, + struct GNUNET_TIME_Relative timeout, + unsigned int max_connect_attempts, + int send_hello, + GNUNET_TESTING_NotifyConnection cb, + void *cb_cls); diff --git a/src/include/gnunet_transport_service.h b/src/include/gnunet_transport_service.h index 3ada9a7cd..5d25e7548 100644 --- a/src/include/gnunet_transport_service.h +++ b/src/include/gnunet_transport_service.h @@ -603,15 +603,19 @@ GNUNET_TRANSPORT_get_hello_cancel (struct GNUNET_TRANSPORT_Handle *handle, /** * Offer the transport service the HELLO of another peer. Note that * the transport service may just ignore this message if the HELLO is - * malformed or useless due to our local configuration. If the HELLO - * is working, we should add it to PEERINFO. + * malformed or useless due to our local configuration. * * @param handle connection to transport service * @param hello the hello message + * @param cont continuation to call when HELLO has been sent + * @param cls closure for continuation + * */ void GNUNET_TRANSPORT_offer_hello (struct GNUNET_TRANSPORT_Handle *handle, - const struct GNUNET_MessageHeader *hello); + const struct GNUNET_MessageHeader *hello, + GNUNET_SCHEDULER_Task cont, + void *cls); /** diff --git a/src/testing/test_testing_topology.c b/src/testing/test_testing_topology.c index 5af3e9ed2..b328873f2 100644 --- a/src/testing/test_testing_topology.c +++ b/src/testing/test_testing_topology.c @@ -1027,6 +1027,7 @@ run (void *cls, char *connect_topology_option_str; char *connect_topology_option_modifier_string; unsigned long long temp_settle; + unsigned long long max_outstanding_connections; ok = 1; dotOutFile = fopen (dotOutFileName, "w"); @@ -1152,6 +1153,14 @@ run (void *cls, return; } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "max_outstanding_connections", + &max_outstanding_connections)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", "testing", "max_outstanding_connections"); + return; + } + if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", &num_peers)) @@ -1180,7 +1189,7 @@ run (void *cls, GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); pg = GNUNET_TESTING_daemons_start (cfg, peers_left, - peers_left / 2, + max_outstanding_connections, peers_left, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, diff --git a/src/testing/testing.c b/src/testing/testing.c index ddfe17d43..4a321c6e6 100644 --- a/src/testing/testing.c +++ b/src/testing/testing.c @@ -38,7 +38,7 @@ #include "gnunet_hello_lib.h" #define DEBUG_TESTING GNUNET_NO -#define DEBUG_TESTING_RECONNECT GNUNET_NO +#define DEBUG_TESTING_RECONNECT GNUNET_YES /** * How long do we wait after starting gnunet-service-arm @@ -65,10 +65,19 @@ static void process_hello (void *cls, const struct GNUNET_MessageHeader *message) { struct GNUNET_TESTING_Daemon *daemon = cls; + GNUNET_TESTING_NotifyDaemonRunning cb; + int msize; if (daemon == NULL) return; + GNUNET_assert (daemon->phase == SP_GET_HELLO); + + cb = daemon->cb; + daemon->cb = NULL; + if (daemon->task != GNUNET_SCHEDULER_NO_TASK) /* Assertion here instead? */ + GNUNET_SCHEDULER_cancel(daemon->task); + if (daemon->server != NULL) { #if DEBUG_TESTING @@ -105,9 +114,15 @@ process_hello (void *cls, const struct GNUNET_MessageHeader *message) GNUNET_TRANSPORT_disconnect (daemon->th); daemon->th = NULL; } + daemon->phase = SP_START_DONE; + if (NULL != cb) /* FIXME: what happens when this callback calls GNUNET_TESTING_daemon_stop? */ + cb (daemon->cb_cls, &daemon->id, daemon->cfg, daemon, NULL); } +static void +start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + /** * Function called after GNUNET_CORE_connect has succeeded * (or failed for good). Note that the private key of the @@ -127,12 +142,10 @@ testing_init (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey) { struct GNUNET_TESTING_Daemon *d = cls; - GNUNET_TESTING_NotifyDaemonRunning cb; GNUNET_assert (d->phase == SP_START_CORE); - d->phase = SP_START_DONE; - cb = d->cb; - d->cb = NULL; + d->phase = SP_GET_HELLO; + if (server == NULL) { d->server = NULL; @@ -141,8 +154,8 @@ testing_init (void *cls, GNUNET_TIME_absolute_get_remaining (d->max_timeout), d->dead_cb, d->dead_cb_cls, GNUNET_YES, GNUNET_NO); - else if (NULL != cb) - cb (d->cb_cls, NULL, d->cfg, d, + else if (NULL != d->cb) + d->cb (d->cb_cls, NULL, d->cfg, d, _("Failed to connect to core service\n")); return; } @@ -155,9 +168,6 @@ testing_init (void *cls, d->server = server; d->running = GNUNET_YES; - if (NULL != cb) /* FIXME: what happens when this callback calls GNUNET_TESTING_daemon_stop? */ - cb (d->cb_cls, my_identity, d->cfg, d, NULL); - if (GNUNET_NO == d->running) { #if DEBUG_TESTING @@ -192,6 +202,12 @@ testing_init (void *cls, #endif GNUNET_TRANSPORT_get_hello (d->th, &process_hello, d); + /* wait some more */ + if (d->task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel(d->task); + d->task + = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, + &start_fsm, d); } @@ -551,7 +567,12 @@ start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) (NULL == d->hostname) ? _("`gnunet-arm' does not seem to terminate.\n") : _("`ssh' does not seem to terminate.\n")); + GNUNET_CONFIGURATION_destroy (d->cfg); + GNUNET_free (d->cfgfile); + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); GNUNET_free(d->proc); + GNUNET_free(d); return; } /* wait some more */ @@ -570,18 +591,68 @@ start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Calling CORE_connect\n"); #endif + /* Fall through */ + case SP_START_CORE: + if (d->server != NULL) + GNUNET_CORE_disconnect(d->server); + + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == + 0) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, + NULL, + d->cfg, + d, + _("Unable to connect to CORE service for peer!\n")); + GNUNET_CONFIGURATION_destroy (d->cfg); + GNUNET_free (d->cfgfile); + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + GNUNET_free (d); + return; + } d->server = GNUNET_CORE_connect (d->cfg, 1, -#if NO_MORE_TIMEOUT_FIXME - ARM_START_WAIT, -#endif d, &testing_init, NULL, NULL, NULL, NULL, GNUNET_NO, NULL, GNUNET_NO, no_handlers); + d->task + = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_CONSTANTS_SERVICE_RETRY, 2), + &start_fsm, d); break; - case SP_START_CORE: - GNUNET_break (0); + case SP_GET_HELLO: + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == + 0) + { + if (d->server != NULL) + GNUNET_CORE_disconnect(d->server); + if (d->th != NULL) + GNUNET_TRANSPORT_disconnect(d->th); + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, + NULL, + d->cfg, + d, + _("Unable to get HELLO for peer!\n")); + GNUNET_CONFIGURATION_destroy (d->cfg); + GNUNET_free (d->cfgfile); + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + GNUNET_free (d); + return; + } + if (d->hello != NULL) + return; + GNUNET_assert(d->task == GNUNET_SCHEDULER_NO_TASK); + d->task + = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_CONSTANTS_SERVICE_RETRY, 2), + &start_fsm, d); break; case SP_START_DONE: GNUNET_break (0); @@ -1367,12 +1438,6 @@ struct ConnectContext */ void *cb_cls; - /** - * When should this operation be complete (or we must trigger - * a timeout). - */ - struct GNUNET_TIME_Absolute timeout; - /** * The relative timeout from whence this connect attempt was * started. Allows for reconnect attempts. @@ -1383,7 +1448,7 @@ struct ConnectContext * Maximum number of connect attempts, will retry connection * this number of times on failures. */ - unsigned int max_connect_attempts; + unsigned int connect_attempts; /** * Hello timeout task @@ -1406,6 +1471,11 @@ struct ConnectContext */ int connected; + /** + * When connecting, do we need to send the HELLO? + */ + int send_hello; + /** * The distance between the two connected peers */ @@ -1431,8 +1501,6 @@ notify_connect_result (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ConnectContext *ctx = cls; - struct GNUNET_TIME_Relative remaining; - ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK; if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK) { @@ -1445,6 +1513,7 @@ notify_connect_result (void *cls, GNUNET_CORE_peer_request_connect_cancel (ctx->connect_request_handle); ctx->connect_request_handle = NULL; } + if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) { if (ctx->d1th != NULL) @@ -1458,12 +1527,16 @@ notify_connect_result (void *cls, ctx->d2core = NULL; #endif ctx->d1core = NULL; - GNUNET_free (ctx); return; } - remaining = GNUNET_TIME_absolute_get_remaining (ctx->timeout); + if (ctx->d1th != NULL) + GNUNET_TRANSPORT_disconnect (ctx->d1th); + ctx->d1th = NULL; + if (ctx->d1core != NULL) + GNUNET_CORE_disconnect (ctx->d1core); + ctx->d1core = NULL; if (ctx->connected == GNUNET_YES) { @@ -1476,13 +1549,8 @@ notify_connect_result (void *cls, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, NULL); } } - else if (remaining.rel_value > 0) + else if (ctx->connect_attempts > 0) { - if (ctx->d1core != NULL) - { - GNUNET_CORE_disconnect (ctx->d1core); - ctx->d1core = NULL; - } ctx->d1core_ready = GNUNET_NO; #if CONNECT_CORE2 if (ctx->d2core != NULL) @@ -1491,12 +1559,6 @@ notify_connect_result (void *cls, ctx->d2core = NULL; } #endif - - if (ctx->d1th != NULL) - { - GNUNET_TRANSPORT_disconnect (ctx->d1th); - ctx->d1th = NULL; - } GNUNET_SCHEDULER_add_now (&reattempt_daemons_connect, ctx); return; } @@ -1510,12 +1572,6 @@ notify_connect_result (void *cls, } } - if (ctx->d1th != NULL) - GNUNET_TRANSPORT_disconnect (ctx->d1th); - ctx->d1th = NULL; - if (ctx->d1core != NULL) - GNUNET_CORE_disconnect (ctx->d1core); - ctx->d1core = NULL; GNUNET_free (ctx); } @@ -1535,8 +1591,15 @@ connect_notify (void *cls, { struct ConnectContext *ctx = cls; +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Connected peer %s to peer %s\n", + ctx->d1->shortname, GNUNET_i2s(peer)); +#endif + if (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity))) { + ctx->connected = GNUNET_YES; ctx->distance = 0; /* FIXME: distance */ if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK) @@ -1606,17 +1669,16 @@ send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { hello = GNUNET_HELLO_get_header (ctx->d2->hello); GNUNET_assert (hello != NULL); - GNUNET_TRANSPORT_offer_hello (ctx->d1th, hello); + GNUNET_TRANSPORT_offer_hello (ctx->d1th, hello, NULL, NULL); GNUNET_assert (ctx->d1core != NULL); ctx->connect_request_handle = GNUNET_CORE_peer_request_connect (ctx->d1core, - GNUNET_TIME_relative_divide - (ctx->relative_timeout, - ctx->max_connect_attempts + 1), - &ctx->d2->id, - &core_connect_request_cont, ctx); + ctx->relative_timeout, + &ctx->d2->id, + &core_connect_request_cont, ctx); + #if DEBUG_TESTING - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Sending connect request to CORE of %s for peer %s\n", GNUNET_i2s (&ctx->d1->id), GNUNET_h2s (&ctx->d2->id.hashPubKey)); @@ -1649,6 +1711,88 @@ core_init_notify (void *cls, { struct ConnectContext *connect_ctx = cls; connect_ctx->d1core_ready = GNUNET_YES; + + if (connect_ctx->send_hello == GNUNET_NO) + { + connect_ctx->connect_request_handle = + GNUNET_CORE_peer_request_connect (connect_ctx->d1core, + connect_ctx->relative_timeout, + &connect_ctx->d2->id, + &core_connect_request_cont, connect_ctx); + GNUNET_assert(connect_ctx->connect_request_handle != NULL); +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending connect request to CORE of %s for peer %s\n", + connect_ctx->d1->shortname, + connect_ctx->d2->shortname); +#endif + } + +} + + +static void +reattempt_daemons_connect (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ConnectContext *ctx = cls; + if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) + { + GNUNET_free(ctx); + return; + } +#if DEBUG_TESTING_RECONNECT + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "re-attempting connect of peer %s to peer %s\n", + ctx->d1->shortname, ctx->d2->shortname); +#endif + ctx->connect_attempts--; + GNUNET_assert (ctx->d1core == NULL); + ctx->d1core_ready = GNUNET_NO; + ctx->d1core = GNUNET_CORE_connect (ctx->d1->cfg, 1, + ctx, + &core_init_notify, + &connect_notify, NULL, NULL, + NULL, GNUNET_NO, + NULL, GNUNET_NO, no_handlers); + if (ctx->d1core == NULL) + { + if (NULL != ctx->cb) + ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, + ctx->d2->cfg, ctx->d1, ctx->d2, + _("Failed to connect to core service of first peer!\n")); + GNUNET_free (ctx); + return; + } + + if (ctx->send_hello == GNUNET_YES) + { + ctx->d1th = GNUNET_TRANSPORT_connect (ctx->d1->cfg, + &ctx->d1->id, + ctx->d1, NULL, NULL, NULL); + if (ctx->d1th == NULL) + { + GNUNET_CORE_disconnect (ctx->d1core); + GNUNET_free (ctx); + if (NULL != ctx->cb) + ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, + ctx->d2->cfg, ctx->d1, ctx->d2, + _("Failed to connect to transport service!\n")); + return; + } + ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); + } + else + { + ctx->connect_request_handle = + GNUNET_CORE_peer_request_connect (ctx->d1core, + ctx->relative_timeout, + &ctx->d2->id, + &core_connect_request_cont, ctx); + } + ctx->timeout_task = + GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout, + ¬ify_connect_result, ctx); } /** @@ -1676,7 +1820,7 @@ core_initial_iteration (void *cls, ctx->distance = 0; /* FIXME: distance */ return; } - else if (peer == NULL) /* Peer not already connected, need to schedule connect request! */ + else if (peer == NULL) /* End of iteration over peers */ { if (ctx->connected == GNUNET_YES) { @@ -1685,12 +1829,21 @@ core_initial_iteration (void *cls, return; } - ctx->d1core = GNUNET_CORE_connect (ctx->d1->cfg, 1, - ctx, - &core_init_notify, - &connect_notify, NULL, NULL, - NULL, GNUNET_NO, - NULL, GNUNET_NO, no_handlers); + /* Peer not already connected, need to schedule connect request! */ + if (ctx->d1core == NULL) + { +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peers are NOT connected, connecting to core!\n"); +#endif + ctx->d1core = GNUNET_CORE_connect (ctx->d1->cfg, 1, + ctx, + &core_init_notify, + &connect_notify, NULL, NULL, + NULL, GNUNET_NO, + NULL, GNUNET_NO, no_handlers); + } + if (ctx->d1core == NULL) { GNUNET_free (ctx); @@ -1700,34 +1853,25 @@ core_initial_iteration (void *cls, return; } -#if DEBUG_TESTING > 2 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Asked to connect peer %s to peer %s\n", - ctx->d1->shortname, ctx->d2->shortname); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connecting to transport service of peer %s\n", ctx->d2->shortname); - -#endif - - ctx->d1th = GNUNET_TRANSPORT_connect (ctx->d1->cfg, - &ctx->d1->id, ctx->d1, NULL, NULL, NULL); - if (ctx->d1th == NULL) + if (ctx->send_hello == GNUNET_YES) { - GNUNET_CORE_disconnect (ctx->d1core); - GNUNET_free (ctx); - if (NULL != ctx->cb) - ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, - _("Failed to connect to transport service!\n")); - return; + ctx->d1th = GNUNET_TRANSPORT_connect (ctx->d1->cfg, + &ctx->d1->id, ctx->d1, NULL, NULL, NULL); + if (ctx->d1th == NULL) + { + GNUNET_CORE_disconnect (ctx->d1core); + GNUNET_free (ctx); + if (NULL != ctx->cb) + ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, + _("Failed to connect to transport service!\n")); + return; + } + ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); } ctx->timeout_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide - (ctx->relative_timeout, - ctx->max_connect_attempts), - ¬ify_connect_result, ctx); - - ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); + GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout, + ¬ify_connect_result, ctx); } } @@ -1741,6 +1885,8 @@ core_initial_iteration (void *cls, * allowed to take? * @param max_connect_attempts how many times should we try to reconnect * (within timeout) + * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume + * the HELLO has already been exchanged * @param cb function to call at the end * @param cb_cls closure for cb */ @@ -1749,6 +1895,7 @@ GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, struct GNUNET_TESTING_Daemon *d2, struct GNUNET_TIME_Relative timeout, unsigned int max_connect_attempts, + int send_hello, GNUNET_TESTING_NotifyConnection cb, void *cb_cls) { @@ -1761,17 +1908,18 @@ GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, _("Peers are not fully running yet, can not connect!\n")); return; } + ctx = GNUNET_malloc (sizeof (struct ConnectContext)); ctx->d1 = d1; ctx->d2 = d2; - ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); ctx->timeout_hello = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500); - ctx->relative_timeout = timeout; + ctx->relative_timeout = GNUNET_TIME_relative_divide(timeout, max_connect_attempts); ctx->cb = cb; ctx->cb_cls = cb_cls; - ctx->max_connect_attempts = max_connect_attempts; + ctx->connect_attempts = max_connect_attempts; ctx->connected = GNUNET_NO; + ctx->send_hello = send_hello; #if DEBUG_TESTING GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to connect peer %s to peer %s\n", @@ -1779,66 +1927,8 @@ GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, #endif /* Core is up! Iterate over all _known_ peers first to check if we are already connected to the peer! */ - GNUNET_CORE_is_peer_connected (ctx->d1->cfg, &ctx->d2->id, &core_initial_iteration, ctx); - /* GNUNET_CORE_iterate_peers(ctx->d1->cfg, &core_initial_iteration, ctx); */ - -} - -static void -reattempt_daemons_connect (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - - struct ConnectContext *ctx = cls; - if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) - { - return; - } -#if DEBUG_TESTING_RECONNECT - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "re-attempting connect of peer %s to peer %s\n", - ctx->d1->shortname, ctx->d2->shortname); -#endif - - GNUNET_assert (ctx->d1core == NULL); - ctx->d1core_ready = GNUNET_NO; - ctx->d1core = GNUNET_CORE_connect (ctx->d1->cfg, 1, - ctx, - &core_init_notify, - &connect_notify, NULL, NULL, - NULL, GNUNET_NO, - NULL, GNUNET_NO, no_handlers); - if (ctx->d1core == NULL) - { - if (NULL != ctx->cb) - ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, - ctx->d2->cfg, ctx->d1, ctx->d2, - _("Failed to connect to core service of first peer!\n")); - GNUNET_free (ctx); - return; - } - - ctx->d1th = GNUNET_TRANSPORT_connect (ctx->d1->cfg, - &ctx->d1->id, - ctx->d1, NULL, NULL, NULL); - if (ctx->d1th == NULL) - { - GNUNET_CORE_disconnect (ctx->d1core); - GNUNET_free (ctx); - if (NULL != ctx->cb) - ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, - ctx->d2->cfg, ctx->d1, ctx->d2, - _("Failed to connect to transport service!\n")); - return; - } - - ctx->timeout_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide - (ctx->relative_timeout, - ctx->max_connect_attempts), - ¬ify_connect_result, ctx); - - ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); + GNUNET_assert(GNUNET_OK == GNUNET_CORE_is_peer_connected (ctx->d1->cfg, &ctx->d2->id, &core_initial_iteration, ctx)); + /*GNUNET_assert(GNUNET_OK == GNUNET_CORE_iterate_peers (ctx->d1->cfg, &core_initial_iteration, ctx));*/ } /* end of testing.c */ diff --git a/src/testing/testing_group.c b/src/testing/testing_group.c index fc527efe3..90aad3ca2 100644 --- a/src/testing/testing_group.c +++ b/src/testing/testing_group.c @@ -30,7 +30,7 @@ #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" -#define VERBOSE_TESTING GNUNET_YES +#define VERBOSE_TESTING GNUNET_NO #define VERBOSE_TOPOLOGY GNUNET_YES @@ -38,6 +38,8 @@ #define OLD 1 +#define USE_SEND_HELLOS GNUNET_NO + /** * Lowest port used for GNUnet testing. Should be high enough to not * conflict with other applications running on the hosts but be low @@ -159,6 +161,40 @@ struct RestartContext }; +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; @@ -599,6 +635,46 @@ struct StatsCoreContext 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; +}; + + /** * Handle to a group of GNUnet peers. */ @@ -681,6 +757,11 @@ struct GNUNET_TESTING_PeerGroup */ unsigned int outstanding_connects; + /** + * Number of HELLOs we have yet to send. + */ + unsigned int remaining_hellos; + /** * How many connects have already been scheduled? */ @@ -707,72 +788,59 @@ struct GNUNET_TESTING_PeerGroup * Stop scheduling peers connecting. */ unsigned int stop_connects; -}; - -struct UpdateContext -{ - struct GNUNET_CONFIGURATION_Handle *ret; - const struct GNUNET_CONFIGURATION_Handle *orig; - const char *hostname; - unsigned int nport; - unsigned int upnum; - unsigned int fdnum; -}; - -struct ConnectTopologyContext -{ - /** - * How many connections are left to create. - */ - unsigned int remaining_connections; /** - * How many more connections do we need to schedule? + * Connection context for peer group. */ - unsigned int remaining_connects_to_schedule; + struct ConnectTopologyContext ct_ctx; +}; +struct UpdateContext +{ /** - * Handle to group of peers. + * The altered configuration. */ - struct GNUNET_TESTING_PeerGroup *pg; + struct GNUNET_CONFIGURATION_Handle *ret; /** - * How long to try this connection before timing out. + * The original configuration to alter. */ - struct GNUNET_TIME_Relative connect_timeout; + const struct GNUNET_CONFIGURATION_Handle *orig; /** - * How many times to retry connecting the two peers. + * The hostname that this peer will run on. */ - unsigned int connect_attempts; + const char *hostname; /** - * Temp value set for each iteration. + * The next possible port to assign. */ - //struct PeerData *first; + unsigned int nport; /** - * Notification that all peers are connected. + * Unique number for unix domain sockets. */ - GNUNET_TESTING_NotifyCompletion notify_connections_done; + unsigned int upnum; /** - * Closure for notify. + * Unique number for this peer/host to offset + * things that are grouped by host. */ - void *notify_cls; + unsigned int fdnum; }; + struct ConnectContext { /** - * Peer to connect second to. + * Index of peer to connect second to. */ - struct GNUNET_TESTING_Daemon *first; + uint32_t first_index; /** - * Peer to connect first to. + * Index of peer to connect first to. */ - struct GNUNET_TESTING_Daemon *second; + uint32_t second_index; /** * Higher level topology connection context. @@ -915,6 +983,10 @@ uid_from_hash (const GNUNET_HashCode * hash, uint32_t * uid) } #endif +#if USE_SEND_HELLOS +static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} }; +#endif + /** * Get a topology from a string input. * @@ -1102,25 +1174,34 @@ update_config (void *cls, 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))) { - GNUNET_asprintf (&single_variable, "single_%s_per_host", section); - if ((ival != 0) - && (GNUNET_YES != + 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; } - - GNUNET_free (single_variable); + 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; + } } if (0 == strcmp (option, "UNIXPATH")) { - GNUNET_asprintf (&single_variable, "single_%s_per_host", section); - GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section); if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", single_variable)) @@ -1142,15 +1223,14 @@ update_config (void *cls, section, ctx->fdnum % num_per_host); value = uval; } - GNUNET_free (single_variable); - GNUNET_free (per_host_variable); } if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL)) { value = ctx->hostname; } - + GNUNET_free (single_variable); + GNUNET_free (per_host_variable); GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value); } @@ -1176,13 +1256,13 @@ static struct GNUNET_CONFIGURATION_Handle * make_config (const struct GNUNET_CONFIGURATION_Handle *cfg, uint32_t off, uint16_t * port, - uint32_t * upnum, const char *hostname, uint32_t * fdnum) + uint32_t * upnum, const char *hostname, + uint32_t * fdnum) { struct UpdateContext uc; uint16_t orig; char *control_host; char *allowed_hosts; - unsigned long long temp_port; orig = *port; uc.nport = *port; @@ -1223,16 +1303,6 @@ make_config (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "UNIXPATH", ""); GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "UNIXPATH", ""); - - if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(uc.orig, "statistics", "port", &temp_port) && - (temp_port != 0) && - (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_yesno (uc.orig, "testing", - "single_statistics_per_host"))) - { - GNUNET_CONFIGURATION_set_value_number (uc.ret, "statistics", "port", temp_port + off); - } - GNUNET_free_non_null (control_host); GNUNET_free (allowed_hosts); } @@ -1493,9 +1563,6 @@ add_connections (struct GNUNET_TESTING_PeerGroup *pg, new_first = GNUNET_malloc (sizeof (struct PeerConnection)); new_first->index = second; GNUNET_CONTAINER_DLL_insert(*first_list, *first_tail, new_first); - /* - new_first->next = *first_list; - *first_list = new_first;*/ #else GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (pg-> @@ -1516,10 +1583,6 @@ add_connections (struct GNUNET_TESTING_PeerGroup *pg, new_second = GNUNET_malloc (sizeof (struct PeerConnection)); new_second->index = first; GNUNET_CONTAINER_DLL_insert(*second_list, *second_tail, new_second); - /* - new_second->next = *second_list; - *second_list = new_second; - *second_list */ #else GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (pg-> @@ -2606,7 +2669,8 @@ create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Copying file with command cp %s %s\n"), mytemp, arg); #endif - + ret = GNUNET_OS_process_wait(procarr[pg_iter]); /* FIXME: schedule this, throttle! */ + GNUNET_OS_process_close (procarr[pg_iter]); GNUNET_free (arg); } else /* Remote, scp the file to the correct place */ @@ -2895,33 +2959,402 @@ schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); * * @param ct_ctx the overall connection context */ -static void preschedule_connect(struct ConnectTopologyContext *ct_ctx) +static void preschedule_connect(struct GNUNET_TESTING_PeerGroup *pg) { - struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg; + struct ConnectTopologyContext *ct_ctx = &pg->ct_ctx; struct PeerConnection *connection_iter; struct ConnectContext *connect_context; uint32_t random_peer; - if (ct_ctx->remaining_connects_to_schedule == 0) + if (ct_ctx->remaining_connections == 0) return; random_peer = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, pg->total); while (pg->peers[random_peer].connect_peers_head == NULL) random_peer = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, pg->total); connection_iter = pg->peers[random_peer].connect_peers_head; -#if DEBUG_TESTING - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Scheduling connection between %d and %d\n", random_peer, connection_iter->index); -#endif connect_context = GNUNET_malloc (sizeof (struct ConnectContext)); - connect_context->first = pg->peers[random_peer].daemon; - connect_context->second = pg->peers[connection_iter->index].daemon; + connect_context->first_index = random_peer; + connect_context->second_index = connection_iter->index; connect_context->ct_ctx = ct_ctx; GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); GNUNET_CONTAINER_DLL_remove(pg->peers[random_peer].connect_peers_head, pg->peers[random_peer].connect_peers_tail, connection_iter); - ct_ctx->remaining_connects_to_schedule--; + GNUNET_free(connection_iter); + ct_ctx->remaining_connections--; +} + +#if USE_SEND_HELLOS +/* Forward declaration */ +static void schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Close connections and free the hello context. + * + * @param cls the 'struct SendHelloContext *' + * @param tc scheduler context + */ +static void +free_hello_context (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct SendHelloContext *send_hello_context = cls; + if (send_hello_context->peer->daemon->server != NULL) + { + GNUNET_CORE_disconnect(send_hello_context->peer->daemon->server); + send_hello_context->peer->daemon->server = NULL; + } + if (send_hello_context->peer->daemon->th != NULL) + { + GNUNET_TRANSPORT_disconnect(send_hello_context->peer->daemon->th); + send_hello_context->peer->daemon->th = NULL; + } + if (send_hello_context->core_connect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel(send_hello_context->core_connect_task); + send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK; + } + send_hello_context->pg->outstanding_connects--; + GNUNET_free(send_hello_context); +} + +/** + * For peers that haven't yet connected, notify + * the caller that they have failed (timeout). + * + * @param cls the 'struct SendHelloContext *' + * @param tc scheduler context + */ +static void +notify_remaining_connections_failed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct SendHelloContext *send_hello_context = cls; + struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; + struct PeerConnection *connection; + + GNUNET_CORE_disconnect(send_hello_context->peer->daemon->server); + send_hello_context->peer->daemon->server = NULL; + + connection = send_hello_context->peer->connect_peers_head; + + while (connection != NULL) + { + if (pg->notify_connection != NULL) + { + pg->notify_connection(pg->notify_connection_cls, + &send_hello_context->peer->daemon->id, + &pg->peers[connection->index].daemon->id, + 0, /* FIXME */ + send_hello_context->peer->daemon->cfg, + pg->peers[connection->index].daemon->cfg, + send_hello_context->peer->daemon, + pg->peers[connection->index].daemon, + "Peers failed to connect (timeout)"); + } + GNUNET_CONTAINER_DLL_remove(send_hello_context->peer->connect_peers_head, send_hello_context->peer->connect_peers_tail, connection); + GNUNET_free(connection); + connection = connection->next; + } + GNUNET_SCHEDULER_add_now(&free_hello_context, send_hello_context); +#if BAD + other_peer = &pg->peers[connection->index]; +#endif } +/** + * For peers that haven't yet connected, send + * CORE connect requests. + * + * @param cls the 'struct SendHelloContext *' + * @param tc scheduler context + */ +static void +send_core_connect_requests (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct SendHelloContext *send_hello_context = cls; + struct PeerConnection *conn; + GNUNET_assert(send_hello_context->peer->daemon->server != NULL); + + send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK; + + send_hello_context->connect_attempts++; + if (send_hello_context->connect_attempts < send_hello_context->pg->ct_ctx.connect_attempts) + { + conn = send_hello_context->peer->connect_peers_head; + while (conn != NULL) + { + GNUNET_CORE_peer_request_connect(send_hello_context->peer->daemon->server, + GNUNET_TIME_relative_get_forever(), + &send_hello_context->pg->peers[conn->index].daemon->id, + NULL, + NULL); + conn = conn->next; + } + send_hello_context->core_connect_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_divide(send_hello_context->pg->ct_ctx.connect_timeout, send_hello_context->pg->ct_ctx.connect_attempts) , + &send_core_connect_requests, + send_hello_context); + } + else + { + GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Timeout before all connections created, marking rest as failed!\n"); + GNUNET_SCHEDULER_add_now(¬ify_remaining_connections_failed, send_hello_context); + } + +} + + +/** + * Success, connection is up. Signal client our success. + * + * @param cls our "struct SendHelloContext" + * @param peer identity of the peer that has connected + * @param atsi performance information + * + * FIXME: remove peers from BOTH lists, call notify twice, should + * double the speed of connections as long as the list iteration + * doesn't take too long! + */ +static void +core_connect_notify (void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_TRANSPORT_ATS_Information *atsi) +{ + struct SendHelloContext *send_hello_context = cls; + struct PeerConnection *connection; + struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; +#if BAD + struct PeerData *other_peer; +#endif +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Connected peer %s to peer %s\n", + ctx->d1->shortname, GNUNET_i2s(peer)); +#endif + + if (0 == memcmp(&send_hello_context->peer->daemon->id, peer, sizeof(struct GNUNET_PeerIdentity))) + return; + + connection = send_hello_context->peer->connect_peers_head; +#if BAD + other_peer = NULL; +#endif + + while ((connection != NULL) && + (0 != memcmp(&pg->peers[connection->index].daemon->id, peer, sizeof(struct GNUNET_PeerIdentity)))) + { + connection = connection->next; + } + + if (connection == NULL) + { + GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Connected peer %s to %s, not in list (no problem(?))\n", GNUNET_i2s(peer), send_hello_context->peer->daemon->shortname); + } + else + { +#if BAD + other_peer = &pg->peers[connection->index]; +#endif + if (pg->notify_connection != NULL) + { + pg->notify_connection(pg->notify_connection_cls, + &send_hello_context->peer->daemon->id, + peer, + 0, /* FIXME */ + send_hello_context->peer->daemon->cfg, + pg->peers[connection->index].daemon->cfg, + send_hello_context->peer->daemon, + pg->peers[connection->index].daemon, + NULL); + } + GNUNET_CONTAINER_DLL_remove(send_hello_context->peer->connect_peers_head, send_hello_context->peer->connect_peers_tail, connection); + GNUNET_free(connection); + } + +#if BAD + /* Notify of reverse connection and remove from other peers list of outstanding */ + if (other_peer != NULL) + { + connection = other_peer->connect_peers_head; + while ((connection != NULL) && + (0 != memcmp(&send_hello_context->peer->daemon->id, &pg->peers[connection->index].daemon->id, sizeof(struct GNUNET_PeerIdentity)))) + { + connection = connection->next; + } + if (connection != NULL) + { + if (pg->notify_connection != NULL) + { + pg->notify_connection(pg->notify_connection_cls, + peer, + &send_hello_context->peer->daemon->id, + 0, /* FIXME */ + pg->peers[connection->index].daemon->cfg, + send_hello_context->peer->daemon->cfg, + pg->peers[connection->index].daemon, + send_hello_context->peer->daemon, + NULL); + } + + GNUNET_CONTAINER_DLL_remove(other_peer->connect_peers_head, other_peer->connect_peers_tail, connection); + GNUNET_free(connection); + } + } +#endif + + if (send_hello_context->peer->connect_peers_head == NULL) + { + GNUNET_SCHEDULER_add_now(&free_hello_context, send_hello_context); + } +} + +/** + * Notify of a successful connection to the core service. + * + * @param cls a struct SendHelloContext * + * @param server handle to the core service + * @param my_identity the peer identity of this peer + * @param publicKey the public key of the peer + */ +void +core_init (void *cls, + struct GNUNET_CORE_Handle * server, + const struct GNUNET_PeerIdentity * + my_identity, + const struct + GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * + publicKey) +{ + struct SendHelloContext *send_hello_context = cls; + send_hello_context->core_ready = GNUNET_YES; +} + + +/** + * Function called once a hello has been sent + * to the transport, move on to the next one + * or go away forever. + * + * @param cls the 'struct SendHelloContext *' + * @param tc scheduler context + */ +static void +hello_sent_callback (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct SendHelloContext *send_hello_context = cls; + //unsigned int pg_iter; + if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) + { + GNUNET_free(send_hello_context); + return; + } + + send_hello_context->pg->remaining_hellos--; +#if DEBUG_TESTING + GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Sent HELLO, have %d remaining!\n", send_hello_context->pg->remaining_hellos); +#endif + if (send_hello_context->peer_pos == NULL) /* All HELLOs (for this peer!) have been transmitted! */ + { +#if DEBUG_TESTING + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "All hellos for this peer sent, disconnecting transport!\n"); +#endif + GNUNET_assert(send_hello_context->peer->daemon->th != NULL); + GNUNET_TRANSPORT_disconnect(send_hello_context->peer->daemon->th); + send_hello_context->peer->daemon->th = NULL; + + /*if (send_hello_context->pg->remaining_hellos == 0) + { + for (pg_iter = 0; pg_iter < send_hello_context->pg->max_outstanding_connections; pg_iter++) + { + preschedule_connect(&send_hello_context->pg->ct_ctx); + } + } + */ + GNUNET_assert (send_hello_context->peer->daemon->server == NULL); + send_hello_context->peer->daemon->server = GNUNET_CORE_connect(send_hello_context->peer->cfg, + 1, + send_hello_context, + &core_init, + &core_connect_notify, + NULL, + NULL, + NULL, GNUNET_NO, + NULL, GNUNET_NO, + no_handlers); + + send_hello_context->core_connect_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_divide(send_hello_context->pg->ct_ctx.connect_timeout, send_hello_context->pg->ct_ctx.connect_attempts), + &send_core_connect_requests, + send_hello_context); + } + else + GNUNET_SCHEDULER_add_now(&schedule_send_hellos, send_hello_context); +} + + +/** + * Connect to a peer, give it all the HELLO's of those peers + * we will later ask it to connect to. + * + * @param ct_ctx the overall connection context + */ +static void schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct SendHelloContext *send_hello_context = cls; + struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; + + if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) + { + GNUNET_free(send_hello_context); + return; + } + + GNUNET_assert(send_hello_context->peer_pos != NULL); /* All of the HELLO sends to be scheduled have been scheduled! */ + + if (((send_hello_context->peer->daemon->th == NULL) && + (pg->outstanding_connects > pg->max_outstanding_connections)) || + (pg->stop_connects == GNUNET_YES)) + { +#if VERBOSE_TESTING > 2 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _ + ("Delaying connect, we have too many outstanding connections!\n")); +#endif + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_send_hellos, send_hello_context); + } + else + { +#if VERBOSE_TESTING > 2 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Creating connection, outstanding_connections is %d\n"), + outstanding_connects); +#endif + if (send_hello_context->peer->daemon->th == NULL) + { + pg->outstanding_connects++; /* Actual TRANSPORT, CORE connections! */ + send_hello_context->peer->daemon->th = GNUNET_TRANSPORT_connect(send_hello_context->peer->cfg, + NULL, + send_hello_context, + NULL, + NULL, + NULL); + } +#if DEBUG_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Offering Hello of peer %s to peer %s\n"), + send_hello_context->peer->daemon->shortname, pg->peers[send_hello_context->peer_pos->index].daemon->shortname); +#endif + GNUNET_TRANSPORT_offer_hello(send_hello_context->peer->daemon->th, + (const struct GNUNET_MessageHeader *)pg->peers[send_hello_context->peer_pos->index].daemon->hello, + &hello_sent_callback, + send_hello_context); + send_hello_context->peer_pos = send_hello_context->peer_pos->next; + GNUNET_assert(send_hello_context->peer->daemon->th != NULL); + } +} +#endif + + /** * Internal notification of a connection, kept so that we can ensure some connections * happen instead of flooding all testing daemons with requests to connect. @@ -2937,23 +3370,54 @@ internal_connect_notify (void *cls, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { - struct ConnectTopologyContext *ct_ctx = cls; + struct ConnectContext *connect_ctx = cls; + struct ConnectTopologyContext *ct_ctx = connect_ctx->ct_ctx; struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg; + struct PeerConnection *connection; pg->outstanding_connects--; - ct_ctx->remaining_connections--; + + /* + * Check whether the inverse connection has been scheduled yet, + * if not, we can remove it from the other peers list and avoid + * even trying to connect them again! + */ + connection = pg->peers[connect_ctx->second_index].connect_peers_head; +#if BAD + other_peer = NULL; +#endif + + while ((connection != NULL) && + (0 != memcmp(first, &pg->peers[connection->index].daemon->id, sizeof(struct GNUNET_PeerIdentity)))) + { + connection = connection->next; + } + + if (connection != NULL) /* Can safely remove! */ + { + ct_ctx->remaining_connections--; + if (pg->notify_connection != NULL) /* Notify of reverse connection */ + pg->notify_connection (pg->notify_connection_cls, second, first, distance, + second_cfg, first_cfg, second_daemon, first_daemon, + emsg); + + GNUNET_CONTAINER_DLL_remove(pg->peers[connect_ctx->second_index].connect_peers_head, pg->peers[connect_ctx->second_index].connect_peers_tail, connection); + GNUNET_free(connection); + } + if (ct_ctx->remaining_connections == 0) { if (ct_ctx->notify_connections_done != NULL) ct_ctx->notify_connections_done (ct_ctx->notify_cls, NULL); - GNUNET_free (ct_ctx); } else - preschedule_connect(ct_ctx); + preschedule_connect(pg); if (pg->notify_connection != NULL) pg->notify_connection (pg->notify_connection_cls, first, second, distance, first_cfg, second_cfg, first_daemon, second_daemon, emsg); + + GNUNET_free(connect_ctx); } @@ -2975,8 +3439,8 @@ schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) if ((pg->outstanding_connects > pg->max_outstanding_connections) || (pg->stop_connects == GNUNET_YES)) { -#if VERBOSE_TESTING > 2 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Delaying connect, we have too many outstanding connections!\n")); #endif @@ -2986,20 +3450,24 @@ schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) } else { -#if VERBOSE_TESTING > 2 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Creating connection, outstanding_connections is %d\n"), - outstanding_connects); +#if VERBOSE_TESTING + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Creating connection, outstanding_connections is %d (max %d)\n"), + pg->outstanding_connects, pg->max_outstanding_connections); #endif pg->outstanding_connects++; pg->total_connects_scheduled++; - GNUNET_TESTING_daemons_connect (connect_context->first, - connect_context->second, + GNUNET_TESTING_daemons_connect (pg->peers[connect_context->first_index].daemon, + pg->peers[connect_context->second_index].daemon, connect_context->ct_ctx->connect_timeout, connect_context->ct_ctx->connect_attempts, +#if USE_SEND_HELLOS + GNUNET_NO, +#else + GNUNET_YES, +#endif &internal_connect_notify, - connect_context->ct_ctx); - GNUNET_free (connect_context); + connect_context); /* FIXME: free connect context! */ } } @@ -3123,16 +3591,18 @@ connect_topology (struct GNUNET_TESTING_PeerGroup *pg, { unsigned int pg_iter; unsigned int total; - struct ConnectTopologyContext *ct_ctx; + #if OLD struct PeerConnection *connection_iter; #endif +#if USE_SEND_HELLOS + struct SendHelloContext *send_hello_context +#endif total = 0; - ct_ctx = GNUNET_malloc (sizeof (struct ConnectTopologyContext)); - ct_ctx->notify_connections_done = notify_callback; - ct_ctx->notify_cls = notify_cls; - ct_ctx->pg = pg; + pg->ct_ctx.notify_connections_done = notify_callback; + pg->ct_ctx.notify_cls = notify_cls; + pg->ct_ctx.pg = pg; for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { @@ -3150,19 +3620,29 @@ connect_topology (struct GNUNET_TESTING_PeerGroup *pg, } if (total == 0) + return total; + + pg->ct_ctx.connect_timeout = connect_timeout; + pg->ct_ctx.connect_attempts = connect_attempts; + pg->ct_ctx.remaining_connections = total; + +#if USE_SEND_HELLOS + /* First give all peers the HELLO's of other peers (connect to first peer's transport service, give HELLO's of other peers, continue...) */ + pg->remaining_hellos = total; + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { - GNUNET_free (ct_ctx); - return total; + send_hello_context = GNUNET_malloc(sizeof(struct SendHelloContext)); + send_hello_context->peer = &pg->peers[pg_iter]; + send_hello_context->peer_pos = pg->peers[pg_iter].connect_peers_head; + send_hello_context->pg = pg; + GNUNET_SCHEDULER_add_now(&schedule_send_hellos, send_hello_context); } - ct_ctx->connect_timeout = connect_timeout; - ct_ctx->connect_attempts = connect_attempts; - ct_ctx->remaining_connections = total; - ct_ctx->remaining_connects_to_schedule = total; - +#else for (pg_iter = 0; pg_iter < pg->max_outstanding_connections; pg_iter++) - { - preschedule_connect(ct_ctx); - } + { + preschedule_connect(pg); + } +#endif return total; } diff --git a/src/topology/gnunet-daemon-topology.c b/src/topology/gnunet-daemon-topology.c index 0eb6869e8..1441e218a 100644 --- a/src/topology/gnunet-daemon-topology.c +++ b/src/topology/gnunet-daemon-topology.c @@ -1230,7 +1230,7 @@ handle_encrypted_hello (void *cls, } if (transport != NULL) GNUNET_TRANSPORT_offer_hello (transport, - message); + message, NULL, NULL); return GNUNET_OK; } diff --git a/src/util/client.c b/src/util/client.c index 681e53971..b1c92b3a6 100644 --- a/src/util/client.c +++ b/src/util/client.c @@ -304,6 +304,7 @@ do_connect (const char *service_name, #if DEBUG_CLIENT GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connected to unixpath `%s'!\n", unixpath); #endif + GNUNET_free(unixpath); return sock; } } -- 2.25.1