From: Nathan S. Evans Date: Sat, 16 Jul 2011 11:11:40 +0000 (+0000) Subject: nse updates X-Git-Tag: initial-import-from-subversion-38251~17810 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=41479de2a35d2c73cf1f6357af37e8324122e90e;p=oweals%2Fgnunet.git nse updates --- diff --git a/src/nse/Makefile.am b/src/nse/Makefile.am index fa9d43f4d..a13d6d8b1 100644 --- a/src/nse/Makefile.am +++ b/src/nse/Makefile.am @@ -40,13 +40,15 @@ gnunet_service_nse_LDADD = \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ -lm \ $(GN_LIBINTL) gnunet_service_nse_DEPENDENCIES = \ libgnunetnse.la check_PROGRAMS = \ - test_nse_api + test_nse_api \ + test_nse_multipeer if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) $(check_SCRIPTS) @@ -58,9 +60,15 @@ test_nse_api_LDADD = \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la +test_nse_multipeer_SOURCES = \ + test_nse_multipeer.c +test_nse_multipeer_LDADD = \ + $(top_builddir)/src/nse/libgnunetnse.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/testing/libgnunettesting.la EXTRA_DIST = \ - test_nse_api_data.conf \ + test_nse.conf \ $(check_SCRIPTS) diff --git a/src/nse/gnunet-service-nse.c b/src/nse/gnunet-service-nse.c index 50ec9a013..90fc680d3 100644 --- a/src/nse/gnunet-service-nse.c +++ b/src/nse/gnunet-service-nse.c @@ -1,22 +1,22 @@ /* - This file is part of GNUnet. - (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ /** * @file nse/gnunet-service-nse.c @@ -44,16 +44,17 @@ #include "gnunet_signatures.h" #include "gnunet_service_lib.h" #include "gnunet_server_lib.h" +#include "gnunet_statistics_service.h" #include "gnunet_core_service.h" #include "gnunet_time_lib.h" #include "gnunet_nse_service.h" #include "nse.h" -#define DEFAULT_HISTORY_SIZE 10 +#define DEFAULT_HISTORY_SIZE 50 #define DEFAULT_CORE_QUEUE_SIZE 32 -#define DEFAULT_NSE_PRIORITY 0 +#define DEFAULT_NSE_PRIORITY 5 /** * Entry in the list of clients which @@ -114,6 +115,11 @@ struct NSEPeerEntry */ static const struct GNUNET_CONFIGURATION_Handle *cfg; +/** + * Handle to the statistics service. + */ +static struct GNUNET_STATISTICS_Handle *stats; + /** * Handle to the core service. */ @@ -161,7 +167,8 @@ static unsigned int size_estimates[DEFAULT_HISTORY_SIZE]; /** * Array of size estimate messages. */ -static struct GNUNET_NSE_FloodMessage size_estimate_messages[DEFAULT_HISTORY_SIZE]; +static struct GNUNET_NSE_FloodMessage + size_estimate_messages[DEFAULT_HISTORY_SIZE]; /** * Index of most recent estimate. @@ -234,22 +241,21 @@ static struct GNUNET_NSE_FloodMessage flood_message; * @param message the message received */ static void -handle_start_message (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) +handle_start_message(void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) { if ((ntohs (message->size) != sizeof(struct GNUNET_MessageHeader)) || (ntohs (message->type) != GNUNET_MESSAGE_TYPE_NSE_START)) return; #if DEBUG_NSE - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "NSE", "Received START message from client\n"); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "NSE", + "Received START message from client\n"); #endif GNUNET_SERVER_notification_context_add (nc, client); - GNUNET_SERVER_receive_done(client, GNUNET_OK); + GNUNET_SERVER_receive_done (client, GNUNET_OK); } - /** * Called when core is ready to send a message we asked for * out to the destination. @@ -260,23 +266,41 @@ handle_start_message (void *cls, * @return number of bytes written to buf */ static size_t -transmit_ready (void *cls, size_t size, void *buf) +transmit_ready(void *cls, size_t size, void *buf) { struct NSEPeerEntry *peer_entry = cls; char *cbuf = buf; size_t msize; peer_entry->th = NULL; +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: transmit_ready called\n", + GNUNET_i2s (&my_identity)); +#endif if (buf == NULL) /* client disconnected */ - return 0; + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: transmit_ready called (disconnect)\n", + GNUNET_i2s (&my_identity)); + return 0; + } if (peer_entry->pending_message == NULL) - return 0; + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: transmit_ready called (no message)\n", + GNUNET_i2s (&my_identity)); + return 0; + } - msize = ntohs(peer_entry->pending_message->size); + msize = ntohs (peer_entry->pending_message->size); if (msize <= size) - memcpy(cbuf, peer_entry->pending_message, msize); - + memcpy (cbuf, peer_entry->pending_message, msize); +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: transmit_ready called (transmit %d bytes)\n", + GNUNET_i2s (&my_identity), msize); +#endif return msize; } @@ -288,35 +312,82 @@ transmit_ready (void *cls, size_t size, void *buf) * * @param message the network flood message */ -static void update_network_size_estimate(struct GNUNET_NSE_FloodMessage *message) +static void +update_network_size_estimate(struct GNUNET_NSE_FloodMessage *message) { unsigned int i; unsigned int count; double average; + double std_dev; + double diff; - size_estimates[estimate_index] = htons(message->distance); - memcpy(&size_estimate_messages[estimate_index], message, sizeof(struct GNUNET_NSE_FloodMessage)); + size_estimates[estimate_index] = htonl (message->distance); + memcpy (&size_estimate_messages[estimate_index], message, + sizeof(struct GNUNET_NSE_FloodMessage)); count = 0; + std_dev = 0.0; + average = 0.0; for (i = 0; i < DEFAULT_HISTORY_SIZE; i++) { if (size_estimate_messages[i].distance != 0) { - average += 1 << htons(size_estimate_messages[i].distance); +#if AVERAGE_SQUARE + average += (1 << htonl (size_estimate_messages[i].distance)); +#else + average += htonl (size_estimate_messages[i].distance); +#endif count++; } } - average /= (double)count; - current_estimate_message.size_estimate = average; - /* Finally, broadcast the current estimate to all clients */ - GNUNET_SERVER_notification_context_broadcast (nc, - ¤t_estimate_message.header, - GNUNET_NO); + + if (count > 0) + { + average /= (double) count; + for (i = 0; i < DEFAULT_HISTORY_SIZE; i++) + { + if (size_estimate_messages[i].distance != 0) + { +#if DEBUG_NSE + GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%s: estimate %d %d\n", GNUNET_i2s(&my_identity), i, (1 << htonl(size_estimate_messages[i].distance))); +#endif +#if AVERAGE_SQUARE + diff = average + - (1 << htonl (size_estimate_messages[i].distance)); +#else + diff = average - htonl (size_estimate_messages[i].distance); +#endif + std_dev += diff * diff; + } + } + std_dev /= count; + std_dev = sqrt (std_dev); + current_estimate_message.header.size + = htons (sizeof(struct GNUNET_NSE_ClientMessage)); + current_estimate_message.header.type + = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE); + current_estimate_message.size_estimate = average; + current_estimate_message.std_deviation = std_dev; + /* Finally, broadcast the current estimate to all clients */ +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: sending estimate %f -- %f to client\n", + GNUNET_i2s (&my_identity), + average, + std_dev); +#endif + GNUNET_SERVER_notification_context_broadcast ( + nc, + ¤t_estimate_message.header, + GNUNET_NO); + + GNUNET_STATISTICS_set (stats, "Current network size estimate", + (uint64_t) average, GNUNET_NO); + } } static void -send_flood_message (void *cls, - const struct GNUNET_SCHEDULER_TaskContext * tc); +send_flood_message(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc); /** * Schedule a flood message to be sent. @@ -332,13 +403,11 @@ send_flood_message (void *cls, * always be a message scheduled to be sent. */ static void -schedule_flood_message (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +schedule_flood_message(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_HashCode timestamp_hash; struct GNUNET_TIME_Absolute curr_time; struct GNUNET_TIME_Relative offset; - struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; unsigned int matching_bits; double millisecond_offset; @@ -348,29 +417,46 @@ schedule_flood_message (void *cls, GNUNET_assert(flood_task == GNUNET_SCHEDULER_NO_TASK); - if (0 != GNUNET_TIME_absolute_get_remaining(next_timestamp).rel_value) + if (0 != GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value) { GNUNET_break(0); /* Shouldn't ever happen! */ - schedule_flood_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining(next_timestamp), &schedule_flood_message, NULL); + schedule_flood_task + = GNUNET_SCHEDULER_add_delayed ( + GNUNET_TIME_absolute_get_remaining ( + next_timestamp), + &schedule_flood_message, NULL); } /* Get the current UTC time */ - curr_time = GNUNET_TIME_absolute_get(); + curr_time = GNUNET_TIME_absolute_get (); /* Find the previous interval start time */ - previous_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL) * GNUNET_NSE_INTERVAL; + previous_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL) + * GNUNET_NSE_INTERVAL; /* Find the next interval start time */ - next_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL) * (GNUNET_NSE_INTERVAL + 1); - - GNUNET_CRYPTO_hash(&next_timestamp.abs_value, sizeof(uint64_t), ×tamp_hash); - matching_bits = GNUNET_CRYPTO_hash_matching_bits(×tamp_hash, &my_identity.hashPubKey); - - flood_message.timestamp = GNUNET_TIME_absolute_hton(next_timestamp); - flood_message.distance = htons(matching_bits); - flood_message.enc_type = htons(0); - flood_message.proof_of_work = htonl(0); - purpose.purpose = GNUNET_SIGNATURE_PURPOSE_NSE_SEND; - purpose.size = sizeof(struct GNUNET_NSE_FloodMessage) - sizeof(struct GNUNET_MessageHeader) - sizeof(flood_message.proof_of_work) - sizeof(flood_message.signature); - GNUNET_CRYPTO_rsa_sign(my_private_key, &purpose, &flood_message.signature); + next_timestamp.abs_value = previous_timestamp.abs_value + GNUNET_NSE_INTERVAL; +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: curr_time %lu, prev timestamp %lu, next timestamp %lu\n", + GNUNET_i2s (&my_identity), curr_time.abs_value, + previous_timestamp.abs_value, next_timestamp.abs_value); +#endif + GNUNET_CRYPTO_hash (&next_timestamp.abs_value, + sizeof(next_timestamp.abs_value), ×tamp_hash); + matching_bits = GNUNET_CRYPTO_hash_matching_bits (×tamp_hash, + &my_identity.hashPubKey); + + flood_message.header.size = htons (sizeof(struct GNUNET_NSE_FloodMessage)); + flood_message.header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD); + flood_message.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND); + flood_message.purpose.size = htonl (sizeof(struct GNUNET_NSE_FloodMessage) + - sizeof(struct GNUNET_MessageHeader) - sizeof(flood_message.signature)); + flood_message.distance = htonl (matching_bits); + flood_message.timestamp = GNUNET_TIME_absolute_hton (next_timestamp); + memcpy (&flood_message.pkey, &my_public_key, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + flood_message.proof_of_work = htonl (0); + GNUNET_CRYPTO_rsa_sign (my_private_key, &flood_message.purpose, + &flood_message.signature); /*S + f/2 - (f / pi) * (atan(x - p'))*/ @@ -378,21 +464,135 @@ schedule_flood_message (void *cls, // f is frequency (GNUNET_NSE_INTERVAL) // x is matching_bits // p' is current_size_estimate - millisecond_offset = ((double)GNUNET_NSE_INTERVAL / (double)2) - ((GNUNET_NSE_INTERVAL / M_PI) * atan(matching_bits - current_size_estimate)); - - fprintf(stderr, "my id matches %d bits, offset is %lu\n", matching_bits, (uint64_t)millisecond_offset); - - estimate_index += 1; + millisecond_offset = ((double) GNUNET_NSE_INTERVAL / (double) 2) + - ((GNUNET_NSE_INTERVAL / M_PI) * atan (matching_bits + - current_size_estimate)); +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: id matches %d bits, offset is %lu\n\n", + GNUNET_i2s (&my_identity), matching_bits, + (uint64_t) millisecond_offset); +#endif + /* Stop initial call from incrementing */ + if (size_estimate_messages[estimate_index].distance != 0) + estimate_index += 1; if (estimate_index >= DEFAULT_HISTORY_SIZE) estimate_index = 0; - offset.rel_value = (uint64_t)millisecond_offset + GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value; - flood_task = GNUNET_SCHEDULER_add_delayed (offset, - &send_flood_message, NULL); + if (millisecond_offset < curr_time.abs_value - previous_timestamp.abs_value) + offset.rel_value = 0; + else + offset.rel_value = (uint64_t) millisecond_offset + curr_time.abs_value + - previous_timestamp.abs_value; +#if DEBUG_NSE + GNUNET_log ( + GNUNET_ERROR_TYPE_WARNING, + "%s: milliseconds until next timestamp %lu, sending flood in %lu\n", + GNUNET_i2s (&my_identity), + GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value, + offset.rel_value); +#endif + flood_task = GNUNET_SCHEDULER_add_delayed (offset, &send_flood_message, NULL); } +#if VERIFY_CRYPTO +/** + * Check whether the given public key + * and integer are a valid proof of work. + * + * @param pkey the public key + * @param val the integer + * @param want the number of trailing zeroes + * + * @return GNUNET_YES if valid, GNUNET_NO if not + */ +static int check_proof_of_work(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey, uint64_t val, unsigned int want) + { + + return GNUNET_YES; + } + +/** + * Count the trailing zeroes in hash. + * + * @param hash + * + * @return the number of trailing zero bits. + */ +static unsigned int count_trailing_zeroes(GNUNET_HashCode *hash) + { + unsigned int hash_count; + + hash_count = sizeof(GNUNET_HashCode) * 8; + while ((0 == GNUNET_CRYPTO_hash_get_bit(hash, hash_count))) + hash_count--; + return (sizeof(GNUNET_HashCode) * 8) - hash_count; + } + +/** + * Given a public key, find an integer such that + * the hash of the key concatenated with the integer + * has want trailing 0 bits. + * + * @param pkey the public key + * @param want the number of trailing 0 bits + * + * @return 64 bit number that satisfies the + * requirements + * + * FIXME: use pointer and return GNUNET_YES or + * GNUNET_NO in case no such number works? + */ +static uint64_t find_proof_of_work(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey, unsigned int want) + { + uint64_t counter; + static char buf[sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof(uint64_t)]; + unsigned int data_size; + static GNUNET_HashCode result; + + data_size = sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof(uint64_t); + memcpy(buf, pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + counter = 0; + while (counter != (uint64_t)-1) + { + memcpy(&buf[sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)], &counter, sizeof(uint64_t)); + GNUNET_CRYPTO_hash(buf, data_size, &result); + if (want == count_trailing_zeroes(&result)) /* Found good proof of work! */ + break; + counter++; + } + if (counter < (uint64_t)-1) + return counter; /* Found valid proof of work */ + else + return 0; /* Did not find valid proof of work */ + } + +/** + * An incoming flood message has been received which claims + * to have more bits matching than any we know in this time + * period. Verify the signature and/or proof of work. + * + * @param incoming_flood the message to verify + * + * @return GNUNET_YES if the message is verified + * GNUNET_NO if the key/signature don't verify + */ +static int verify_message_crypto(struct GNUNET_NSE_FloodMessage *incoming_flood) + { + int ret; + if (GNUNET_OK == (ret + = GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND, + &incoming_flood->purpose, + &incoming_flood->signature, + &incoming_flood->pkey))) + return GNUNET_YES; + + return GNUNET_NO; + } +#endif + /** * Core handler for size estimate flooding messages. * @@ -408,20 +608,89 @@ handle_p2p_size_estimate(void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_TRANSPORT_ATS_Information *atsi) { struct GNUNET_NSE_FloodMessage *incoming_flood; + struct GNUNET_TIME_Absolute curr_time; + uint64_t drift; - if (ntohs(message->size) != sizeof(struct GNUNET_NSE_FloodMessage)) - return GNUNET_NO; +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: received flood message!\n", + GNUNET_i2s (&my_identity)); +#endif + if (ntohs (message->size) != sizeof(struct GNUNET_NSE_FloodMessage)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: bad message size!\n", + GNUNET_i2s (&my_identity)); + return GNUNET_NO; + } - incoming_flood = (struct GNUNET_NSE_FloodMessage *)message; - if (ntohs(incoming_flood->distance) <= ntohs(size_estimate_messages[estimate_index].distance)) /* Not closer than our most recent message */ - return GNUNET_OK; + GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO); + incoming_flood = (struct GNUNET_NSE_FloodMessage *) message; + if (ntohl (incoming_flood->distance) + <= ntohl (size_estimate_messages[estimate_index].distance)) /* Not closer than our most recent message */ + { +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: distance %d not greater than %d, discarding\n", + GNUNET_i2s (&my_identity), ntohl (incoming_flood->distance), + ntohl (size_estimate_messages[estimate_index].distance)); +#endif + GNUNET_STATISTICS_update (stats, + "# flood messages discarded (had closer)", 1, + GNUNET_NO); + return GNUNET_OK; + } + + curr_time = GNUNET_TIME_absolute_get (); + if (curr_time.abs_value + > GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value) + drift = curr_time.abs_value + - GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value; + else + drift = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value + - curr_time.abs_value; + + if (drift > GNUNET_NSE_DRIFT_TOLERANCE) + { + GNUNET_STATISTICS_update ( + stats, + "# flood messages discarded (clock skew too high)", + 1, GNUNET_NO); + return GNUNET_OK; + } + +#if VERIFY_CRYPTO + if (GNUNET_YES != verify_message_crypto(incoming_flood)) + { + GNUNET_STATISTICS_update (stats, + "# flood messages discarded (bad crypto)", + 1, GNUNET_NO); + return GNUNET_OK; + } +#endif /* Have a new, better size estimate! */ - update_network_size_estimate(incoming_flood); + update_network_size_estimate (incoming_flood); + + if (flood_task != GNUNET_SCHEDULER_NO_TASK) + { +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: received closer message, canceling my flood task!\n", GNUNET_i2s(&my_identity)); +#endif + GNUNET_SCHEDULER_cancel (flood_task); + flood_task = GNUNET_SCHEDULER_NO_TASK; + } + /** Commenting out prevents forwarding of messages */ +#if DO_FORWARD + GNUNET_SCHEDULER_add_now(&send_flood_message, &size_estimate_messages[estimate_index]); +#endif if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel(schedule_flood_task); - schedule_flood_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining(next_timestamp), &schedule_flood_message, NULL); + GNUNET_SCHEDULER_cancel (schedule_flood_task); + + schedule_flood_task + = GNUNET_SCHEDULER_add_delayed ( + GNUNET_TIME_absolute_get_remaining ( + next_timestamp), + &schedule_flood_message, NULL); return GNUNET_OK; } @@ -429,39 +698,80 @@ handle_p2p_size_estimate(void *cls, const struct GNUNET_PeerIdentity *peer, /** * Send a flood message. * - * If we've gotten here, it means we haven't received - * a network size estimate message closer than ours. + * If we've gotten here, it means either we haven't received + * a network size estimate message closer than ours, or + * we need to forward a message we received which was closer + * than ours. */ static void -send_flood_message (void *cls, - const struct GNUNET_SCHEDULER_TaskContext * tc) +send_flood_message(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) { struct NSEPeerEntry *peer_entry; + struct GNUNET_NSE_FloodMessage *to_send; + + if (cls == NULL) /* Means we are sending our OWN flood message */ + to_send = &flood_message; + else + /* Received a message from another peer that should be forwarded */ + to_send = (struct GNUNET_NSE_FloodMessage *) cls; flood_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; - +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: my time has come, sending flood message of size %d!\n", + GNUNET_i2s (&my_identity), ntohs (to_send->header.size)); +#endif peer_entry = peers_head; while (peer_entry != NULL) { + peer_entry->pending_message = &to_send->header; peer_entry->th - = GNUNET_CORE_notify_transmit_ready (coreAPI, - GNUNET_YES, + = GNUNET_CORE_notify_transmit_ready ( + coreAPI, + GNUNET_NO, DEFAULT_NSE_PRIORITY, GNUNET_TIME_absolute_get_remaining ( next_timestamp), &peer_entry->id, - ntohs (flood_message.header.size), + ntohs (to_send->header.size), &transmit_ready, peer_entry); + if (peer_entry->th == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: transmit handle is null!\n", GNUNET_i2s (&my_identity)); +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: Sending flood message (distance %d) to %s!\n", + GNUNET_i2s (&my_identity), ntohl (to_send->distance), + GNUNET_h2s (&peer_entry->id.hashPubKey)); +#endif peer_entry = peer_entry->next; } - update_network_size_estimate(&flood_message); + if (cls == NULL) /* Need to update our size estimate */ + { + update_network_size_estimate (to_send); + GNUNET_STATISTICS_update (stats, "# flood messages sent", 1, GNUNET_NO); + } + else + GNUNET_STATISTICS_update (stats, "# flood messages forwarded", 1, GNUNET_NO); + +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "%s: scheduling schedule_flood_message in %lu\n", + GNUNET_i2s (&my_identity), + GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value); +#endif if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel(schedule_flood_task); - schedule_flood_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining(next_timestamp), &schedule_flood_message, NULL); + GNUNET_SCHEDULER_cancel (schedule_flood_task); + + schedule_flood_task + = GNUNET_SCHEDULER_add_delayed ( + GNUNET_TIME_absolute_get_remaining ( + next_timestamp), + &schedule_flood_message, NULL); } /** @@ -472,18 +782,19 @@ send_flood_message (void *cls, * @param atsi performance data */ static void -handle_core_connect (void *cls, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_TRANSPORT_ATS_Information *atsi) +handle_core_connect(void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_TRANSPORT_ATS_Information *atsi) { struct NSEPeerEntry *peer_entry; + if (0 == (memcmp (peer, &my_identity, sizeof(struct GNUNET_PeerIdentity)))) + return; /* Do not connect to self... */ + peer_entry = GNUNET_malloc(sizeof(struct NSEPeerEntry)); - memcpy(&peer_entry->id, peer, sizeof(struct GNUNET_PeerIdentity)); + memcpy (&peer_entry->id, peer, sizeof(struct GNUNET_PeerIdentity)); GNUNET_CONTAINER_DLL_insert(peers_head, peers_tail, peer_entry); } - /** * Method called whenever a peer disconnects. * @@ -491,30 +802,37 @@ handle_core_connect (void *cls, * @param peer peer identity this notification is about */ static void -handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) +handle_core_disconnect(void *cls, const struct GNUNET_PeerIdentity *peer) { struct NSEPeerEntry *pos; + if (0 == (memcmp (peer, &my_identity, sizeof(struct GNUNET_PeerIdentity)))) + return; /* Ignore disconnect from self... */ + pos = peers_head; - while ((NULL != pos) && (0 != memcmp(&pos->id, peer, sizeof(struct GNUNET_PeerIdentity)))) + while ((NULL != pos) && (0 != memcmp (&pos->id, peer, + sizeof(struct GNUNET_PeerIdentity)))) pos = pos->next; if (pos == NULL) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Received disconnect before connect!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Received disconnect before connect!\n"); GNUNET_break(0); /* Should never receive a disconnect message for a peer we don't know about... */ return; } + /* TODO: decide whether to copy the message, or always use the static pointer */ +#if TODO if (pos->pending_message != NULL) - GNUNET_free(pos->pending_message); + GNUNET_free(pos->pending_message); +#endif if (pos->th != NULL) - GNUNET_CORE_notify_transmit_ready_cancel(pos->th); + GNUNET_CORE_notify_transmit_ready_cancel (pos->th); GNUNET_CONTAINER_DLL_remove(peers_head, peers_tail, pos); GNUNET_free(pos); } - /** * A client disconnected. Remove it from the * global DLL of clients. @@ -523,8 +841,7 @@ handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) * @param client identification of the client */ static void -handle_client_disconnect (void *cls, - struct GNUNET_SERVER_Client* client) +handle_client_disconnect(void *cls, struct GNUNET_SERVER_Client* client) { struct ClientListEntry *cle; @@ -533,15 +850,15 @@ handle_client_disconnect (void *cls, if (cle != NULL) { - GNUNET_SERVER_client_drop(cle->client); + GNUNET_SERVER_client_drop (cle->client); GNUNET_CONTAINER_DLL_remove(cle_head, - cle_tail, - cle); + cle_tail, + cle); GNUNET_free(cle); } if (coreAPI != NULL) { - GNUNET_CORE_disconnect(coreAPI); + GNUNET_CORE_disconnect (coreAPI); coreAPI = NULL; } } @@ -553,32 +870,33 @@ handle_client_disconnect (void *cls, * @param tc unused */ static void -shutdown_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +shutdown_task(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ClientListEntry *cle; if (flood_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel(flood_task); + GNUNET_SCHEDULER_cancel (flood_task); GNUNET_SERVER_notification_context_destroy (nc); nc = NULL; while (NULL != (cle = cle_head)) { GNUNET_SERVER_client_drop (cle->client); GNUNET_CONTAINER_DLL_remove (cle_head, - cle_tail, - cle); + cle_tail, + cle); GNUNET_free (cle); } if (coreAPI != NULL) { - GNUNET_CORE_disconnect(coreAPI); + GNUNET_CORE_disconnect (coreAPI); coreAPI = NULL; } -} + if (stats != NULL) + GNUNET_STATISTICS_destroy (stats, GNUNET_NO); +} /** * Called on core init/fail. @@ -589,42 +907,54 @@ shutdown_task (void *cls, * @param publicKey the public key of this peer */ void -core_init (void *cls, - struct GNUNET_CORE_Handle *server, - const struct GNUNET_PeerIdentity *identity, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey) +core_init(void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *identity, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey) { + struct GNUNET_TIME_Absolute curr_time; if (server == NULL) { #if DEBUG_NSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%s: Connection to core FAILED!\n", "nse", - GNUNET_i2s (identity)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Connection to core FAILED!\n", + "nse", GNUNET_i2s (identity)); #endif GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); return; } -#if DEBUG_NSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%s: Core connection initialized, I am peer: %s\n", "nse", - GNUNET_i2s (identity)); -#endif /* Copy our identity so we can use it */ - memcpy (&my_identity, identity, sizeof (struct GNUNET_PeerIdentity)); + memcpy (&my_identity, identity, sizeof(struct GNUNET_PeerIdentity)); /* Copy our public key for inclusion in flood messages */ - memcpy (&my_public_key, publicKey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); - - flood_message.header.size = htons(sizeof(struct GNUNET_NSE_FloodMessage)); - flood_message.header.type = htons(GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD); - memcpy(&flood_message.pkey, &my_public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + memcpy (&my_public_key, publicKey, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); if (flood_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel(flood_task); + GNUNET_SCHEDULER_cancel (flood_task); - schedule_flood_task = GNUNET_SCHEDULER_add_now(&schedule_flood_message, NULL); + /* Get the current UTC time */ + curr_time = GNUNET_TIME_absolute_get (); + /* Find the previous interval start time */ + previous_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL) + * GNUNET_NSE_INTERVAL; + /* Find the next interval start time */ + next_timestamp.abs_value = previous_timestamp.abs_value + GNUNET_NSE_INTERVAL; - GNUNET_SERVER_notification_context_broadcast (nc, +#if DEBUG_NSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Core connection initialized, I am peer: %s, scheduling flood task in %lu\n", "nse", + GNUNET_i2s (identity), GNUNET_TIME_absolute_get_remaining(next_timestamp)); +#endif + /* FIXME: In production, we'd likely want to do this immediately, but in test-beds it causes stupid behavior */ + if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (schedule_flood_task); + schedule_flood_task + = GNUNET_SCHEDULER_add_delayed ( + GNUNET_TIME_absolute_get_remaining ( + next_timestamp), + &schedule_flood_message, NULL); + + GNUNET_SERVER_notification_context_broadcast ( + nc, ¤t_estimate_message.header, GNUNET_NO); } @@ -637,31 +967,28 @@ core_init (void *cls, * @param c configuration to use */ static void -run (void *cls, - struct GNUNET_SERVER_Handle *server, - const struct GNUNET_CONFIGURATION_Handle *c) +run(void *cls, struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *c) { char *keyfile; - static const struct GNUNET_SERVER_MessageHandler handlers[] = { - {&handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START, 0}, - {NULL, NULL, 0, 0} - }; + static const struct GNUNET_SERVER_MessageHandler handlers[] = + { + { &handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START, 0 }, + { NULL, NULL, 0, 0 } }; - static const struct GNUNET_CORE_MessageHandler core_handlers[] = { - {&handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD, 0}, - {NULL, 0, 0} - }; + static const struct GNUNET_CORE_MessageHandler core_handlers[] = + { + { &handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD, 0 }, + { NULL, 0, 0 } }; cfg = c; - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (c, - "GNUNETD", - "HOSTKEY", &keyfile)) + if (GNUNET_OK + != GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY", + &keyfile)) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _ - ("NSE service is lacking key configuration settings. Exiting.\n")); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ + ("NSE service is lacking key configuration settings. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); return; } @@ -671,31 +998,29 @@ run (void *cls, if (my_private_key == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("NSE Service could not access hostkey. Exiting.\n")); + _("NSE Service could not access hostkey. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); return; } GNUNET_SERVER_add_handlers (server, handlers); nc = GNUNET_SERVER_notification_context_create (server, 16); - GNUNET_SERVER_disconnect_notify (server, - &handle_client_disconnect, - NULL); + GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); flood_task = GNUNET_SCHEDULER_NO_TASK; /** Connect to core service and register core handlers */ - coreAPI = GNUNET_CORE_connect (cfg, /* Main configuration */ - DEFAULT_CORE_QUEUE_SIZE, /* queue size */ - NULL, /* Closure passed to functions */ - &core_init, /* Call core_init once connected */ - &handle_core_connect, /* Handle connects */ - &handle_core_disconnect, /* Handle disconnects */ - NULL, /* Do we care about "status" updates? */ - NULL, /* Don't want notified about all incoming messages */ - GNUNET_NO, /* For header only inbound notification */ - NULL, /* Don't want notified about all outbound messages */ - GNUNET_NO, /* For header only outbound notification */ - core_handlers); /* Register these handlers */ + coreAPI = GNUNET_CORE_connect (cfg, /* Main configuration */ + DEFAULT_CORE_QUEUE_SIZE, /* queue size */ + NULL, /* Closure passed to functions */ + &core_init, /* Call core_init once connected */ + &handle_core_connect, /* Handle connects */ + &handle_core_disconnect, /* Handle disconnects */ + NULL, /* Do we care about "status" updates? */ + NULL, /* Don't want notified about all incoming messages */ + GNUNET_NO, /* For header only inbound notification */ + NULL, /* Don't want notified about all outbound messages */ + GNUNET_NO, /* For header only outbound notification */ + core_handlers); /* Register these handlers */ if (coreAPI == NULL) { @@ -703,26 +1028,26 @@ run (void *cls, return; } + stats = GNUNET_STATISTICS_create ("NSE", cfg); + increment = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, GNUNET_NSE_INTERVAL - / (sizeof(GNUNET_HashCode) - * 8)); + / (sizeof(GNUNET_HashCode) * 8)); /* Set we have no idea defaults for network size estimate */ current_size_estimate = 0.0; current_std_dev = NAN; size_estimates[estimate_index] = 0; - current_estimate_message.header.size = htons(sizeof(struct GNUNET_NSE_ClientMessage)); - current_estimate_message.header.type = htons(GNUNET_MESSAGE_TYPE_NSE_ESTIMATE); + current_estimate_message.header.size + = htons (sizeof(struct GNUNET_NSE_ClientMessage)); + current_estimate_message.header.type + = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE); current_estimate_message.size_estimate = current_size_estimate; current_estimate_message.std_deviation = current_std_dev; - - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, - &shutdown_task, + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } - /** * The main function for the statistics service. * @@ -731,14 +1056,11 @@ run (void *cls, * @return 0 ok, 1 on error */ int -main (int argc, char *const *argv) +main(int argc, char * const *argv) { - return (GNUNET_OK == - GNUNET_SERVICE_run (argc, - argv, - "nse", - GNUNET_SERVICE_OPTION_NONE, - &run, NULL)) ? 0 : 1; + return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "nse", + GNUNET_SERVICE_OPTION_NONE, &run, + NULL)) ? 0 : 1; } /* End of gnunet-service-nse.c */ diff --git a/src/nse/nse.h b/src/nse/nse.h index 59dd6bc1b..245bd4ca7 100644 --- a/src/nse/nse.h +++ b/src/nse/nse.h @@ -30,7 +30,9 @@ #include "gnunet_common.h" -#define DEBUG_NSE GNUNET_YES +#define DEBUG_NSE GNUNET_NO + +#define VERIFY_CRYPTO GNUNET_NO /** @@ -95,16 +97,16 @@ struct GNUNET_NSE_FloodMessage struct GNUNET_MessageHeader header; /** - * Magic header code(?) + * Purpose. */ - uint16_t enc_type; + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; /** * Number of matching bits between the hash * of timestamp and the initiator's public * key. */ - uint16_t distance; + uint32_t distance; /** * The current timestamp value (which all diff --git a/src/nse/nse_api.c b/src/nse/nse_api.c index 20c28e94f..4c441608f 100644 --- a/src/nse/nse_api.c +++ b/src/nse/nse_api.c @@ -105,6 +105,9 @@ void message_handler (void *cls, struct GNUNET_NSE_Handle *h = cls; struct GNUNET_NSE_ClientMessage *client_msg; + if (msg == NULL) /* Error, timeout, death */ + return; + if ((ntohs (msg->size) < sizeof(struct GNUNET_NSE_ClientMessage)) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_NSE_ESTIMATE)) { diff --git a/src/nse/test_nse.conf b/src/nse/test_nse.conf index 554cc4c0f..32f7a3262 100644 --- a/src/nse/test_nse.conf +++ b/src/nse/test_nse.conf @@ -5,12 +5,14 @@ DEFAULTCONFIG = test_nse.conf [nse] PORT = 22353 UNIXPATH = /tmp/test-nse-service-nse.unix +BINARY = /home/mrwiggles/documents/research/gnunet/gnunet-ng/src/nse/.libs/gnunet-service-nse +PREFIX = valgrind --leak-check=full --log-file=valgrind_nse.%p AUTOSTART = YES DEBUG = YES [arm] PORT = 22354 -DEFAULTSERVICES = nse +DEFAULTSERVICES = nse core UNIXPATH = /tmp/test-nse-service-arm.unix #DEBUG = YES @@ -24,14 +26,26 @@ AUTOSTART = NO AUTOSTART = NO [transport] -AUTOSTART = NO +AUTOSTART = YES [core] AUTOSTART = YES [peerinfo] -AUTOSTART = NO +AUTOSTART = YES [dns] AUTOSTART = NO +[testing] +NUM_PEERS = 40 +WEAKRANDOM = YES +TOPOLOGY = CLIQUE +F2F = NO +CONNECT_TIMEOUT = 60 +CONNECT_ATTEMPTS = 3 +#DEBUG = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat +MAX_CONCURRENT_SSH = 20 +USE_PROGRESSBARS = YES +PEERGROUP_TIMEOUT = 180 diff --git a/src/nse/test_nse_api.c b/src/nse/test_nse_api.c index f7274640a..4f83a6d78 100644 --- a/src/nse/test_nse_api.c +++ b/src/nse/test_nse_api.c @@ -71,9 +71,9 @@ static void end_test (void *cls, * @param estimate the value of the current network size estimate * @param std_dev standard deviation (rounded down to nearest integer) * of the size estimation values seen - * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + * */ -static int +static void check_nse_message (void *cls, double estimate, double std_dev) { int *ok = cls; @@ -87,7 +87,6 @@ check_nse_message (void *cls, double estimate, double std_dev) if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel(die_task); GNUNET_SCHEDULER_add_now(&end_test, NULL); - return GNUNET_OK; } static void diff --git a/src/nse/test_nse_multipeer.c b/src/nse/test_nse_multipeer.c new file mode 100644 index 000000000..600e0c2f2 --- /dev/null +++ b/src/nse/test_nse_multipeer.c @@ -0,0 +1,233 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file nse/test_nse_multipeer.c + * + * @brief Testcase for the network size estimation service. Starts + * a peergroup with a given number of peers, then waits to + * receive size estimates from each peer. Expects to wait + * for one message from each peer. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_nse_service.h" + +#define VERBOSE GNUNET_NO + +#define NUM_PEERS 4 + +struct NSEPeer +{ + struct NSEPeer *prev; + + struct NSEPeer *next; + + struct GNUNET_TESTING_Daemon *daemon; + + struct GNUNET_NSE_Handle *nse_handle; +}; + +struct NSEPeer *peer_head; + +struct NSEPeer *peer_tail; + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) + +static int ok; + +static int peers_left; + +static unsigned int num_peers; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All peers successfully shut down!\n"); +#endif + ok = 0; + } +} + +static void +shutdown_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NSEPeer *pos; +#if VERBOSE + fprintf(stderr, "Ending test.\n"); +#endif + + while (NULL != (pos = peer_head)) + { + GNUNET_NSE_disconnect(pos->nse_handle); + GNUNET_CONTAINER_DLL_remove(peer_head, peer_tail, pos); + GNUNET_free(pos); + } + + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + +/** + * Callback to call when network size estimate is updated. + * + * @param cls closure + * @param estimate the value of the current network size estimate + * @param std_dev standard deviation (rounded down to nearest integer) + * of the size estimation values seen + * + */ +static void +handle_estimate (void *cls, double estimate, double std_dev) +{ + struct NSEPeer *peer = cls; + fprintf(stderr, "Received network size estimate from peer %s. Size: %f std.dev. %f\n", GNUNET_i2s(&peer->daemon->id), estimate, std_dev); +} + +static void +connect_nse_service (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct NSEPeer *current_peer; + unsigned int i; +#if VERBOSE + fprintf(stderr, "TEST_NSE_MULTIPEER: connecting to nse service of peers\n"); +#endif + for (i = 0; i < num_peers; i++) + { + current_peer = GNUNET_malloc(sizeof(struct NSEPeer)); + current_peer->daemon = GNUNET_TESTING_daemon_get(pg, i); + current_peer->nse_handle = GNUNET_NSE_connect (current_peer->daemon->cfg, &handle_estimate, current_peer); + GNUNET_assert(current_peer->nse_handle != NULL); + + GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, current_peer); + } +} + +static void +my_cb (void *cls, + const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peergroup callback called with error, aborting test!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); + ok = 1; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + return; + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer Group started successfully, connecting to NSE service for each peer!\n"); +#endif + + GNUNET_SCHEDULER_add_now(&connect_nse_service, NULL); +} + + +static void +run (void *cls, + char *const *args, + const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_CONFIGURATION_Handle *testing_cfg; + unsigned long long total_peers; + ok = 1; + testing_cfg = GNUNET_CONFIGURATION_create(); + GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_load(testing_cfg, cfgfile)); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); + GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", + "use_progressbars", + "YES"); +#endif + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", "num_peers", &total_peers)) + total_peers = NUM_PEERS; + + peers_left = total_peers; + num_peers = peers_left; + pg = GNUNET_TESTING_peergroup_start(testing_cfg, + peers_left, + TIMEOUT, + NULL, + &my_cb, NULL, + NULL); + GNUNET_assert (pg != NULL); + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &shutdown_task, NULL); +} + +static int +check () +{ + char *const argv[] = { "test-nse-multipeer", + "-c", + "test_nse.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, + argv, "test-nse-multipeer", "nohelp", + options, &run, &ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-nse-multipeer", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + GNUNET_DISK_directory_remove ("/tmp/test-nse-multipeer"); + return ret; +} + +/* end of test_nse_multipeer.c */