summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nse/Makefile.am12
-rw-r--r--src/nse/gnunet-service-nse.c692
-rw-r--r--src/nse/nse.h10
-rw-r--r--src/nse/nse_api.c3
-rw-r--r--src/nse/test_nse.conf20
-rw-r--r--src/nse/test_nse_api.c5
-rw-r--r--src/nse/test_nse_multipeer.c233
7 files changed, 778 insertions, 197 deletions
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 = \
40 $(top_builddir)/src/nse/libgnunetnse.la \ 40 $(top_builddir)/src/nse/libgnunetnse.la \
41 $(top_builddir)/src/util/libgnunetutil.la \ 41 $(top_builddir)/src/util/libgnunetutil.la \
42 $(top_builddir)/src/core/libgnunetcore.la \ 42 $(top_builddir)/src/core/libgnunetcore.la \
43 $(top_builddir)/src/statistics/libgnunetstatistics.la \
43 -lm \ 44 -lm \
44 $(GN_LIBINTL) 45 $(GN_LIBINTL)
45gnunet_service_nse_DEPENDENCIES = \ 46gnunet_service_nse_DEPENDENCIES = \
46 libgnunetnse.la 47 libgnunetnse.la
47 48
48check_PROGRAMS = \ 49check_PROGRAMS = \
49 test_nse_api 50 test_nse_api \
51 test_nse_multipeer
50 52
51if ENABLE_TEST_RUN 53if ENABLE_TEST_RUN
52TESTS = $(check_PROGRAMS) $(check_SCRIPTS) 54TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
@@ -58,9 +60,15 @@ test_nse_api_LDADD = \
58 $(top_builddir)/src/nse/libgnunetnse.la \ 60 $(top_builddir)/src/nse/libgnunetnse.la \
59 $(top_builddir)/src/util/libgnunetutil.la 61 $(top_builddir)/src/util/libgnunetutil.la
60 62
63test_nse_multipeer_SOURCES = \
64 test_nse_multipeer.c
65test_nse_multipeer_LDADD = \
66 $(top_builddir)/src/nse/libgnunetnse.la \
67 $(top_builddir)/src/util/libgnunetutil.la \
68 $(top_builddir)/src/testing/libgnunettesting.la
61 69
62EXTRA_DIST = \ 70EXTRA_DIST = \
63 test_nse_api_data.conf \ 71 test_nse.conf \
64 $(check_SCRIPTS) 72 $(check_SCRIPTS)
65 73
66 74
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 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) 3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your 7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version. 8 option) any later version.
9 9
10 GNUnet is distributed in the hope that it will be useful, but 10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details. 13 General Public License for more details.
14 14
15 You should have received a copy of the GNU General Public License 15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the 16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19*/ 19 */
20 20
21/** 21/**
22 * @file nse/gnunet-service-nse.c 22 * @file nse/gnunet-service-nse.c
@@ -44,16 +44,17 @@
44#include "gnunet_signatures.h" 44#include "gnunet_signatures.h"
45#include "gnunet_service_lib.h" 45#include "gnunet_service_lib.h"
46#include "gnunet_server_lib.h" 46#include "gnunet_server_lib.h"
47#include "gnunet_statistics_service.h"
47#include "gnunet_core_service.h" 48#include "gnunet_core_service.h"
48#include "gnunet_time_lib.h" 49#include "gnunet_time_lib.h"
49#include "gnunet_nse_service.h" 50#include "gnunet_nse_service.h"
50#include "nse.h" 51#include "nse.h"
51 52
52#define DEFAULT_HISTORY_SIZE 10 53#define DEFAULT_HISTORY_SIZE 50
53 54
54#define DEFAULT_CORE_QUEUE_SIZE 32 55#define DEFAULT_CORE_QUEUE_SIZE 32
55 56
56#define DEFAULT_NSE_PRIORITY 0 57#define DEFAULT_NSE_PRIORITY 5
57 58
58/** 59/**
59 * Entry in the list of clients which 60 * Entry in the list of clients which
@@ -115,6 +116,11 @@ struct NSEPeerEntry
115static const struct GNUNET_CONFIGURATION_Handle *cfg; 116static const struct GNUNET_CONFIGURATION_Handle *cfg;
116 117
117/** 118/**
119 * Handle to the statistics service.
120 */
121static struct GNUNET_STATISTICS_Handle *stats;
122
123/**
118 * Handle to the core service. 124 * Handle to the core service.
119 */ 125 */
120static struct GNUNET_CORE_Handle *coreAPI; 126static struct GNUNET_CORE_Handle *coreAPI;
@@ -161,7 +167,8 @@ static unsigned int size_estimates[DEFAULT_HISTORY_SIZE];
161/** 167/**
162 * Array of size estimate messages. 168 * Array of size estimate messages.
163 */ 169 */
164static struct GNUNET_NSE_FloodMessage size_estimate_messages[DEFAULT_HISTORY_SIZE]; 170static struct GNUNET_NSE_FloodMessage
171 size_estimate_messages[DEFAULT_HISTORY_SIZE];
165 172
166/** 173/**
167 * Index of most recent estimate. 174 * Index of most recent estimate.
@@ -234,22 +241,21 @@ static struct GNUNET_NSE_FloodMessage flood_message;
234 * @param message the message received 241 * @param message the message received
235 */ 242 */
236static void 243static void
237handle_start_message (void *cls, 244handle_start_message(void *cls, struct GNUNET_SERVER_Client *client,
238 struct GNUNET_SERVER_Client *client, 245 const struct GNUNET_MessageHeader *message)
239 const struct GNUNET_MessageHeader *message)
240{ 246{
241 if ((ntohs (message->size) != sizeof(struct GNUNET_MessageHeader)) 247 if ((ntohs (message->size) != sizeof(struct GNUNET_MessageHeader))
242 || (ntohs (message->type) != GNUNET_MESSAGE_TYPE_NSE_START)) 248 || (ntohs (message->type) != GNUNET_MESSAGE_TYPE_NSE_START))
243 return; 249 return;
244 250
245#if DEBUG_NSE 251#if DEBUG_NSE
246 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "NSE", "Received START message from client\n"); 252 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "NSE",
253 "Received START message from client\n");
247#endif 254#endif
248 GNUNET_SERVER_notification_context_add (nc, client); 255 GNUNET_SERVER_notification_context_add (nc, client);
249 GNUNET_SERVER_receive_done(client, GNUNET_OK); 256 GNUNET_SERVER_receive_done (client, GNUNET_OK);
250} 257}
251 258
252
253/** 259/**
254 * Called when core is ready to send a message we asked for 260 * Called when core is ready to send a message we asked for
255 * out to the destination. 261 * out to the destination.
@@ -260,23 +266,41 @@ handle_start_message (void *cls,
260 * @return number of bytes written to buf 266 * @return number of bytes written to buf
261 */ 267 */
262static size_t 268static size_t
263transmit_ready (void *cls, size_t size, void *buf) 269transmit_ready(void *cls, size_t size, void *buf)
264{ 270{
265 struct NSEPeerEntry *peer_entry = cls; 271 struct NSEPeerEntry *peer_entry = cls;
266 char *cbuf = buf; 272 char *cbuf = buf;
267 273
268 size_t msize; 274 size_t msize;
269 peer_entry->th = NULL; 275 peer_entry->th = NULL;
276#if DEBUG_NSE
277 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: transmit_ready called\n",
278 GNUNET_i2s (&my_identity));
279#endif
270 if (buf == NULL) /* client disconnected */ 280 if (buf == NULL) /* client disconnected */
271 return 0; 281 {
282 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
283 "%s: transmit_ready called (disconnect)\n",
284 GNUNET_i2s (&my_identity));
285 return 0;
286 }
272 287
273 if (peer_entry->pending_message == NULL) 288 if (peer_entry->pending_message == NULL)
274 return 0; 289 {
290 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
291 "%s: transmit_ready called (no message)\n",
292 GNUNET_i2s (&my_identity));
293 return 0;
294 }
275 295
276 msize = ntohs(peer_entry->pending_message->size); 296 msize = ntohs (peer_entry->pending_message->size);
277 if (msize <= size) 297 if (msize <= size)
278 memcpy(cbuf, peer_entry->pending_message, msize); 298 memcpy (cbuf, peer_entry->pending_message, msize);
279 299#if DEBUG_NSE
300 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
301 "%s: transmit_ready called (transmit %d bytes)\n",
302 GNUNET_i2s (&my_identity), msize);
303#endif
280 return msize; 304 return msize;
281} 305}
282 306
@@ -288,35 +312,82 @@ transmit_ready (void *cls, size_t size, void *buf)
288 * 312 *
289 * @param message the network flood message 313 * @param message the network flood message
290 */ 314 */
291static void update_network_size_estimate(struct GNUNET_NSE_FloodMessage *message) 315static void
316update_network_size_estimate(struct GNUNET_NSE_FloodMessage *message)
292{ 317{
293 unsigned int i; 318 unsigned int i;
294 unsigned int count; 319 unsigned int count;
295 double average; 320 double average;
321 double std_dev;
322 double diff;
296 323
297 size_estimates[estimate_index] = htons(message->distance); 324 size_estimates[estimate_index] = htonl (message->distance);
298 memcpy(&size_estimate_messages[estimate_index], message, sizeof(struct GNUNET_NSE_FloodMessage)); 325 memcpy (&size_estimate_messages[estimate_index], message,
326 sizeof(struct GNUNET_NSE_FloodMessage));
299 327
300 count = 0; 328 count = 0;
329 std_dev = 0.0;
330 average = 0.0;
301 for (i = 0; i < DEFAULT_HISTORY_SIZE; i++) 331 for (i = 0; i < DEFAULT_HISTORY_SIZE; i++)
302 { 332 {
303 if (size_estimate_messages[i].distance != 0) 333 if (size_estimate_messages[i].distance != 0)
304 { 334 {
305 average += 1 << htons(size_estimate_messages[i].distance); 335#if AVERAGE_SQUARE
336 average += (1 << htonl (size_estimate_messages[i].distance));
337#else
338 average += htonl (size_estimate_messages[i].distance);
339#endif
306 count++; 340 count++;
307 } 341 }
308 } 342 }
309 average /= (double)count; 343
310 current_estimate_message.size_estimate = average; 344 if (count > 0)
311 /* Finally, broadcast the current estimate to all clients */ 345 {
312 GNUNET_SERVER_notification_context_broadcast (nc, 346 average /= (double) count;
313 &current_estimate_message.header, 347 for (i = 0; i < DEFAULT_HISTORY_SIZE; i++)
314 GNUNET_NO); 348 {
349 if (size_estimate_messages[i].distance != 0)
350 {
351#if DEBUG_NSE
352 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%s: estimate %d %d\n", GNUNET_i2s(&my_identity), i, (1 << htonl(size_estimate_messages[i].distance)));
353#endif
354#if AVERAGE_SQUARE
355 diff = average
356 - (1 << htonl (size_estimate_messages[i].distance));
357#else
358 diff = average - htonl (size_estimate_messages[i].distance);
359#endif
360 std_dev += diff * diff;
361 }
362 }
363 std_dev /= count;
364 std_dev = sqrt (std_dev);
365 current_estimate_message.header.size
366 = htons (sizeof(struct GNUNET_NSE_ClientMessage));
367 current_estimate_message.header.type
368 = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE);
369 current_estimate_message.size_estimate = average;
370 current_estimate_message.std_deviation = std_dev;
371 /* Finally, broadcast the current estimate to all clients */
372#if DEBUG_NSE
373 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
374 "%s: sending estimate %f -- %f to client\n",
375 GNUNET_i2s (&my_identity),
376 average,
377 std_dev);
378#endif
379 GNUNET_SERVER_notification_context_broadcast (
380 nc,
381 &current_estimate_message.header,
382 GNUNET_NO);
383
384 GNUNET_STATISTICS_set (stats, "Current network size estimate",
385 (uint64_t) average, GNUNET_NO);
386 }
315} 387}
316 388
317static void 389static void
318send_flood_message (void *cls, 390send_flood_message(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc);
319 const struct GNUNET_SCHEDULER_TaskContext * tc);
320 391
321/** 392/**
322 * Schedule a flood message to be sent. 393 * Schedule a flood message to be sent.
@@ -332,13 +403,11 @@ send_flood_message (void *cls,
332 * always be a message scheduled to be sent. 403 * always be a message scheduled to be sent.
333 */ 404 */
334static void 405static void
335schedule_flood_message (void *cls, 406schedule_flood_message(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
336 const struct GNUNET_SCHEDULER_TaskContext *tc)
337{ 407{
338 GNUNET_HashCode timestamp_hash; 408 GNUNET_HashCode timestamp_hash;
339 struct GNUNET_TIME_Absolute curr_time; 409 struct GNUNET_TIME_Absolute curr_time;
340 struct GNUNET_TIME_Relative offset; 410 struct GNUNET_TIME_Relative offset;
341 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
342 unsigned int matching_bits; 411 unsigned int matching_bits;
343 double millisecond_offset; 412 double millisecond_offset;
344 413
@@ -348,29 +417,46 @@ schedule_flood_message (void *cls,
348 417
349 GNUNET_assert(flood_task == GNUNET_SCHEDULER_NO_TASK); 418 GNUNET_assert(flood_task == GNUNET_SCHEDULER_NO_TASK);
350 419
351 if (0 != GNUNET_TIME_absolute_get_remaining(next_timestamp).rel_value) 420 if (0 != GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value)
352 { 421 {
353 GNUNET_break(0); /* Shouldn't ever happen! */ 422 GNUNET_break(0); /* Shouldn't ever happen! */
354 schedule_flood_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining(next_timestamp), &schedule_flood_message, NULL); 423 schedule_flood_task
424 = GNUNET_SCHEDULER_add_delayed (
425 GNUNET_TIME_absolute_get_remaining (
426 next_timestamp),
427 &schedule_flood_message, NULL);
355 } 428 }
356 429
357 /* Get the current UTC time */ 430 /* Get the current UTC time */
358 curr_time = GNUNET_TIME_absolute_get(); 431 curr_time = GNUNET_TIME_absolute_get ();
359 /* Find the previous interval start time */ 432 /* Find the previous interval start time */
360 previous_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL) * GNUNET_NSE_INTERVAL; 433 previous_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL)
434 * GNUNET_NSE_INTERVAL;
361 /* Find the next interval start time */ 435 /* Find the next interval start time */
362 next_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL) * (GNUNET_NSE_INTERVAL + 1); 436 next_timestamp.abs_value = previous_timestamp.abs_value + GNUNET_NSE_INTERVAL;
363 437#if DEBUG_NSE
364 GNUNET_CRYPTO_hash(&next_timestamp.abs_value, sizeof(uint64_t), &timestamp_hash); 438 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
365 matching_bits = GNUNET_CRYPTO_hash_matching_bits(&timestamp_hash, &my_identity.hashPubKey); 439 "%s: curr_time %lu, prev timestamp %lu, next timestamp %lu\n",
366 440 GNUNET_i2s (&my_identity), curr_time.abs_value,
367 flood_message.timestamp = GNUNET_TIME_absolute_hton(next_timestamp); 441 previous_timestamp.abs_value, next_timestamp.abs_value);
368 flood_message.distance = htons(matching_bits); 442#endif
369 flood_message.enc_type = htons(0); 443 GNUNET_CRYPTO_hash (&next_timestamp.abs_value,
370 flood_message.proof_of_work = htonl(0); 444 sizeof(next_timestamp.abs_value), &timestamp_hash);
371 purpose.purpose = GNUNET_SIGNATURE_PURPOSE_NSE_SEND; 445 matching_bits = GNUNET_CRYPTO_hash_matching_bits (&timestamp_hash,
372 purpose.size = sizeof(struct GNUNET_NSE_FloodMessage) - sizeof(struct GNUNET_MessageHeader) - sizeof(flood_message.proof_of_work) - sizeof(flood_message.signature); 446 &my_identity.hashPubKey);
373 GNUNET_CRYPTO_rsa_sign(my_private_key, &purpose, &flood_message.signature); 447
448 flood_message.header.size = htons (sizeof(struct GNUNET_NSE_FloodMessage));
449 flood_message.header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD);
450 flood_message.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND);
451 flood_message.purpose.size = htonl (sizeof(struct GNUNET_NSE_FloodMessage)
452 - sizeof(struct GNUNET_MessageHeader) - sizeof(flood_message.signature));
453 flood_message.distance = htonl (matching_bits);
454 flood_message.timestamp = GNUNET_TIME_absolute_hton (next_timestamp);
455 memcpy (&flood_message.pkey, &my_public_key,
456 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
457 flood_message.proof_of_work = htonl (0);
458 GNUNET_CRYPTO_rsa_sign (my_private_key, &flood_message.purpose,
459 &flood_message.signature);
374 460
375 /*S + f/2 - (f / pi) * (atan(x - p'))*/ 461 /*S + f/2 - (f / pi) * (atan(x - p'))*/
376 462
@@ -378,21 +464,135 @@ schedule_flood_message (void *cls,
378 // f is frequency (GNUNET_NSE_INTERVAL) 464 // f is frequency (GNUNET_NSE_INTERVAL)
379 // x is matching_bits 465 // x is matching_bits
380 // p' is current_size_estimate 466 // p' is current_size_estimate
381 millisecond_offset = ((double)GNUNET_NSE_INTERVAL / (double)2) - ((GNUNET_NSE_INTERVAL / M_PI) * atan(matching_bits - current_size_estimate)); 467 millisecond_offset = ((double) GNUNET_NSE_INTERVAL / (double) 2)
382 468 - ((GNUNET_NSE_INTERVAL / M_PI) * atan (matching_bits
383 fprintf(stderr, "my id matches %d bits, offset is %lu\n", matching_bits, (uint64_t)millisecond_offset); 469 - current_size_estimate));
384 470#if DEBUG_NSE
385 estimate_index += 1; 471 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
472 "%s: id matches %d bits, offset is %lu\n\n",
473 GNUNET_i2s (&my_identity), matching_bits,
474 (uint64_t) millisecond_offset);
475#endif
476 /* Stop initial call from incrementing */
477 if (size_estimate_messages[estimate_index].distance != 0)
478 estimate_index += 1;
386 479
387 if (estimate_index >= DEFAULT_HISTORY_SIZE) 480 if (estimate_index >= DEFAULT_HISTORY_SIZE)
388 estimate_index = 0; 481 estimate_index = 0;
389 482
390 offset.rel_value = (uint64_t)millisecond_offset + GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value; 483 if (millisecond_offset < curr_time.abs_value - previous_timestamp.abs_value)
391 flood_task = GNUNET_SCHEDULER_add_delayed (offset, 484 offset.rel_value = 0;
392 &send_flood_message, NULL); 485 else
486 offset.rel_value = (uint64_t) millisecond_offset + curr_time.abs_value
487 - previous_timestamp.abs_value;
488#if DEBUG_NSE
489 GNUNET_log (
490 GNUNET_ERROR_TYPE_WARNING,
491 "%s: milliseconds until next timestamp %lu, sending flood in %lu\n",
492 GNUNET_i2s (&my_identity),
493 GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value,
494 offset.rel_value);
495#endif
496 flood_task = GNUNET_SCHEDULER_add_delayed (offset, &send_flood_message, NULL);
393 497
394} 498}
395 499
500#if VERIFY_CRYPTO
501/**
502 * Check whether the given public key
503 * and integer are a valid proof of work.
504 *
505 * @param pkey the public key
506 * @param val the integer
507 * @param want the number of trailing zeroes
508 *
509 * @return GNUNET_YES if valid, GNUNET_NO if not
510 */
511static int check_proof_of_work(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey, uint64_t val, unsigned int want)
512 {
513
514 return GNUNET_YES;
515 }
516
517/**
518 * Count the trailing zeroes in hash.
519 *
520 * @param hash
521 *
522 * @return the number of trailing zero bits.
523 */
524static unsigned int count_trailing_zeroes(GNUNET_HashCode *hash)
525 {
526 unsigned int hash_count;
527
528 hash_count = sizeof(GNUNET_HashCode) * 8;
529 while ((0 == GNUNET_CRYPTO_hash_get_bit(hash, hash_count)))
530 hash_count--;
531 return (sizeof(GNUNET_HashCode) * 8) - hash_count;
532 }
533
534/**
535 * Given a public key, find an integer such that
536 * the hash of the key concatenated with the integer
537 * has <param>want</param> trailing 0 bits.
538 *
539 * @param pkey the public key
540 * @param want the number of trailing 0 bits
541 *
542 * @return 64 bit number that satisfies the
543 * requirements
544 *
545 * FIXME: use pointer and return GNUNET_YES or
546 * GNUNET_NO in case no such number works?
547 */
548static uint64_t find_proof_of_work(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey, unsigned int want)
549 {
550 uint64_t counter;
551 static char buf[sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof(uint64_t)];
552 unsigned int data_size;
553 static GNUNET_HashCode result;
554
555 data_size = sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof(uint64_t);
556 memcpy(buf, pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
557 counter = 0;
558 while (counter != (uint64_t)-1)
559 {
560 memcpy(&buf[sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)], &counter, sizeof(uint64_t));
561 GNUNET_CRYPTO_hash(buf, data_size, &result);
562 if (want == count_trailing_zeroes(&result)) /* Found good proof of work! */
563 break;
564 counter++;
565 }
566 if (counter < (uint64_t)-1)
567 return counter; /* Found valid proof of work */
568 else
569 return 0; /* Did not find valid proof of work */
570 }
571
572/**
573 * An incoming flood message has been received which claims
574 * to have more bits matching than any we know in this time
575 * period. Verify the signature and/or proof of work.
576 *
577 * @param incoming_flood the message to verify
578 *
579 * @return GNUNET_YES if the message is verified
580 * GNUNET_NO if the key/signature don't verify
581 */
582static int verify_message_crypto(struct GNUNET_NSE_FloodMessage *incoming_flood)
583 {
584 int ret;
585 if (GNUNET_OK == (ret
586 = GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND,
587 &incoming_flood->purpose,
588 &incoming_flood->signature,
589 &incoming_flood->pkey)))
590 return GNUNET_YES;
591
592 return GNUNET_NO;
593 }
594#endif
595
396/** 596/**
397 * Core handler for size estimate flooding messages. 597 * Core handler for size estimate flooding messages.
398 * 598 *
@@ -408,20 +608,89 @@ handle_p2p_size_estimate(void *cls, const struct GNUNET_PeerIdentity *peer,
408 const struct GNUNET_TRANSPORT_ATS_Information *atsi) 608 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
409{ 609{
410 struct GNUNET_NSE_FloodMessage *incoming_flood; 610 struct GNUNET_NSE_FloodMessage *incoming_flood;
611 struct GNUNET_TIME_Absolute curr_time;
612 uint64_t drift;
411 613
412 if (ntohs(message->size) != sizeof(struct GNUNET_NSE_FloodMessage)) 614#if DEBUG_NSE
413 return GNUNET_NO; 615 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: received flood message!\n",
616 GNUNET_i2s (&my_identity));
617#endif
618 if (ntohs (message->size) != sizeof(struct GNUNET_NSE_FloodMessage))
619 {
620 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: bad message size!\n",
621 GNUNET_i2s (&my_identity));
622 return GNUNET_NO;
623 }
414 624
415 incoming_flood = (struct GNUNET_NSE_FloodMessage *)message; 625 GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO);
416 if (ntohs(incoming_flood->distance) <= ntohs(size_estimate_messages[estimate_index].distance)) /* Not closer than our most recent message */ 626 incoming_flood = (struct GNUNET_NSE_FloodMessage *) message;
417 return GNUNET_OK; 627 if (ntohl (incoming_flood->distance)
628 <= ntohl (size_estimate_messages[estimate_index].distance)) /* Not closer than our most recent message */
629 {
630#if DEBUG_NSE
631 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
632 "%s: distance %d not greater than %d, discarding\n",
633 GNUNET_i2s (&my_identity), ntohl (incoming_flood->distance),
634 ntohl (size_estimate_messages[estimate_index].distance));
635#endif
636 GNUNET_STATISTICS_update (stats,
637 "# flood messages discarded (had closer)", 1,
638 GNUNET_NO);
639 return GNUNET_OK;
640 }
641
642 curr_time = GNUNET_TIME_absolute_get ();
643 if (curr_time.abs_value
644 > GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value)
645 drift = curr_time.abs_value
646 - GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value;
647 else
648 drift = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value
649 - curr_time.abs_value;
650
651 if (drift > GNUNET_NSE_DRIFT_TOLERANCE)
652 {
653 GNUNET_STATISTICS_update (
654 stats,
655 "# flood messages discarded (clock skew too high)",
656 1, GNUNET_NO);
657 return GNUNET_OK;
658 }
659
660#if VERIFY_CRYPTO
661 if (GNUNET_YES != verify_message_crypto(incoming_flood))
662 {
663 GNUNET_STATISTICS_update (stats,
664 "# flood messages discarded (bad crypto)",
665 1, GNUNET_NO);
666 return GNUNET_OK;
667 }
668#endif
418 669
419 /* Have a new, better size estimate! */ 670 /* Have a new, better size estimate! */
420 update_network_size_estimate(incoming_flood); 671 update_network_size_estimate (incoming_flood);
672
673 if (flood_task != GNUNET_SCHEDULER_NO_TASK)
674 {
675#if DEBUG_NSE
676 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: received closer message, canceling my flood task!\n", GNUNET_i2s(&my_identity));
677#endif
678 GNUNET_SCHEDULER_cancel (flood_task);
679 flood_task = GNUNET_SCHEDULER_NO_TASK;
680 }
421 681
682 /** Commenting out prevents forwarding of messages */
683#if DO_FORWARD
684 GNUNET_SCHEDULER_add_now(&send_flood_message, &size_estimate_messages[estimate_index]);
685#endif
422 if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK) 686 if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK)
423 GNUNET_SCHEDULER_cancel(schedule_flood_task); 687 GNUNET_SCHEDULER_cancel (schedule_flood_task);
424 schedule_flood_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining(next_timestamp), &schedule_flood_message, NULL); 688
689 schedule_flood_task
690 = GNUNET_SCHEDULER_add_delayed (
691 GNUNET_TIME_absolute_get_remaining (
692 next_timestamp),
693 &schedule_flood_message, NULL);
425 694
426 return GNUNET_OK; 695 return GNUNET_OK;
427} 696}
@@ -429,39 +698,80 @@ handle_p2p_size_estimate(void *cls, const struct GNUNET_PeerIdentity *peer,
429/** 698/**
430 * Send a flood message. 699 * Send a flood message.
431 * 700 *
432 * If we've gotten here, it means we haven't received 701 * If we've gotten here, it means either we haven't received
433 * a network size estimate message closer than ours. 702 * a network size estimate message closer than ours, or
703 * we need to forward a message we received which was closer
704 * than ours.
434 */ 705 */
435static void 706static void
436send_flood_message (void *cls, 707send_flood_message(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
437 const struct GNUNET_SCHEDULER_TaskContext * tc)
438{ 708{
439 struct NSEPeerEntry *peer_entry; 709 struct NSEPeerEntry *peer_entry;
710 struct GNUNET_NSE_FloodMessage *to_send;
711
712 if (cls == NULL) /* Means we are sending our OWN flood message */
713 to_send = &flood_message;
714 else
715 /* Received a message from another peer that should be forwarded */
716 to_send = (struct GNUNET_NSE_FloodMessage *) cls;
440 717
441 flood_task = GNUNET_SCHEDULER_NO_TASK; 718 flood_task = GNUNET_SCHEDULER_NO_TASK;
442 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) 719 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
443 return; 720 return;
444 721#if DEBUG_NSE
722 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
723 "%s: my time has come, sending flood message of size %d!\n",
724 GNUNET_i2s (&my_identity), ntohs (to_send->header.size));
725#endif
445 peer_entry = peers_head; 726 peer_entry = peers_head;
446 727
447 while (peer_entry != NULL) 728 while (peer_entry != NULL)
448 { 729 {
730 peer_entry->pending_message = &to_send->header;
449 peer_entry->th 731 peer_entry->th
450 = GNUNET_CORE_notify_transmit_ready (coreAPI, 732 = GNUNET_CORE_notify_transmit_ready (
451 GNUNET_YES, 733 coreAPI,
734 GNUNET_NO,
452 DEFAULT_NSE_PRIORITY, 735 DEFAULT_NSE_PRIORITY,
453 GNUNET_TIME_absolute_get_remaining ( 736 GNUNET_TIME_absolute_get_remaining (
454 next_timestamp), 737 next_timestamp),
455 &peer_entry->id, 738 &peer_entry->id,
456 ntohs (flood_message.header.size), 739 ntohs (to_send->header.size),
457 &transmit_ready, peer_entry); 740 &transmit_ready, peer_entry);
741 if (peer_entry->th == NULL)
742 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
743 "%s: transmit handle is null!\n", GNUNET_i2s (&my_identity));
744#if DEBUG_NSE
745 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
746 "%s: Sending flood message (distance %d) to %s!\n",
747 GNUNET_i2s (&my_identity), ntohl (to_send->distance),
748 GNUNET_h2s (&peer_entry->id.hashPubKey));
749#endif
458 peer_entry = peer_entry->next; 750 peer_entry = peer_entry->next;
459 } 751 }
460 752
461 update_network_size_estimate(&flood_message); 753 if (cls == NULL) /* Need to update our size estimate */
754 {
755 update_network_size_estimate (to_send);
756 GNUNET_STATISTICS_update (stats, "# flood messages sent", 1, GNUNET_NO);
757 }
758 else
759 GNUNET_STATISTICS_update (stats, "# flood messages forwarded", 1, GNUNET_NO);
760
761#if DEBUG_NSE
762 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
763 "%s: scheduling schedule_flood_message in %lu\n",
764 GNUNET_i2s (&my_identity),
765 GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value);
766#endif
462 if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK) 767 if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK)
463 GNUNET_SCHEDULER_cancel(schedule_flood_task); 768 GNUNET_SCHEDULER_cancel (schedule_flood_task);
464 schedule_flood_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining(next_timestamp), &schedule_flood_message, NULL); 769
770 schedule_flood_task
771 = GNUNET_SCHEDULER_add_delayed (
772 GNUNET_TIME_absolute_get_remaining (
773 next_timestamp),
774 &schedule_flood_message, NULL);
465} 775}
466 776
467/** 777/**
@@ -472,18 +782,19 @@ send_flood_message (void *cls,
472 * @param atsi performance data 782 * @param atsi performance data
473 */ 783 */
474static void 784static void
475handle_core_connect (void *cls, 785handle_core_connect(void *cls, const struct GNUNET_PeerIdentity *peer,
476 const struct GNUNET_PeerIdentity *peer, 786 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
477 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
478{ 787{
479 struct NSEPeerEntry *peer_entry; 788 struct NSEPeerEntry *peer_entry;
480 789
790 if (0 == (memcmp (peer, &my_identity, sizeof(struct GNUNET_PeerIdentity))))
791 return; /* Do not connect to self... */
792
481 peer_entry = GNUNET_malloc(sizeof(struct NSEPeerEntry)); 793 peer_entry = GNUNET_malloc(sizeof(struct NSEPeerEntry));
482 memcpy(&peer_entry->id, peer, sizeof(struct GNUNET_PeerIdentity)); 794 memcpy (&peer_entry->id, peer, sizeof(struct GNUNET_PeerIdentity));
483 GNUNET_CONTAINER_DLL_insert(peers_head, peers_tail, peer_entry); 795 GNUNET_CONTAINER_DLL_insert(peers_head, peers_tail, peer_entry);
484} 796}
485 797
486
487/** 798/**
488 * Method called whenever a peer disconnects. 799 * Method called whenever a peer disconnects.
489 * 800 *
@@ -491,30 +802,37 @@ handle_core_connect (void *cls,
491 * @param peer peer identity this notification is about 802 * @param peer peer identity this notification is about
492 */ 803 */
493static void 804static void
494handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) 805handle_core_disconnect(void *cls, const struct GNUNET_PeerIdentity *peer)
495{ 806{
496 struct NSEPeerEntry *pos; 807 struct NSEPeerEntry *pos;
497 808
809 if (0 == (memcmp (peer, &my_identity, sizeof(struct GNUNET_PeerIdentity))))
810 return; /* Ignore disconnect from self... */
811
498 pos = peers_head; 812 pos = peers_head;
499 while ((NULL != pos) && (0 != memcmp(&pos->id, peer, sizeof(struct GNUNET_PeerIdentity)))) 813 while ((NULL != pos) && (0 != memcmp (&pos->id, peer,
814 sizeof(struct GNUNET_PeerIdentity))))
500 pos = pos->next; 815 pos = pos->next;
501 if (pos == NULL) 816 if (pos == NULL)
502 { 817 {
503 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Received disconnect before connect!\n"); 818 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
819 "Received disconnect before connect!\n");
504 GNUNET_break(0); /* Should never receive a disconnect message for a peer we don't know about... */ 820 GNUNET_break(0); /* Should never receive a disconnect message for a peer we don't know about... */
505 return; 821 return;
506 } 822 }
507 823
824 /* TODO: decide whether to copy the message, or always use the static pointer */
825#if TODO
508 if (pos->pending_message != NULL) 826 if (pos->pending_message != NULL)
509 GNUNET_free(pos->pending_message); 827 GNUNET_free(pos->pending_message);
828#endif
510 829
511 if (pos->th != NULL) 830 if (pos->th != NULL)
512 GNUNET_CORE_notify_transmit_ready_cancel(pos->th); 831 GNUNET_CORE_notify_transmit_ready_cancel (pos->th);
513 GNUNET_CONTAINER_DLL_remove(peers_head, peers_tail, pos); 832 GNUNET_CONTAINER_DLL_remove(peers_head, peers_tail, pos);
514 GNUNET_free(pos); 833 GNUNET_free(pos);
515} 834}
516 835
517
518/** 836/**
519 * A client disconnected. Remove it from the 837 * A client disconnected. Remove it from the
520 * global DLL of clients. 838 * global DLL of clients.
@@ -523,8 +841,7 @@ handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
523 * @param client identification of the client 841 * @param client identification of the client
524 */ 842 */
525static void 843static void
526handle_client_disconnect (void *cls, 844handle_client_disconnect(void *cls, struct GNUNET_SERVER_Client* client)
527 struct GNUNET_SERVER_Client* client)
528{ 845{
529 struct ClientListEntry *cle; 846 struct ClientListEntry *cle;
530 847
@@ -533,15 +850,15 @@ handle_client_disconnect (void *cls,
533 850
534 if (cle != NULL) 851 if (cle != NULL)
535 { 852 {
536 GNUNET_SERVER_client_drop(cle->client); 853 GNUNET_SERVER_client_drop (cle->client);
537 GNUNET_CONTAINER_DLL_remove(cle_head, 854 GNUNET_CONTAINER_DLL_remove(cle_head,
538 cle_tail, 855 cle_tail,
539 cle); 856 cle);
540 GNUNET_free(cle); 857 GNUNET_free(cle);
541 } 858 }
542 if (coreAPI != NULL) 859 if (coreAPI != NULL)
543 { 860 {
544 GNUNET_CORE_disconnect(coreAPI); 861 GNUNET_CORE_disconnect (coreAPI);
545 coreAPI = NULL; 862 coreAPI = NULL;
546 } 863 }
547} 864}
@@ -553,32 +870,33 @@ handle_client_disconnect (void *cls,
553 * @param tc unused 870 * @param tc unused
554 */ 871 */
555static void 872static void
556shutdown_task (void *cls, 873shutdown_task(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
557 const struct GNUNET_SCHEDULER_TaskContext *tc)
558{ 874{
559 struct ClientListEntry *cle; 875 struct ClientListEntry *cle;
560 876
561 if (flood_task != GNUNET_SCHEDULER_NO_TASK) 877 if (flood_task != GNUNET_SCHEDULER_NO_TASK)
562 GNUNET_SCHEDULER_cancel(flood_task); 878 GNUNET_SCHEDULER_cancel (flood_task);
563 GNUNET_SERVER_notification_context_destroy (nc); 879 GNUNET_SERVER_notification_context_destroy (nc);
564 nc = NULL; 880 nc = NULL;
565 while (NULL != (cle = cle_head)) 881 while (NULL != (cle = cle_head))
566 { 882 {
567 GNUNET_SERVER_client_drop (cle->client); 883 GNUNET_SERVER_client_drop (cle->client);
568 GNUNET_CONTAINER_DLL_remove (cle_head, 884 GNUNET_CONTAINER_DLL_remove (cle_head,
569 cle_tail, 885 cle_tail,
570 cle); 886 cle);
571 GNUNET_free (cle); 887 GNUNET_free (cle);
572 } 888 }
573 889
574 if (coreAPI != NULL) 890 if (coreAPI != NULL)
575 { 891 {
576 GNUNET_CORE_disconnect(coreAPI); 892 GNUNET_CORE_disconnect (coreAPI);
577 coreAPI = NULL; 893 coreAPI = NULL;
578 } 894 }
579 895
580} 896 if (stats != NULL)
897 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
581 898
899}
582 900
583/** 901/**
584 * Called on core init/fail. 902 * Called on core init/fail.
@@ -589,42 +907,54 @@ shutdown_task (void *cls,
589 * @param publicKey the public key of this peer 907 * @param publicKey the public key of this peer
590 */ 908 */
591void 909void
592core_init (void *cls, 910core_init(void *cls, struct GNUNET_CORE_Handle *server,
593 struct GNUNET_CORE_Handle *server, 911 const struct GNUNET_PeerIdentity *identity,
594 const struct GNUNET_PeerIdentity *identity, 912 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
595 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
596{ 913{
914 struct GNUNET_TIME_Absolute curr_time;
597 if (server == NULL) 915 if (server == NULL)
598 { 916 {
599#if DEBUG_NSE 917#if DEBUG_NSE
600 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 918 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Connection to core FAILED!\n",
601 "%s: Connection to core FAILED!\n", "nse", 919 "nse", GNUNET_i2s (identity));
602 GNUNET_i2s (identity));
603#endif 920#endif
604 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); 921 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
605 return; 922 return;
606 } 923 }
607#if DEBUG_NSE
608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
609 "%s: Core connection initialized, I am peer: %s\n", "nse",
610 GNUNET_i2s (identity));
611#endif
612 924
613 /* Copy our identity so we can use it */ 925 /* Copy our identity so we can use it */
614 memcpy (&my_identity, identity, sizeof (struct GNUNET_PeerIdentity)); 926 memcpy (&my_identity, identity, sizeof(struct GNUNET_PeerIdentity));
615 /* Copy our public key for inclusion in flood messages */ 927 /* Copy our public key for inclusion in flood messages */
616 memcpy (&my_public_key, publicKey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); 928 memcpy (&my_public_key, publicKey,
617 929 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
618 flood_message.header.size = htons(sizeof(struct GNUNET_NSE_FloodMessage));
619 flood_message.header.type = htons(GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD);
620 memcpy(&flood_message.pkey, &my_public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
621 930
622 if (flood_task != GNUNET_SCHEDULER_NO_TASK) 931 if (flood_task != GNUNET_SCHEDULER_NO_TASK)
623 GNUNET_SCHEDULER_cancel(flood_task); 932 GNUNET_SCHEDULER_cancel (flood_task);
624 933
625 schedule_flood_task = GNUNET_SCHEDULER_add_now(&schedule_flood_message, NULL); 934 /* Get the current UTC time */
935 curr_time = GNUNET_TIME_absolute_get ();
936 /* Find the previous interval start time */
937 previous_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL)
938 * GNUNET_NSE_INTERVAL;
939 /* Find the next interval start time */
940 next_timestamp.abs_value = previous_timestamp.abs_value + GNUNET_NSE_INTERVAL;
626 941
627 GNUNET_SERVER_notification_context_broadcast (nc, 942#if DEBUG_NSE
943 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
944 "%s: Core connection initialized, I am peer: %s, scheduling flood task in %lu\n", "nse",
945 GNUNET_i2s (identity), GNUNET_TIME_absolute_get_remaining(next_timestamp));
946#endif
947 /* FIXME: In production, we'd likely want to do this immediately, but in test-beds it causes stupid behavior */
948 if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK)
949 GNUNET_SCHEDULER_cancel (schedule_flood_task);
950 schedule_flood_task
951 = GNUNET_SCHEDULER_add_delayed (
952 GNUNET_TIME_absolute_get_remaining (
953 next_timestamp),
954 &schedule_flood_message, NULL);
955
956 GNUNET_SERVER_notification_context_broadcast (
957 nc,
628 &current_estimate_message.header, 958 &current_estimate_message.header,
629 GNUNET_NO); 959 GNUNET_NO);
630} 960}
@@ -637,31 +967,28 @@ core_init (void *cls,
637 * @param c configuration to use 967 * @param c configuration to use
638 */ 968 */
639static void 969static void
640run (void *cls, 970run(void *cls, struct GNUNET_SERVER_Handle *server,
641 struct GNUNET_SERVER_Handle *server, 971 const struct GNUNET_CONFIGURATION_Handle *c)
642 const struct GNUNET_CONFIGURATION_Handle *c)
643{ 972{
644 char *keyfile; 973 char *keyfile;
645 static const struct GNUNET_SERVER_MessageHandler handlers[] = { 974 static const struct GNUNET_SERVER_MessageHandler handlers[] =
646 {&handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START, 0}, 975 {
647 {NULL, NULL, 0, 0} 976 { &handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START, 0 },
648 }; 977 { NULL, NULL, 0, 0 } };
649 978
650 static const struct GNUNET_CORE_MessageHandler core_handlers[] = { 979 static const struct GNUNET_CORE_MessageHandler core_handlers[] =
651 {&handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD, 0}, 980 {
652 {NULL, 0, 0} 981 { &handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD, 0 },
653 }; 982 { NULL, 0, 0 } };
654 983
655 cfg = c; 984 cfg = c;
656 985
657 if (GNUNET_OK != 986 if (GNUNET_OK
658 GNUNET_CONFIGURATION_get_value_filename (c, 987 != GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY",
659 "GNUNETD", 988 &keyfile))
660 "HOSTKEY", &keyfile))
661 { 989 {
662 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 990 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _
663 _ 991 ("NSE service is lacking key configuration settings. Exiting.\n"));
664 ("NSE service is lacking key configuration settings. Exiting.\n"));
665 GNUNET_SCHEDULER_shutdown (); 992 GNUNET_SCHEDULER_shutdown ();
666 return; 993 return;
667 } 994 }
@@ -671,31 +998,29 @@ run (void *cls,
671 if (my_private_key == NULL) 998 if (my_private_key == NULL)
672 { 999 {
673 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1000 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
674 _("NSE Service could not access hostkey. Exiting.\n")); 1001 _("NSE Service could not access hostkey. Exiting.\n"));
675 GNUNET_SCHEDULER_shutdown (); 1002 GNUNET_SCHEDULER_shutdown ();
676 return; 1003 return;
677 } 1004 }
678 1005
679 GNUNET_SERVER_add_handlers (server, handlers); 1006 GNUNET_SERVER_add_handlers (server, handlers);
680 nc = GNUNET_SERVER_notification_context_create (server, 16); 1007 nc = GNUNET_SERVER_notification_context_create (server, 16);
681 GNUNET_SERVER_disconnect_notify (server, 1008 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
682 &handle_client_disconnect,
683 NULL);
684 1009
685 flood_task = GNUNET_SCHEDULER_NO_TASK; 1010 flood_task = GNUNET_SCHEDULER_NO_TASK;
686 /** Connect to core service and register core handlers */ 1011 /** Connect to core service and register core handlers */
687 coreAPI = GNUNET_CORE_connect (cfg, /* Main configuration */ 1012 coreAPI = GNUNET_CORE_connect (cfg, /* Main configuration */
688 DEFAULT_CORE_QUEUE_SIZE, /* queue size */ 1013 DEFAULT_CORE_QUEUE_SIZE, /* queue size */
689 NULL, /* Closure passed to functions */ 1014 NULL, /* Closure passed to functions */
690 &core_init, /* Call core_init once connected */ 1015 &core_init, /* Call core_init once connected */
691 &handle_core_connect, /* Handle connects */ 1016 &handle_core_connect, /* Handle connects */
692 &handle_core_disconnect, /* Handle disconnects */ 1017 &handle_core_disconnect, /* Handle disconnects */
693 NULL, /* Do we care about "status" updates? */ 1018 NULL, /* Do we care about "status" updates? */
694 NULL, /* Don't want notified about all incoming messages */ 1019 NULL, /* Don't want notified about all incoming messages */
695 GNUNET_NO, /* For header only inbound notification */ 1020 GNUNET_NO, /* For header only inbound notification */
696 NULL, /* Don't want notified about all outbound messages */ 1021 NULL, /* Don't want notified about all outbound messages */
697 GNUNET_NO, /* For header only outbound notification */ 1022 GNUNET_NO, /* For header only outbound notification */
698 core_handlers); /* Register these handlers */ 1023 core_handlers); /* Register these handlers */
699 1024
700 if (coreAPI == NULL) 1025 if (coreAPI == NULL)
701 { 1026 {
@@ -703,26 +1028,26 @@ run (void *cls,
703 return; 1028 return;
704 } 1029 }
705 1030
1031 stats = GNUNET_STATISTICS_create ("NSE", cfg);
1032
706 increment 1033 increment
707 = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 1034 = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
708 GNUNET_NSE_INTERVAL 1035 GNUNET_NSE_INTERVAL
709 / (sizeof(GNUNET_HashCode) 1036 / (sizeof(GNUNET_HashCode) * 8));
710 * 8));
711 /* Set we have no idea defaults for network size estimate */ 1037 /* Set we have no idea defaults for network size estimate */
712 current_size_estimate = 0.0; 1038 current_size_estimate = 0.0;
713 current_std_dev = NAN; 1039 current_std_dev = NAN;
714 size_estimates[estimate_index] = 0; 1040 size_estimates[estimate_index] = 0;
715 current_estimate_message.header.size = htons(sizeof(struct GNUNET_NSE_ClientMessage)); 1041 current_estimate_message.header.size
716 current_estimate_message.header.type = htons(GNUNET_MESSAGE_TYPE_NSE_ESTIMATE); 1042 = htons (sizeof(struct GNUNET_NSE_ClientMessage));
1043 current_estimate_message.header.type
1044 = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE);
717 current_estimate_message.size_estimate = current_size_estimate; 1045 current_estimate_message.size_estimate = current_size_estimate;
718 current_estimate_message.std_deviation = current_std_dev; 1046 current_estimate_message.std_deviation = current_std_dev;
719 1047 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
720 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
721 &shutdown_task,
722 NULL); 1048 NULL);
723} 1049}
724 1050
725
726/** 1051/**
727 * The main function for the statistics service. 1052 * The main function for the statistics service.
728 * 1053 *
@@ -731,14 +1056,11 @@ run (void *cls,
731 * @return 0 ok, 1 on error 1056 * @return 0 ok, 1 on error
732 */ 1057 */
733int 1058int
734main (int argc, char *const *argv) 1059main(int argc, char * const *argv)
735{ 1060{
736 return (GNUNET_OK == 1061 return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "nse",
737 GNUNET_SERVICE_run (argc, 1062 GNUNET_SERVICE_OPTION_NONE, &run,
738 argv, 1063 NULL)) ? 0 : 1;
739 "nse",
740 GNUNET_SERVICE_OPTION_NONE,
741 &run, NULL)) ? 0 : 1;
742} 1064}
743 1065
744/* End of gnunet-service-nse.c */ 1066/* 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 @@
30 30
31#include "gnunet_common.h" 31#include "gnunet_common.h"
32 32
33#define DEBUG_NSE GNUNET_YES 33#define DEBUG_NSE GNUNET_NO
34
35#define VERIFY_CRYPTO GNUNET_NO
34 36
35 37
36/** 38/**
@@ -95,16 +97,16 @@ struct GNUNET_NSE_FloodMessage
95 struct GNUNET_MessageHeader header; 97 struct GNUNET_MessageHeader header;
96 98
97 /** 99 /**
98 * Magic header code(?) 100 * Purpose.
99 */ 101 */
100 uint16_t enc_type; 102 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
101 103
102 /** 104 /**
103 * Number of matching bits between the hash 105 * Number of matching bits between the hash
104 * of timestamp and the initiator's public 106 * of timestamp and the initiator's public
105 * key. 107 * key.
106 */ 108 */
107 uint16_t distance; 109 uint32_t distance;
108 110
109 /** 111 /**
110 * The current timestamp value (which all 112 * 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,
105 struct GNUNET_NSE_Handle *h = cls; 105 struct GNUNET_NSE_Handle *h = cls;
106 struct GNUNET_NSE_ClientMessage *client_msg; 106 struct GNUNET_NSE_ClientMessage *client_msg;
107 107
108 if (msg == NULL) /* Error, timeout, death */
109 return;
110
108 if ((ntohs (msg->size) < sizeof(struct GNUNET_NSE_ClientMessage)) 111 if ((ntohs (msg->size) < sizeof(struct GNUNET_NSE_ClientMessage))
109 || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_NSE_ESTIMATE)) 112 || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_NSE_ESTIMATE))
110 { 113 {
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
5[nse] 5[nse]
6PORT = 22353 6PORT = 22353
7UNIXPATH = /tmp/test-nse-service-nse.unix 7UNIXPATH = /tmp/test-nse-service-nse.unix
8BINARY = /home/mrwiggles/documents/research/gnunet/gnunet-ng/src/nse/.libs/gnunet-service-nse
9PREFIX = valgrind --leak-check=full --log-file=valgrind_nse.%p
8AUTOSTART = YES 10AUTOSTART = YES
9DEBUG = YES 11DEBUG = YES
10 12
11[arm] 13[arm]
12PORT = 22354 14PORT = 22354
13DEFAULTSERVICES = nse 15DEFAULTSERVICES = nse core
14UNIXPATH = /tmp/test-nse-service-arm.unix 16UNIXPATH = /tmp/test-nse-service-arm.unix
15#DEBUG = YES 17#DEBUG = YES
16 18
@@ -24,14 +26,26 @@ AUTOSTART = NO
24AUTOSTART = NO 26AUTOSTART = NO
25 27
26[transport] 28[transport]
27AUTOSTART = NO 29AUTOSTART = YES
28 30
29[core] 31[core]
30AUTOSTART = YES 32AUTOSTART = YES
31 33
32[peerinfo] 34[peerinfo]
33AUTOSTART = NO 35AUTOSTART = YES
34 36
35[dns] 37[dns]
36AUTOSTART = NO 38AUTOSTART = NO
37 39
40[testing]
41NUM_PEERS = 40
42WEAKRANDOM = YES
43TOPOLOGY = CLIQUE
44F2F = NO
45CONNECT_TIMEOUT = 60
46CONNECT_ATTEMPTS = 3
47#DEBUG = YES
48HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat
49MAX_CONCURRENT_SSH = 20
50USE_PROGRESSBARS = YES
51PEERGROUP_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,
71 * @param estimate the value of the current network size estimate 71 * @param estimate the value of the current network size estimate
72 * @param std_dev standard deviation (rounded down to nearest integer) 72 * @param std_dev standard deviation (rounded down to nearest integer)
73 * of the size estimation values seen 73 * of the size estimation values seen
74 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration 74 *
75 */ 75 */
76static int 76static void
77check_nse_message (void *cls, double estimate, double std_dev) 77check_nse_message (void *cls, double estimate, double std_dev)
78{ 78{
79 int *ok = cls; 79 int *ok = cls;
@@ -87,7 +87,6 @@ check_nse_message (void *cls, double estimate, double std_dev)
87 if (die_task != GNUNET_SCHEDULER_NO_TASK) 87 if (die_task != GNUNET_SCHEDULER_NO_TASK)
88 GNUNET_SCHEDULER_cancel(die_task); 88 GNUNET_SCHEDULER_cancel(die_task);
89 GNUNET_SCHEDULER_add_now(&end_test, NULL); 89 GNUNET_SCHEDULER_add_now(&end_test, NULL);
90 return GNUNET_OK;
91} 90}
92 91
93static void 92static 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 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file nse/test_nse_multipeer.c
22 *
23 * @brief Testcase for the network size estimation service. Starts
24 * a peergroup with a given number of peers, then waits to
25 * receive size estimates from each peer. Expects to wait
26 * for one message from each peer.
27 */
28#include "platform.h"
29#include "gnunet_testing_lib.h"
30#include "gnunet_nse_service.h"
31
32#define VERBOSE GNUNET_NO
33
34#define NUM_PEERS 4
35
36struct NSEPeer
37{
38 struct NSEPeer *prev;
39
40 struct NSEPeer *next;
41
42 struct GNUNET_TESTING_Daemon *daemon;
43
44 struct GNUNET_NSE_Handle *nse_handle;
45};
46
47struct NSEPeer *peer_head;
48
49struct NSEPeer *peer_tail;
50
51/**
52 * How long until we give up on connecting the peers?
53 */
54#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500)
55
56static int ok;
57
58static int peers_left;
59
60static unsigned int num_peers;
61
62static struct GNUNET_TESTING_PeerGroup *pg;
63
64/**
65 * Check whether peers successfully shut down.
66 */
67void
68shutdown_callback (void *cls, const char *emsg)
69{
70 if (emsg != NULL)
71 {
72#if VERBOSE
73 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n");
74#endif
75 if (ok == 0)
76 ok = 666;
77 }
78 else
79 {
80#if VERBOSE
81 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
82 "All peers successfully shut down!\n");
83#endif
84 ok = 0;
85 }
86}
87
88static void
89shutdown_task (void *cls,
90 const struct GNUNET_SCHEDULER_TaskContext *tc)
91{
92 struct NSEPeer *pos;
93#if VERBOSE
94 fprintf(stderr, "Ending test.\n");
95#endif
96
97 while (NULL != (pos = peer_head))
98 {
99 GNUNET_NSE_disconnect(pos->nse_handle);
100 GNUNET_CONTAINER_DLL_remove(peer_head, peer_tail, pos);
101 GNUNET_free(pos);
102 }
103
104 GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
105}
106
107/**
108 * Callback to call when network size estimate is updated.
109 *
110 * @param cls closure
111 * @param estimate the value of the current network size estimate
112 * @param std_dev standard deviation (rounded down to nearest integer)
113 * of the size estimation values seen
114 *
115 */
116static void
117handle_estimate (void *cls, double estimate, double std_dev)
118{
119 struct NSEPeer *peer = cls;
120 fprintf(stderr, "Received network size estimate from peer %s. Size: %f std.dev. %f\n", GNUNET_i2s(&peer->daemon->id), estimate, std_dev);
121}
122
123static void
124connect_nse_service (void *cls,
125 const struct GNUNET_SCHEDULER_TaskContext *tc)
126{
127 struct NSEPeer *current_peer;
128 unsigned int i;
129#if VERBOSE
130 fprintf(stderr, "TEST_NSE_MULTIPEER: connecting to nse service of peers\n");
131#endif
132 for (i = 0; i < num_peers; i++)
133 {
134 current_peer = GNUNET_malloc(sizeof(struct NSEPeer));
135 current_peer->daemon = GNUNET_TESTING_daemon_get(pg, i);
136 current_peer->nse_handle = GNUNET_NSE_connect (current_peer->daemon->cfg, &handle_estimate, current_peer);
137 GNUNET_assert(current_peer->nse_handle != NULL);
138
139 GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, current_peer);
140 }
141}
142
143static void
144my_cb (void *cls,
145 const char *emsg)
146{
147 if (emsg != NULL)
148 {
149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
150 "Peergroup callback called with error, aborting test!\n");
151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n");
152 ok = 1;
153 GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
154 return;
155 }
156#if VERBOSE
157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
158 "Peer Group started successfully, connecting to NSE service for each peer!\n");
159#endif
160
161 GNUNET_SCHEDULER_add_now(&connect_nse_service, NULL);
162}
163
164
165static void
166run (void *cls,
167 char *const *args,
168 const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
169{
170 struct GNUNET_CONFIGURATION_Handle *testing_cfg;
171 unsigned long long total_peers;
172 ok = 1;
173 testing_cfg = GNUNET_CONFIGURATION_create();
174 GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_load(testing_cfg, cfgfile));
175#if VERBOSE
176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n");
177 GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing",
178 "use_progressbars",
179 "YES");
180#endif
181 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", "num_peers", &total_peers))
182 total_peers = NUM_PEERS;
183
184 peers_left = total_peers;
185 num_peers = peers_left;
186 pg = GNUNET_TESTING_peergroup_start(testing_cfg,
187 peers_left,
188 TIMEOUT,
189 NULL,
190 &my_cb, NULL,
191 NULL);
192 GNUNET_assert (pg != NULL);
193 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &shutdown_task, NULL);
194}
195
196static int
197check ()
198{
199 char *const argv[] = { "test-nse-multipeer",
200 "-c",
201 "test_nse.conf",
202#if VERBOSE
203 "-L", "DEBUG",
204#endif
205 NULL
206 };
207 struct GNUNET_GETOPT_CommandLineOption options[] = {
208 GNUNET_GETOPT_OPTION_END
209 };
210 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
211 argv, "test-nse-multipeer", "nohelp",
212 options, &run, &ok);
213 return ok;
214}
215
216int
217main (int argc, char *argv[])
218{
219 int ret;
220
221 GNUNET_log_setup ("test-nse-multipeer",
222#if VERBOSE
223 "DEBUG",
224#else
225 "WARNING",
226#endif
227 NULL);
228 ret = check ();
229 GNUNET_DISK_directory_remove ("/tmp/test-nse-multipeer");
230 return ret;
231}
232
233/* end of test_nse_multipeer.c */