GNUnet debian-0.24.3-29-g453fda2cf
 
Loading...
Searching...
No Matches
gnunet-service-nse.c File Reference

network size estimation service More...

#include "platform.h"
#include <math.h>
#include "gnunet_util_lib.h"
#include "gnunet_hello_uri_lib.h"
#include "gnunet_protocols.h"
#include "gnunet_signatures.h"
#include "gnunet_statistics_service.h"
#include "gnunet_core_service.h"
#include "gnunet_pils_service.h"
#include "nse.h"
#include <gcrypt.h>
Include dependency graph for gnunet-service-nse.c:

Go to the source code of this file.

Data Structures

struct  NSEPeerEntry
 Per-peer information. More...
 
struct  GNUNET_NSE_FloodMessage
 Network size estimate reply; sent when "this" peer's timer has run out before receiving a valid reply from another peer. More...
 

Macros

#define USE_RANDOM_DELAYS   GNUNET_YES
 Should messages be delayed randomly? This option should be set to GNUNET_NO only for experiments, not in production.
 
#define DEBUG_NSE   GNUNET_NO
 Generate extensive debug-level log messages?
 
#define HISTORY_SIZE   64
 Over how many values do we calculate the weighted average?
 
#define NSE_PRIORITY
 Message priority to use.
 
#define WEST   1
 
#define ROUND_SIZE   10
 

Functions

static void setup_estimate_message (struct GNUNET_NSE_ClientMessage *em)
 Initialize a message to clients with the current network size estimate.
 
static void handle_start (void *cls, const struct GNUNET_MessageHeader *message)
 Handler for START message from client, triggers an immediate current network estimate notification.
 
static double get_matching_bits_delay (uint32_t matching_bits)
 How long should we delay a message to go the given number of matching bits?
 
static struct GNUNET_TIME_Relative get_delay_randomization (uint32_t matching_bits)
 What delay randomization should we apply for a given number of matching bits?
 
static uint32_t get_matching_bits (struct GNUNET_TIME_Absolute timestamp, const struct GNUNET_PeerIdentity *id)
 Get the number of matching bits that the given timestamp has to the given peer ID.
 
static struct GNUNET_TIME_Relative get_transmit_delay (int round_offset)
 Get the transmission delay that should be applied for a particular round.
 
static void sign_message_before_send_cb (void *cls, const struct GNUNET_PeerIdentity *pid, const struct GNUNET_CRYPTO_EddsaSignature *sig)
 
static void transmit_task_cb (void *cls)
 Task that triggers a NSE P2P transmission.
 
static void update_network_size_estimate ()
 We've sent on our flood message or one that we received which was validated and closer than ours.
 
static void setup_flood_message (unsigned int slot, struct GNUNET_TIME_Absolute ts)
 Setup a flood message in our history array at the given slot offset for the given timestamp.
 
static int schedule_current_round (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
 Schedule transmission for the given peer for the current round based on what we know about the desired delay.
 
static void update_flood_message (void *cls)
 Update our flood message to be sent (and our timestamps).
 
static enum GNUNET_GenericReturnValue check_proof_of_work (const struct GNUNET_CRYPTO_EddsaPublicKey *pkey, uint64_t val)
 Check whether the given public key and integer are a valid proof of work.
 
static void write_proof (void)
 Write our current proof to disk.
 
static void find_proof (void *cls)
 Find our proof of work.
 
static int verify_message_crypto (const struct GNUNET_NSE_FloodMessage *incoming_flood)
 An incoming flood message has been received which claims to have more bits matching than any we know in this time period.
 
static int update_flood_times (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
 Update transmissions for the given peer for the current round based on updated proximity information.
 
static void handle_p2p_estimate (void *cls, const struct GNUNET_NSE_FloodMessage *incoming_flood)
 Core handler for size estimate flooding messages.
 
static void * handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer, struct GNUNET_MQ_Handle *mq, enum GNUNET_CORE_PeerClass class)
 Method called whenever a peer connects.
 
static void handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer, void *internal_cls)
 Method called whenever a peer disconnects.
 
static void shutdown_task (void *cls)
 Task run during shutdown.
 
static void identity_changed (const struct GNUNET_PeerIdentity *identity)
 
static void pils_id_change_cb (void *cls, const struct GNUNET_HELLO_Parser *parser, const struct GNUNET_HashCode *addr_hash)
 
static void core_init (void *cls, const struct GNUNET_PeerIdentity *identity)
 Called on core init/fail.
 
static void run (void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service)
 Handle network size estimate clients.
 
static void * client_connect_cb (void *cls, struct GNUNET_SERVICE_Client *c, struct GNUNET_MQ_Handle *mq)
 Callback called when a client connects to the service.
 
static void client_disconnect_cb (void *cls, struct GNUNET_SERVICE_Client *c, void *internal_cls)
 Callback called when a client disconnected from the service.
 
 GNUNET_SERVICE_MAIN (GNUNET_OS_project_data_gnunet(), "nse", GNUNET_SERVICE_OPTION_NONE, &run, &client_connect_cb, &client_disconnect_cb, NULL, GNUNET_MQ_hd_fixed_size(start, GNUNET_MESSAGE_TYPE_NSE_START, struct GNUNET_MessageHeader, NULL), GNUNET_MQ_handler_end())
 Define "main" method using service macro.
 

Variables

static unsigned long long nse_work_required
 Amount of work required (W-bit collisions) for NSE proofs, in collision-bits.
 
static struct GNUNET_TIME_Relative gnunet_nse_interval
 Interval for sending network size estimation flood requests.
 
static struct GNUNET_TIME_Relative proof_find_delay
 Interval between proof find runs.
 
static struct GNUNET_CRYPTO_PowSalt salt = { "gnunet-nse-proof" }
 Salt for PoW calculations.
 
static GNUNET_NETWORK_STRUCT_END const struct GNUNET_CONFIGURATION_Handlecfg
 Handle to our current configuration.
 
static struct GNUNET_STATISTICS_Handlestats
 Handle to the statistics service.
 
static struct GNUNET_PILS_Handlepils
 Handle to the PILS service.
 
static struct GNUNET_CORE_Handlecore_api
 Handle to the core service.
 
static struct GNUNET_CONTAINER_MultiPeerMappeers
 Map of all connected peers.
 
static double current_size_estimate
 The current network size estimate.
 
static double current_std_dev = NAN
 The standard deviation of the last HISTORY_SIZE network size estimates.
 
static uint32_t hop_count_max
 Current hop counter estimate (estimate for network diameter).
 
static struct GNUNET_NSE_FloodMessage next_message
 Message for the next round, if we got any.
 
static struct GNUNET_NSE_FloodMessage size_estimate_messages [64]
 Array of recent size estimate messages.
 
static unsigned int estimate_index
 Index of most recent estimate.
 
static unsigned int estimate_count
 Number of valid entries in the history.
 
static struct GNUNET_SCHEDULER_Taskflood_task
 Task scheduled to update our flood message for the next round.
 
static struct GNUNET_SCHEDULER_Taskproof_task
 Task scheduled to compute our proof.
 
static struct GNUNET_NotificationContextnc
 Notification context, simplifies client broadcasts.
 
static struct GNUNET_TIME_Absolute next_timestamp
 The next major time.
 
static struct GNUNET_TIME_Absolute current_timestamp
 The current major time.
 
static struct GNUNET_CRYPTO_EddsaPrivateKeymy_private_key
 The private key of this peer.
 
static struct GNUNET_PeerIdentity my_identity
 The peer identity of this peer.
 
static uint64_t my_proof
 Proof of work for this peer.
 

Detailed Description

network size estimation service

Author
Nathan Evans
Christian Grothoff

The purpose of this service is to estimate the size of the network. Given a specified interval, each peer hashes the most recent timestamp which is evenly divisible by that interval. This hash is compared in distance to the peer identity to choose an offset. The closer the peer identity to the hashed timestamp, the earlier the peer sends out a "nearest peer" message. The closest peer's message should thus be received before any others, which stops those peer from sending their messages at a later duration. So every peer should receive the same nearest peer message, and from this can calculate the expected number of peers in the network.

Definition in file gnunet-service-nse.c.

Macro Definition Documentation

◆ USE_RANDOM_DELAYS

#define USE_RANDOM_DELAYS   GNUNET_YES

Should messages be delayed randomly? This option should be set to GNUNET_NO only for experiments, not in production.

Definition at line 58 of file gnunet-service-nse.c.

◆ DEBUG_NSE

#define DEBUG_NSE   GNUNET_NO

Generate extensive debug-level log messages?

Definition at line 63 of file gnunet-service-nse.c.

◆ HISTORY_SIZE

#define HISTORY_SIZE   64

Over how many values do we calculate the weighted average?

Definition at line 68 of file gnunet-service-nse.c.

◆ NSE_PRIORITY

#define NSE_PRIORITY
Value:
@ GNUNET_MQ_PRIO_BACKGROUND
Lowest priority, i.e.
@ GNUNET_MQ_PREF_CORK_ALLOWED
Flag to indicate that CORKing is acceptable.
@ GNUNET_MQ_PREF_UNRELIABLE
Flag to indicate that unreliable delivery is acceptable.

Message priority to use.

No real rush, reliability not required. Corking OK.

Definition at line 74 of file gnunet-service-nse.c.

118 { "gnunet-nse-proof" };
119
120
124struct NSEPeerEntry
125{
129 struct GNUNET_MQ_Handle *mq;
130
134 const struct GNUNET_PeerIdentity *id;
135
140
144 uint32_t next_index_to_send;
145
150
156 int previous_round;
157
158#if ENABLE_NSE_HISTOGRAM
162 unsigned int received_messages;
163
167 unsigned int transmitted_messages;
168
172 unsigned int last_transmitted_size;
173#endif
174};
175
176
178
185{
190
194 uint32_t hop_count GNUNET_PACKED;
195
200
206
213
218
223
228};
230
234static const struct GNUNET_CONFIGURATION_Handle *cfg;
235
239static struct GNUNET_STATISTICS_Handle *stats;
240
244static struct GNUNET_PILS_Handle *pils;
245
249static struct GNUNET_CORE_Handle *core_api;
250
255
260static double current_size_estimate;
261
266static double current_std_dev = NAN;
267
271static uint32_t hop_count_max;
272
277
282
286static unsigned int estimate_index;
287
291static unsigned int estimate_count;
292
296static struct GNUNET_SCHEDULER_Task *flood_task;
297
301static struct GNUNET_SCHEDULER_Task *proof_task;
302
306static struct GNUNET_NotificationContext *nc;
307
312
317
322
326static struct GNUNET_PeerIdentity my_identity;
327
331static uint64_t my_proof;
332
333
340static void
342{
343 double mean;
344 double sum;
345 double std_dev;
346 double variance;
347 double val;
348 double nsize;
349
350#define WEST 1
351 /* Weighted incremental algorithm for stddev according to West (1979) */
352#if WEST
353 double sumweight;
354 double weight;
355 double q;
356 double r;
357 double temp;
358
359 mean = 0.0;
360 sum = 0.0;
361 sumweight = 0.0;
362 variance = 0.0;
363 for (unsigned int i = 0; i < estimate_count; i++)
364 {
365 unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE;
366
367 val = htonl (size_estimate_messages[j].matching_bits);
368 weight = estimate_count + 1 - i;
369
370 temp = weight + sumweight;
371 q = val - mean;
372 r = q * weight / temp;
373 mean += r;
374 sum += sumweight * q * r;
375 sumweight = temp;
376 }
377 if (estimate_count > 0)
378 variance = (sum / sumweight) * estimate_count / (estimate_count - 1.0);
379#else
380 /* trivial version for debugging */
381 double vsq;
382
383 /* non-weighted trivial version */
384 sum = 0.0;
385 vsq = 0.0;
386 variance = 0.0;
387 mean = 0.0;
388
389 for (unsigned int i = 0; i < estimate_count; i++)
390 {
391 unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE;
392
393 val = htonl (size_estimate_messages[j].matching_bits);
394 sum += val;
395 vsq += val * val;
396 }
397 if (0 != estimate_count)
398 {
399 mean = sum / estimate_count;
400 variance = (vsq - mean * sum)
401 / (estimate_count - 1.0); // terrible for numerical stability...
402 }
403#endif
404 if (variance >= 0)
405 std_dev = sqrt (variance);
406 else
407 std_dev = variance; /* return NaN (due to estimate_count == 0 causing 0.0/0.0) */
408 current_std_dev = std_dev;
410
411 em->header.size = htons (sizeof(struct GNUNET_NSE_ClientMessage));
412 em->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE);
413 em->reserved = htonl (0);
415 {
416 double se = mean - 0.332747;
417 unsigned int j = GNUNET_CONTAINER_multipeermap_size (peers);
418 if (0 == j)
419 j = 1; /* Avoid log2(0); can only happen if CORE didn't report
420 connection to self yet */
421 nsize = log2 (j);
422 em->size_estimate = GNUNET_hton_double (GNUNET_MAX (se, nsize));
423 em->std_deviation = GNUNET_hton_double (std_dev);
425 "# nodes in the network (estimate)",
426 (uint64_t) pow (2, GNUNET_MAX (se, nsize)),
427 GNUNET_NO);
428 }
429}
430
431
441static void
442handle_start (void *cls, const struct GNUNET_MessageHeader *message)
443{
444 struct GNUNET_SERVICE_Client *client = cls;
445 struct GNUNET_MQ_Handle *mq;
446 struct GNUNET_NSE_ClientMessage em;
447 struct GNUNET_MQ_Envelope *env;
448
449 (void) message;
450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received START message from client\n");
454 env = GNUNET_MQ_msg_copy (&em.header);
457}
458
459
466static double
468{
469 /* Calculated as: S + f/2 - (f / pi) * (atan(x - p')) */
470 // S is next_timestamp (ignored in return value)
471 // f is frequency (gnunet_nse_interval)
472 // x is matching_bits
473 // p' is current_size_estimate
474 return ((double) gnunet_nse_interval.rel_value_us / (double) 2.0)
477}
478
479
486static struct GNUNET_TIME_Relative
488{
489#if USE_RANDOM_DELAYS
491 uint32_t i;
492 double d;
493
495 i = (uint32_t) (d / (double) (hop_count_max + 1));
496 ret.rel_value_us = i;
498 "Randomizing flood using latencies up to %s\n",
500 ret.rel_value_us =
502 return ret;
503#else
505#endif
506}
507
508
516static uint32_t
518 const struct GNUNET_PeerIdentity *id)
519{
520 struct GNUNET_HashCode timestamp_hash;
521 struct GNUNET_HashCode pid_hash;
522 struct GNUNET_HashCode xor;
523
524 GNUNET_CRYPTO_hash (&timestamp.abs_value_us,
525 sizeof(timestamp.abs_value_us),
526 &timestamp_hash);
528 sizeof(struct GNUNET_PeerIdentity),
529 &pid_hash);
530 GNUNET_CRYPTO_hash_xor (&pid_hash,
531 &timestamp_hash,
532 &xor);
534}
535
536
545static struct GNUNET_TIME_Relative
546get_transmit_delay (int round_offset)
547{
549 struct GNUNET_TIME_Absolute tgt;
550 double dist_delay;
551 uint32_t matching_bits;
552
553 switch (round_offset)
554 {
555 case -1:
556 /* previous round is randomized between 0 and 50 ms */
557#if USE_RANDOM_DELAYS
558 ret.rel_value_us =
560#else
562#endif
564 "Transmitting previous round behind schedule in %s\n",
566 return ret;
567
568 case 0:
569 /* current round is based on best-known matching_bits */
574 ret.rel_value_us = (uint64_t) dist_delay;
576 "For round %s, delay for %u matching bits is %s\n",
578 (unsigned int) matching_bits,
580 /* now consider round start time and add delay to it */
583 }
584 GNUNET_break (0);
586}
587
588static void
590 const struct GNUNET_PeerIdentity *pid,
591 const struct GNUNET_CRYPTO_EddsaSignature *sig)
592{
593 struct NSEPeerEntry *pe = cls;
594 struct GNUNET_MQ_Envelope *env;
595 struct GNUNET_NSE_FloodMessage *fm;
596
597 pe->pils_op = NULL;
599 fm->signature = *sig;
601 GNUNET_MQ_send (pe->mq, env);
602}
603
604
610static void
611transmit_task_cb (void *cls)
612{
613 struct NSEPeerEntry *peer_entry = cls;
614 unsigned int idx;
615
616 peer_entry->transmit_task = NULL;
617 idx = estimate_index;
618 if (GNUNET_NO == peer_entry->previous_round)
619 {
620 idx = (idx + HISTORY_SIZE - 1) % HISTORY_SIZE;
621 peer_entry->previous_round = GNUNET_YES;
622 peer_entry->transmit_task =
625 peer_entry);
626 }
627 if ((0 == ntohl (size_estimate_messages[idx].hop_count)) &&
628 (NULL != proof_task))
629 {
631 "# flood messages not generated (no proof yet)",
632 1,
633 GNUNET_NO);
634 return;
635 }
636 if (0 == ntohs (size_estimate_messages[idx].header.size))
637 {
639 "# flood messages not generated (lack of history)",
640 1,
641 GNUNET_NO);
642 return;
643 }
645 "In round %s, sending to `%s' estimate with %u bits\n",
649 GNUNET_i2s (peer_entry->id),
650 (unsigned int) ntohl (size_estimate_messages[idx].matching_bits));
651 if (0 == ntohl (size_estimate_messages[idx].hop_count))
652 GNUNET_STATISTICS_update (stats, "# flood messages started", 1, GNUNET_NO);
654 "# flood messages transmitted",
655 1,
656 GNUNET_NO);
657#if ENABLE_NSE_HISTOGRAM
658 peer_entry->transmitted_messages++;
659 peer_entry->last_transmitted_size =
661#endif
662 peer_entry->next_index_to_send = idx;
664 pils,
665 &size_estimate_messages[idx].purpose,
667 peer_entry);
668}
669
670
671
678static void
680{
681 struct GNUNET_NSE_ClientMessage em;
682
685}
686
687
695static void
696setup_flood_message (unsigned int slot, struct GNUNET_TIME_Absolute ts)
697{
698 struct GNUNET_NSE_FloodMessage *fm;
699 uint32_t matching_bits;
700
702 fm = &size_estimate_messages[slot];
703 fm->header.size = htons (sizeof(struct GNUNET_NSE_FloodMessage));
705 fm->hop_count = htonl (0);
707 fm->purpose.size =
708 htonl (sizeof(struct GNUNET_NSE_FloodMessage)
709 - sizeof(struct GNUNET_MessageHeader) - sizeof(uint32_t)
710 - sizeof(struct GNUNET_CRYPTO_EddsaSignature));
711 fm->matching_bits = htonl (matching_bits);
713 fm->origin = my_identity;
715 /* FIXME: We now sign asyncronuously later per sent message because
716 * of PILS. This is probably inefficient. But it may also cause race
717 * conditions wrt the signature (?)
718 * if (nse_work_required > 0)
719 GNUNET_assert (GNUNET_OK ==
720 GNUNET_CRYPTO_eddsa_sign_ (my_private_key,
721 &fm->purpose,
722 &fm->signature));
723 else
724 memset (&fm->signature, 0, sizeof(fm->signature));*/
725}
726
727
737static int
738schedule_current_round (void *cls,
739 const struct GNUNET_PeerIdentity *key,
740 void *value)
741{
742 struct NSEPeerEntry *peer_entry = value;
743 struct GNUNET_TIME_Relative delay;
744
745 (void) cls;
746 (void) key;
747 if (NULL != peer_entry->transmit_task)
748 {
750 peer_entry->previous_round = GNUNET_NO;
751 }
752#if ENABLE_NSE_HISTOGRAM
753 if (peer_entry->received_messages > 1)
755 "# extra messages",
756 peer_entry->received_messages - 1,
757 GNUNET_NO);
758 peer_entry->transmitted_messages = 0;
759 peer_entry->last_transmitted_size = 0;
760 peer_entry->received_messages = 0;
761#endif
762 delay =
763 get_transmit_delay ((GNUNET_NO == peer_entry->previous_round) ? -1 : 0);
764 peer_entry->transmit_task =
766 return GNUNET_OK;
767}
768
769
775static void
776update_flood_message (void *cls)
777{
778 struct GNUNET_TIME_Relative offset;
779
780 (void) cls;
781 flood_task = NULL;
783 if (0 != offset.rel_value_us)
784 {
785 /* somehow run early, delay more */
786 flood_task =
788 return;
789 }
800 {
801 /* we received a message for this round way early, use it! */
804 htonl (1 + ntohl (next_message.hop_count));
805 }
806 else
808 next_message.matching_bits = htonl (0); /* reset for 'next' round */
809 hop_count_max = 0;
810 for (unsigned int i = 0; i < HISTORY_SIZE; i++)
812 GNUNET_MAX (ntohl (size_estimate_messages[i].hop_count), hop_count_max);
814 flood_task =
816}
817
818
829 uint64_t val)
830{
831 char buf[sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
832 + sizeof(val)] GNUNET_ALIGN;
833 struct GNUNET_HashCode result;
834
835 GNUNET_memcpy (buf, &val, sizeof(val));
836 GNUNET_memcpy (&buf[sizeof(val)],
837 pkey,
838 sizeof(struct GNUNET_CRYPTO_EddsaPublicKey));
840 buf,
841 sizeof(buf),
842 &result);
845 ? GNUNET_YES
846 : GNUNET_NO;
847}
848
849
853static void
854write_proof (void)
855{
856 char *proof;
857
858 if (GNUNET_OK !=
860 "NSE",
861 "PROOFFILE",
862 &proof))
863 return;
865 if (GNUNET_OK !=
867 &my_proof,
868 sizeof(my_proof),
872 "write",
873 proof);
875}
876
877
883static void
884find_proof (void *cls)
885{
886#define ROUND_SIZE 10
887 uint64_t counter;
888 char buf[sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
889 + sizeof(uint64_t)] GNUNET_ALIGN;
890 struct GNUNET_HashCode result;
891 unsigned int i;
892
893 (void) cls;
894 proof_task = NULL;
895 GNUNET_memcpy (&buf[sizeof(uint64_t)],
897 sizeof(struct GNUNET_PeerIdentity));
898 i = 0;
899 counter = my_proof;
900 while ((counter != UINT64_MAX) && (i < ROUND_SIZE))
901 {
902 GNUNET_memcpy (buf, &counter, sizeof(uint64_t));
904 buf,
905 sizeof(buf),
906 &result);
907 if (nse_work_required <=
909 {
910 my_proof = counter;
912 "Proof of work found: %llu!\n",
913 (unsigned long long) GNUNET_ntohll (counter));
914 write_proof ();
916 return;
917 }
918 counter++;
919 i++;
920 }
921 if (my_proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE))
922 {
924 "Testing proofs currently at %llu\n",
925 (unsigned long long) counter);
926 /* remember progress every 100 rounds */
927 my_proof = counter;
928 write_proof ();
929 }
930 else
931 {
932 my_proof = counter;
933 }
934 proof_task =
937 &find_proof,
938 NULL);
939}
940
941
951static int
952verify_message_crypto (const struct GNUNET_NSE_FloodMessage *incoming_flood)
953{
954 if (GNUNET_YES != check_proof_of_work (&incoming_flood->origin.public_key,
955 incoming_flood->proof_of_work))
956 {
958 "Proof of work invalid: %llu!\n",
959 (unsigned long long) GNUNET_ntohll (
960 incoming_flood->proof_of_work));
961 GNUNET_break_op (0);
962 return GNUNET_NO;
963 }
964 if ((nse_work_required > 0) &&
965 (GNUNET_OK !=
967 &incoming_flood->purpose,
968 &incoming_flood->signature,
969 &incoming_flood->origin.public_key)))
970 {
971 GNUNET_break_op (0);
972 return GNUNET_NO;
973 }
974 return GNUNET_YES;
975}
976
977
987static int
988update_flood_times (void *cls,
989 const struct GNUNET_PeerIdentity *key,
990 void *value)
991{
992 struct NSEPeerEntry *exclude = cls;
993 struct NSEPeerEntry *peer_entry = value;
994 struct GNUNET_TIME_Relative delay;
995
996 (void) key;
997 if (peer_entry == exclude)
998 return GNUNET_OK; /* trigger of the update */
999 if (GNUNET_NO == peer_entry->previous_round)
1000 {
1001 /* still stuck in previous round, no point to update, check that
1002 * we are active here though... */
1003 if (NULL == peer_entry->transmit_task)
1004 {
1005 GNUNET_break (0);
1006 }
1007 return GNUNET_OK;
1008 }
1009 if (NULL != peer_entry->transmit_task)
1010 {
1012 peer_entry->transmit_task = NULL;
1013 }
1014 delay = get_transmit_delay (0);
1015 peer_entry->transmit_task =
1016 GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
1017 return GNUNET_OK;
1018}
1019
1020
1027static void
1028handle_p2p_estimate (void *cls,
1029 const struct GNUNET_NSE_FloodMessage *incoming_flood)
1030{
1031 struct NSEPeerEntry *peer_entry = cls;
1032 struct GNUNET_TIME_Absolute ts;
1033 uint32_t matching_bits;
1034 unsigned int idx;
1035
1036#if ENABLE_NSE_HISTOGRAM
1037 {
1038 uint64_t t;
1039
1041 if (NULL != lh)
1042 GNUNET_TESTBED_LOGGER_write (lh, &t, sizeof(uint64_t));
1043 if (NULL != histogram)
1044 GNUNET_BIO_write_int64 (histogram, "histogram-time", t);
1045 }
1046#endif
1047 GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO);
1048 matching_bits = ntohl (incoming_flood->matching_bits);
1049#if DEBUG_NSE
1050 {
1051 char origin[5];
1052 char pred[5];
1053 struct GNUNET_PeerIdentity os;
1054
1056 sizeof(origin),
1057 "%s",
1058 GNUNET_i2s (&incoming_flood->origin));
1059 GNUNET_snprintf (pred, sizeof(pred), "%s", GNUNET_i2s (peer_entry->id));
1061 "Flood at %s from `%s' via `%s' at `%s' with bits %u\n",
1063 GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp)),
1064 origin,
1065 pred,
1067 (unsigned int) matching_bits);
1068 }
1069#endif
1070
1071#if ENABLE_NSE_HISTOGRAM
1072 peer_entry->received_messages++;
1073 if ((peer_entry->transmitted_messages > 0) &&
1074 (peer_entry->last_transmitted_size >= matching_bits) )
1075 GNUNET_STATISTICS_update (stats, "# cross messages", 1, GNUNET_NO);
1076#endif
1077
1078 ts = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp);
1080 idx = estimate_index;
1081 else if (ts.abs_value_us ==
1085 {
1087 return; /* ignore, simply too early/late */
1088 if (GNUNET_YES != verify_message_crypto (incoming_flood))
1089 {
1091 "Peer %s is likely ill-configured!\n",
1092 GNUNET_i2s (peer_entry->id));
1093 GNUNET_break_op (0);
1094 return;
1095 }
1096 next_message = *incoming_flood;
1097 return;
1098 }
1099 else
1100 {
1102 "# flood messages discarded (clock skew too large)",
1103 1,
1104 GNUNET_NO);
1105 return;
1106 }
1107 if (0 == (GNUNET_memcmp (peer_entry->id, &my_identity)))
1108 {
1109 /* send to self, update our own estimate IF this also comes from us! */
1110 if (0 == GNUNET_memcmp (&incoming_flood->origin, &my_identity))
1112 return;
1113 }
1115 {
1116 /* Cancel transmission in the other direction, as this peer clearly has
1117 up-to-date information already. Even if we didn't talk to this peer in
1118 the previous round, we should no longer send it stale information as it
1119 told us about the current round! */
1120 peer_entry->previous_round = GNUNET_YES;
1121 if (idx != estimate_index)
1122 {
1123 /* do not transmit information for the previous round to this peer
1124 anymore (but allow current round) */
1125 return;
1126 }
1127 /* got up-to-date information for current round, cancel transmission to
1128 * this peer altogether */
1129 if (NULL != peer_entry->transmit_task)
1130 {
1132 peer_entry->transmit_task = NULL;
1133 }
1134 return;
1135 }
1137 {
1138 if ((idx < estimate_index) && (peer_entry->previous_round == GNUNET_YES))
1139 {
1140 peer_entry->previous_round = GNUNET_NO;
1141 }
1142 /* push back our result now, that peer is spreading bad information... */
1143 if (NULL != peer_entry->transmit_task)
1145 peer_entry->transmit_task =
1147 /* Not closer than our most recent message, no need to do work here */
1149 "# flood messages ignored (had closer already)",
1150 1,
1151 GNUNET_NO);
1152 return;
1153 }
1154 if (GNUNET_YES != verify_message_crypto (incoming_flood))
1155 {
1156 GNUNET_break_op (0);
1157 return;
1158 }
1161 /* Cancel transmission in the other direction, as this peer clearly has
1162 * up-to-date information already.
1163 */
1164 peer_entry->previous_round = GNUNET_YES;
1165 if (idx == estimate_index)
1166 {
1167 /* cancel any activity for current round */
1168 if (NULL != peer_entry->transmit_task)
1169 {
1171 peer_entry->transmit_task = NULL;
1172 }
1173 }
1174 size_estimate_messages[idx] = *incoming_flood;
1176 htonl (ntohl (incoming_flood->hop_count) + 1);
1178 GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1, hop_count_max);
1180 "# estimated network diameter",
1182 GNUNET_NO);
1183
1184 /* have a new, better size estimate, inform clients */
1186
1187 /* flood to rest */
1190 peer_entry);
1191}
1192
1193
1202static void *
1203handle_core_connect (void *cls,
1204 const struct GNUNET_PeerIdentity *peer,
1205 struct GNUNET_MQ_Handle *mq,
1206 enum GNUNET_CORE_PeerClass class)
1207{
1208 struct NSEPeerEntry *peer_entry;
1209
1210 (void) cls;
1212 "Peer `%s' connected to us\n",
1213 GNUNET_i2s (peer));
1214 /* set our default transmission options */
1216 /* create our peer entry for this peer */
1217 peer_entry = GNUNET_new (struct NSEPeerEntry);
1218 peer_entry->id = peer;
1219 peer_entry->mq = mq;
1222 peers,
1223 peer_entry->id,
1224 peer_entry,
1226 peer_entry->transmit_task =
1229 peer_entry);
1230 GNUNET_STATISTICS_update (stats, "# peers connected", 1, GNUNET_NO);
1231 return peer_entry;
1232}
1233
1234
1243static void
1244handle_core_disconnect (void *cls,
1245 const struct GNUNET_PeerIdentity *peer,
1246 void *internal_cls)
1247{
1248 struct NSEPeerEntry *pos = internal_cls;
1249
1250 (void) cls;
1252 "Peer `%s' disconnected from us\n",
1253 GNUNET_i2s (peer));
1256 if (NULL != pos->transmit_task)
1257 {
1259 pos->transmit_task = NULL;
1260 }
1261 GNUNET_free (pos);
1262 GNUNET_STATISTICS_update (stats, "# peers connected", -1, GNUNET_NO);
1263}
1264
1265
1266#if ENABLE_NSE_HISTOGRAM
1274static void
1275flush_comp_cb (void *cls, size_t size)
1276{
1277 (void) cls;
1278 (void) size;
1279 GNUNET_TESTBED_LOGGER_disconnect (lh);
1280 lh = NULL;
1281}
1282
1283
1284#endif
1285
1286
1292static void
1293shutdown_task (void *cls)
1294{
1295 (void) cls;
1296 if (NULL != flood_task)
1297 {
1299 flood_task = NULL;
1300 }
1301 if (NULL != proof_task)
1302 {
1304 proof_task = NULL;
1305 write_proof (); /* remember progress */
1306 }
1307 if (NULL != nc)
1308 {
1310 nc = NULL;
1311 }
1312 if (NULL != core_api)
1313 {
1315 core_api = NULL;
1316 }
1317 if (NULL != stats)
1318 {
1320 stats = NULL;
1321 }
1322 if (NULL != peers)
1323 {
1325 peers = NULL;
1326 }
1327 if (NULL != my_private_key)
1328 {
1330 my_private_key = NULL;
1331 }
1332 if (NULL != pils)
1333 {
1335 pils = NULL;
1336 }
1337#if ENABLE_NSE_HISTOGRAM
1338 if (NULL != logger_test)
1339 {
1340 GNUNET_CLIENT_service_test_cancel (logger_test);
1341 logger_test = NULL;
1342 }
1343 if (NULL != lh)
1344 {
1345 GNUNET_TESTBED_LOGGER_flush (lh, &flush_comp_cb, NULL);
1346 }
1347 if (NULL != histogram)
1348 {
1349 GNUNET_BIO_write_close (histogram, NULL);
1350 histogram = NULL;
1351 }
1352#endif
1353}
1354
1355
1356static void
1358{
1359 struct GNUNET_TIME_Absolute now;
1360 struct GNUNET_TIME_Absolute prev_time;
1361
1362 if (NULL == identity)
1363 {
1364 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection to core FAILED!\n");
1366 return;
1367 }
1369 now = GNUNET_TIME_absolute_get ();
1371 (now.abs_value_us / gnunet_nse_interval.rel_value_us)
1376 estimate_count = 0;
1378 {
1379 int idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1380 prev_time.abs_value_us =
1382 setup_flood_message (idx, prev_time);
1385 }
1386 if (NULL != flood_task)
1388 flood_task =
1390}
1391
1392
1393static void
1394pils_id_change_cb (void *cls,
1395 const struct GNUNET_HELLO_Parser *parser,
1396 const struct GNUNET_HashCode *addr_hash)
1397{
1400}
1401
1402
1409static void
1410core_init (void *cls, const struct GNUNET_PeerIdentity *identity)
1411{
1412 (void) cls;
1414}
1415
1416
1417#if ENABLE_NSE_HISTOGRAM
1426static void
1427status_cb (void *cls, int status)
1428{
1429 (void) cls;
1430 logger_test = NULL;
1431 if (GNUNET_YES != status)
1432 {
1433 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed logger not running\n");
1434 return;
1435 }
1436 if (NULL == (lh = GNUNET_TESTBED_LOGGER_connect (cfg)))
1437 {
1439 "Cannot connect to the testbed logger. Exiting.\n");
1441 }
1442}
1443
1444
1445#endif
1446
1447
1455static void
1456run (void *cls,
1457 const struct GNUNET_CONFIGURATION_Handle *c,
1459{
1460 struct GNUNET_MQ_MessageHandler core_handlers[] =
1461 { GNUNET_MQ_hd_fixed_size (p2p_estimate,
1464 NULL),
1466 char *proof;
1468 const struct GNUNET_CORE_ServiceInfo service_info =
1469 {
1471 .version = { 1, 0 },
1472 .version_max = { 1, 0 },
1473 .version_min = { 1, 0 },
1474 };
1475
1476 (void) cls;
1477 (void) service;
1478 cfg = c;
1480 "NSE",
1481 "INTERVAL",
1483 {
1486 return;
1487 }
1489 "NSE",
1490 "WORKDELAY",
1492 {
1495 return;
1496 }
1498 "NSE",
1499 "WORKBITS",
1501 {
1504 return;
1505 }
1506 if (nse_work_required >= sizeof(struct GNUNET_HashCode) * 8)
1507 {
1509 "NSE",
1510 "WORKBITS",
1511 _ ("Value is too large.\n"));
1513 return;
1514 }
1515
1516#if ENABLE_NSE_HISTOGRAM
1517 {
1518 char *histogram_dir;
1519 char *histogram_fn;
1520
1522 "NSE",
1523 "HISTOGRAM_DIR",
1524 &histogram_dir))
1525 {
1527 0 < GNUNET_asprintf (&histogram_fn, "%s/timestamps", histogram_dir));
1528 GNUNET_free (histogram_dir);
1529 histogram = GNUNET_BIO_write_open_file (histogram_fn);
1530 if (NULL == histogram)
1532 "Unable to open histogram file `%s'\n",
1533 histogram_fn);
1534 GNUNET_free (histogram_fn);
1535 }
1536 logger_test = GNUNET_CLIENT_service_test ("testbed-logger",
1537 cfg,
1539 &status_cb,
1540 NULL);
1541 }
1542#endif
1543
1546 GNUNET_assert (NULL != pk);
1549 if (GNUNET_OK !=
1550 GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
1551 {
1554 my_private_key = NULL;
1556 return;
1557 }
1559 (sizeof(my_proof) !=
1561 my_proof = 0;
1563 proof_task =
1565 &find_proof,
1566 NULL);
1567
1570 /* Connect to core service and register core handlers */
1571 core_api =
1572 GNUNET_CORE_connect (cfg, /* Main configuration */
1573 NULL, /* Closure passed to functions */
1574 &core_init, /* Call core_init once connected */
1575 &handle_core_connect, /* Handle connects */
1576 &handle_core_disconnect, /* Handle disconnects */
1577 core_handlers, /* Register these handlers */
1578 &service_info );
1579 if (NULL == core_api)
1580 {
1582 return;
1583 }
1585 if (NULL == pils)
1586 {
1587 GNUNET_break (0);
1589 return;
1590 }
1592}
1593
1594
1603static void *
1604client_connect_cb (void *cls,
1605 struct GNUNET_SERVICE_Client *c,
1606 struct GNUNET_MQ_Handle *mq)
1607{
1608 (void) cls;
1609 (void) mq;
1610 return c;
1611}
1612
1613
1621static void
1622client_disconnect_cb (void *cls,
1623 struct GNUNET_SERVICE_Client *c,
1624 void *internal_cls)
1625{
1626 (void) cls;
1627 GNUNET_assert (c == internal_cls);
1628}
1629
1630
1635 "nse",
1637 &run,
1640 NULL,
1643 struct GNUNET_MessageHeader,
1644 NULL),
1646
1647
1648#if defined(__linux__) && defined(__GLIBC__)
1649#include <malloc.h>
1650
1651void __attribute__ ((constructor))
1652GNUNET_NSE_memory_init (void);
1653
1657void __attribute__ ((constructor))
1658GNUNET_NSE_memory_init (void)
1659{
1660 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1661 mallopt (M_TOP_PAD, 1 * 1024);
1662 malloc_trim (0);
1663}
1664
1665
1666#endif
1667
1668
1669/* end of gnunet-service-nse.c */
struct GNUNET_MQ_Envelope * env
Definition 005.c:1
static mp_limb_t d[(((256)+GMP_NUMB_BITS - 1)/GMP_NUMB_BITS)]
static int start
Set if we are to start default services (including ARM).
Definition gnunet-arm.c:38
static int ret
Final status code.
Definition gnunet-arm.c:93
static uint64_t timestamp(void)
Get current timestamp.
struct GNUNET_HashCode key
The key used in the DHT.
struct GNUNET_CRYPTO_PrivateKey pk
Private key from command line option, or NULL.
struct GNUNET_SCHEDULER_Task * shutdown_task
static char * pkey
Public key of the zone to look in, in ASCII.
static char origin[GNUNET_DNSPARSER_MAX_NAME_LENGTH]
Current origin.
static char * value
Value of the record to add/remove.
static int status
The program status; 0 for success.
Definition gnunet-nse.c:39
static struct GNUNET_IDENTITY_Handle * identity
Which namespace do we publish to? NULL if we do not publish to a namespace.
static int result
Global testing status.
static struct GNUNET_REVOCATION_Query * q
Handle for revocation query.
static unsigned long long matching_bits
Number of matching bits required for revocation.
static uint64_t proof
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
static struct GNUNET_CONTAINER_MultiPeerMap * peers
Map of all connected peers.
static double current_std_dev
The standard deviation of the last HISTORY_SIZE network size estimates.
static struct GNUNET_NSE_FloodMessage size_estimate_messages[64]
Array of recent size estimate messages.
static void update_flood_message(void *cls)
Update our flood message to be sent (and our timestamps).
static void transmit_task_cb(void *cls)
Task that triggers a NSE P2P transmission.
static void core_init(void *cls, const struct GNUNET_PeerIdentity *identity)
Called on core init/fail.
static int update_flood_times(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Update transmissions for the given peer for the current round based on updated proximity information.
static double get_matching_bits_delay(uint32_t matching_bits)
How long should we delay a message to go the given number of matching bits?
static unsigned int estimate_index
Index of most recent estimate.
static struct GNUNET_TIME_Relative gnunet_nse_interval
Interval for sending network size estimation flood requests.
static struct GNUNET_PeerIdentity my_identity
The peer identity of this peer.
#define NSE_PRIORITY
Message priority to use.
#define HISTORY_SIZE
Over how many values do we calculate the weighted average?
static enum GNUNET_GenericReturnValue check_proof_of_work(const struct GNUNET_CRYPTO_EddsaPublicKey *pkey, uint64_t val)
Check whether the given public key and integer are a valid proof of work.
static struct GNUNET_STATISTICS_Handle * stats
Handle to the statistics service.
static void setup_estimate_message(struct GNUNET_NSE_ClientMessage *em)
Initialize a message to clients with the current network size estimate.
static struct GNUNET_SCHEDULER_Task * proof_task
Task scheduled to compute our proof.
static struct GNUNET_TIME_Absolute current_timestamp
The current major time.
static void sign_message_before_send_cb(void *cls, const struct GNUNET_PeerIdentity *pid, const struct GNUNET_CRYPTO_EddsaSignature *sig)
static struct GNUNET_NotificationContext * nc
Notification context, simplifies client broadcasts.
static void find_proof(void *cls)
Find our proof of work.
static unsigned int estimate_count
Number of valid entries in the history.
static void update_network_size_estimate()
We've sent on our flood message or one that we received which was validated and closer than ours.
static struct GNUNET_TIME_Relative proof_find_delay
Interval between proof find runs.
static void identity_changed(const struct GNUNET_PeerIdentity *identity)
static int verify_message_crypto(const struct GNUNET_NSE_FloodMessage *incoming_flood)
An incoming flood message has been received which claims to have more bits matching than any we know ...
static uint64_t my_proof
Proof of work for this peer.
static struct GNUNET_CORE_Handle * core_api
Handle to the core service.
static unsigned long long nse_work_required
Amount of work required (W-bit collisions) for NSE proofs, in collision-bits.
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service)
Handle network size estimate clients.
static GNUNET_NETWORK_STRUCT_END const struct GNUNET_CONFIGURATION_Handle * cfg
Handle to our current configuration.
static void setup_flood_message(unsigned int slot, struct GNUNET_TIME_Absolute ts)
Setup a flood message in our history array at the given slot offset for the given timestamp.
static int schedule_current_round(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Schedule transmission for the given peer for the current round based on what we know about the desire...
static uint32_t hop_count_max
Current hop counter estimate (estimate for network diameter).
static struct GNUNET_TIME_Relative get_transmit_delay(int round_offset)
Get the transmission delay that should be applied for a particular round.
#define ROUND_SIZE
static void handle_start(void *cls, const struct GNUNET_MessageHeader *message)
Handler for START message from client, triggers an immediate current network estimate notification.
static struct GNUNET_NSE_FloodMessage next_message
Message for the next round, if we got any.
static struct GNUNET_SCHEDULER_Task * flood_task
Task scheduled to update our flood message for the next round.
static struct GNUNET_TIME_Absolute next_timestamp
The next major time.
static struct GNUNET_CRYPTO_PowSalt salt
Salt for PoW calculations.
static struct GNUNET_TIME_Relative get_delay_randomization(uint32_t matching_bits)
What delay randomization should we apply for a given number of matching bits?
static double current_size_estimate
The current network size estimate.
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *c, struct GNUNET_MQ_Handle *mq)
Callback called when a client connects to the service.
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *c, void *internal_cls)
Callback called when a client disconnected from the service.
static void write_proof(void)
Write our current proof to disk.
static struct GNUNET_CRYPTO_EddsaPrivateKey * my_private_key
The private key of this peer.
static void handle_p2p_estimate(void *cls, const struct GNUNET_NSE_FloodMessage *incoming_flood)
Core handler for size estimate flooding messages.
static void handle_core_disconnect(void *cls, const struct GNUNET_PeerIdentity *peer, void *internal_cls)
Method called whenever a peer disconnects.
static void * handle_core_connect(void *cls, const struct GNUNET_PeerIdentity *peer, struct GNUNET_MQ_Handle *mq, enum GNUNET_CORE_PeerClass class)
Method called whenever a peer connects.
static struct GNUNET_PILS_Handle * pils
Handle to the PILS service.
static uint32_t get_matching_bits(struct GNUNET_TIME_Absolute timestamp, const struct GNUNET_PeerIdentity *id)
Get the number of matching bits that the given timestamp has to the given peer ID.
static void pils_id_change_cb(void *cls, const struct GNUNET_HELLO_Parser *parser, const struct GNUNET_HashCode *addr_hash)
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
static struct GNUNET_SCHEDULER_Task * t
Main task.
struct GNUNET_PILS_Handle * GNUNET_PILS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_PILS_PidChangeCallback pid_change_cb, void *cls)
Connect to the PILS service.
Definition pils_api.c:367
void GNUNET_PILS_disconnect(struct GNUNET_PILS_Handle *handle)
Disconnect from the PILS service.
Definition pils_api.c:390
struct GNUNET_PILS_Operation * GNUNET_PILS_sign_by_peer_identity(struct GNUNET_PILS_Handle *handle, const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, GNUNET_PILS_SignResultCallback cb, void *cb_cls)
Sign data with the peer id.
Definition pils_api.c:428
struct GNUNET_PQ_ResultSpec __attribute__
#define GNUNET_SIGNATURE_PURPOSE_NSE_SEND
Signature of a network size estimate message.
enum GNUNET_GenericReturnValue GNUNET_BIO_write_close(struct GNUNET_BIO_WriteHandle *h, char **emsg)
Close an IO handle.
Definition bio.c:556
struct GNUNET_BIO_WriteHandle * GNUNET_BIO_write_open_file(const char *fn)
Open a file for writing.
Definition bio.c:508
enum GNUNET_GenericReturnValue GNUNET_BIO_write_int64(struct GNUNET_BIO_WriteHandle *h, const char *what, int64_t i)
Write an (u)int64_t.
Definition bio.c:865
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_time(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, struct GNUNET_TIME_Relative *time)
Get a configuration value that should be a relative time.
GNUNET_CORE_PeerClass
The peer class gives a hint about the capabilities of a peer.
struct GNUNET_CORE_Handle * GNUNET_CORE_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls, GNUNET_CORE_StartupCallback init, GNUNET_CORE_ConnectEventHandler connects, GNUNET_CORE_DisconnectEventHandler disconnects, const struct GNUNET_MQ_MessageHandler *handlers, struct GNUNET_CORE_ServiceInfo *service_info)
Connect to the core service.
Definition core_api.c:698
void GNUNET_CORE_disconnect(struct GNUNET_CORE_Handle *handle)
Disconnect from the core service.
Definition core_api.c:744
@ GNUNET_CORE_SERVICE_NSE
Identifier for nse (network size estimation) service.
uint64_t GNUNET_CRYPTO_random_u64(enum GNUNET_CRYPTO_Quality mode, uint64_t max)
Generate a random unsigned 64-bit value.
void GNUNET_CRYPTO_eddsa_key_get_public(const struct GNUNET_CRYPTO_EddsaPrivateKey *priv, struct GNUNET_CRYPTO_EddsaPublicKey *pub)
Extract the public key for the given private key.
Definition crypto_ecc.c:201
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random value.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_eddsa_verify_(uint32_t purpose, const struct GNUNET_CRYPTO_EccSignaturePurpose *validate, const struct GNUNET_CRYPTO_EddsaSignature *sig, const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
Verify EdDSA signature.
Definition crypto_ecc.c:708
struct GNUNET_CRYPTO_EddsaPrivateKey * GNUNET_CRYPTO_eddsa_key_create_from_configuration(const struct GNUNET_CONFIGURATION_Handle *cfg)
Create a new private key by reading our peer's key from the file specified in the configuration.
@ GNUNET_CRYPTO_QUALITY_WEAK
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
enum GNUNET_GenericReturnValue GNUNET_DISK_file_test(const char *fil)
Check that fil corresponds to a filename (of a file that exists and that is not a directory).
Definition disk.c:533
enum GNUNET_GenericReturnValue GNUNET_DISK_fn_write(const char *fn, const void *buf, size_t buf_size, enum GNUNET_DISK_AccessPermissions mode)
Write a buffer to a file atomically.
Definition disk.c:750
enum GNUNET_GenericReturnValue GNUNET_DISK_directory_remove(const char *filename)
Remove all files in a directory (rm -rf).
Definition disk.c:1098
ssize_t GNUNET_DISK_fn_read(const char *fn, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition disk.c:687
@ GNUNET_DISK_PERM_USER_READ
Owner can read.
@ GNUNET_DISK_PERM_USER_WRITE
Owner can write.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition crypto_hash.c:41
void GNUNET_CRYPTO_hash_xor(const struct GNUNET_HashCode *a, const struct GNUNET_HashCode *b, struct GNUNET_HashCode *result)
compute result = a ^ b
void GNUNET_CONTAINER_multipeermap_destroy(struct GNUNET_CONTAINER_MultiPeerMap *map)
Destroy a hash map.
int GNUNET_CONTAINER_multipeermap_iterate(struct GNUNET_CONTAINER_MultiPeerMap *map, GNUNET_CONTAINER_PeerMapIterator it, void *it_cls)
Iterate over all entries in the map.
struct GNUNET_CONTAINER_MultiPeerMap * GNUNET_CONTAINER_multipeermap_create(unsigned int len, int do_not_copy_keys)
Create a multi peer map (hash map for public keys of peers).
unsigned int GNUNET_CONTAINER_multipeermap_size(const struct GNUNET_CONTAINER_MultiPeerMap *map)
Get the number of key-value pairs in the map.
int GNUNET_CONTAINER_multipeermap_put(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multipeermap_remove(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, const void *value)
Remove the given key-value pair from the map.
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY
There must only be one value per key; storing a value should fail if a value under the same key alrea...
const struct GNUNET_PeerIdentity * GNUNET_HELLO_parser_get_id(const struct GNUNET_HELLO_Parser *parser)
Get the PeerIdentity for this builder.
Definition hello-uri.c:353
unsigned int GNUNET_CRYPTO_hash_count_leading_zeros(const struct GNUNET_HashCode *h)
Count the number of leading 0 bits in h.
#define GNUNET_NETWORK_STRUCT_BEGIN
Define as empty, GNUNET_PACKED should suffice, but this won't work on W32.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
#define GNUNET_MAX(a, b)
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
void GNUNET_CRYPTO_pow_hash(const struct GNUNET_CRYPTO_PowSalt *salt, const void *buf, size_t buf_len, struct GNUNET_HashCode *result)
Calculate the 'proof-of-work' hash (an expensive hash).
Definition crypto_pow.c:42
#define GNUNET_NETWORK_STRUCT_END
Define as empty, GNUNET_PACKED should suffice, but this won't work on W32;.
double GNUNET_hton_double(double d)
Convert double to network byte order.
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
#define GNUNET_ALIGN
gcc-ism to force alignment; we use this to align char-arrays that may then be cast to 'struct's.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
#define GNUNET_PACKED
gcc-ism to get packed structs.
@ GNUNET_SCHEDULER_PRIORITY_IDLE
Run when otherwise idle.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
void GNUNET_log_config_invalid(enum GNUNET_ErrorType kind, const char *section, const char *option, const char *required)
Log error message about invalid configuration option value.
void GNUNET_log_config_missing(enum GNUNET_ErrorType kind, const char *section, const char *option)
Log error message about missing configuration option.
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
int GNUNET_snprintf(char *buf, size_t size, const char *format,...) __attribute__((format(printf
Like snprintf, just aborts if the buffer is of insufficient size.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_notification_context_destroy(struct GNUNET_NotificationContext *nc)
Destroy the context, force disconnect for all subscribers.
Definition nc.c:138
struct GNUNET_MQ_Envelope * GNUNET_MQ_msg_copy(const struct GNUNET_MessageHeader *hdr)
Create a new envelope by copying an existing message.
Definition mq.c:550
void GNUNET_MQ_set_options(struct GNUNET_MQ_Handle *mq, enum GNUNET_MQ_PriorityPreferences pp)
Set application-specific options for this queue.
Definition mq.c:888
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition mq.c:305
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
struct GNUNET_NotificationContext * GNUNET_notification_context_create(unsigned int queue_length)
Create a new notification context.
Definition nc.c:122
void GNUNET_notification_context_broadcast(struct GNUNET_NotificationContext *nc, const struct GNUNET_MessageHeader *msg, int can_drop)
Send a message to all subscribers of this context.
Definition nc.c:190
#define GNUNET_MQ_hd_fixed_size(name, code, str, ctx)
void GNUNET_notification_context_add(struct GNUNET_NotificationContext *nc, struct GNUNET_MQ_Handle *mq)
Add a subscriber to the notification context.
Definition nc.c:161
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
#define GNUNET_MESSAGE_TYPE_NSE_START
client->service message indicating start
#define GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD
P2P message sent from nearest peer.
#define GNUNET_MESSAGE_TYPE_NSE_ESTIMATE
service->client message indicating
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition scheduler.c:567
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_at(struct GNUNET_TIME_Absolute at, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run at the specified time.
Definition scheduler.c:1254
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition scheduler.c:1339
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:980
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition scheduler.c:1304
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition scheduler.c:1277
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed_with_priority(struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition scheduler.c:1207
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_with_priority(enum GNUNET_SCHEDULER_Priority prio, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified priority.
Definition scheduler.c:1231
#define GNUNET_SERVICE_MAIN(pd, service_name, service_options, init_cb, connect_cb, disconnect_cb, cls,...)
Creates the "main" function for a GNUnet service.
struct GNUNET_MQ_Handle * GNUNET_SERVICE_client_get_mq(struct GNUNET_SERVICE_Client *c)
Obtain the message queue of c.
Definition service.c:2544
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition service.c:2433
@ GNUNET_SERVICE_OPTION_NONE
Use defaults.
struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create(const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg)
Get handle for the statistics service.
void GNUNET_STATISTICS_set(struct GNUNET_STATISTICS_Handle *handle, const char *name, uint64_t value, int make_persistent)
Set statistic value for the peer.
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
void GNUNET_STATISTICS_destroy(struct GNUNET_STATISTICS_Handle *h, int sync_first)
Destroy a handle (free all state associated with it).
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
#define GNUNET_TIME_UNIT_SECONDS
One second.
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition time.c:406
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition strings.c:599
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition time.c:111
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_ntoh(struct GNUNET_TIME_AbsoluteNBO a)
Convert absolute time from network byte order.
Definition time.c:741
#define GNUNET_TIME_UNIT_ZERO
Relative time zero.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_add(struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Relative duration)
Add a given relative duration to the given start time.
Definition time.c:452
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition time.c:640
const char * GNUNET_STRINGS_absolute_time_to_string(struct GNUNET_TIME_Absolute t)
Like asctime, except for GNUnet time.
Definition strings.c:660
static unsigned int size
Size of the "table".
Definition peer.c:68
#define _(String)
GNU gettext support macro.
Definition platform.h:179
static struct GNUNET_MQ_Handle * mq
Our connection to the resolver service, created on-demand, but then persists until error or shutdown.
Internal representation of the hash map.
Context for the core service connection.
Definition core_api.c:78
Gnunet service info - identifying compatibility with a range of version of a service communicating ov...
enum GNUNET_CORE_Service service
Identifier of the service on top of CORE.
header of what an ECC signature signs this must be followed by "size - 8" bytes of the actual signed ...
uint32_t size
How many bytes does this signature sign? (including this purpose header); in network byte order (!...
uint32_t purpose
What does this signature vouch for? This must contain a GNUNET_SIGNATURE_PURPOSE_XXX constant (from g...
Private ECC key encoded for transmission.
Public ECC key (always for curve Ed25519) encoded in a format suitable for network transmission and E...
an ECC signature using EdDSA.
Context for parsing HELLOs.
Definition hello-uri.c:232
A 512-bit hashcode.
Handle to a message queue.
Definition mq.c:87
Message handler for a specific message type.
Header for all communications.
Network size estimate sent from the service to clients.
Definition nse.h:43
Network size estimate reply; sent when "this" peer's timer has run out before receiving a valid reply...
uint32_t hop_count
Number of hops this message has taken so far.
uint32_t matching_bits
Number of matching bits between the hash of timestamp and the initiator's public key.
struct GNUNET_TIME_AbsoluteNBO timestamp
The current timestamp value (which all peers should agree on).
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD.
struct GNUNET_PeerIdentity origin
Public key of the originator.
uint64_t proof_of_work
Proof of work, causing leading zeros when hashed with pkey.
struct GNUNET_CRYPTO_EccSignaturePurpose purpose
Purpose.
struct GNUNET_CRYPTO_EddsaSignature signature
Signature (over range specified in purpose).
The notification context is the key datastructure for a convenience API used for transmission of noti...
Definition nc.c:77
A handle for the PILS service.
Definition pils_api.c:82
The identity of the host (wraps the signing key of the peer).
struct GNUNET_CRYPTO_EddsaPublicKey public_key
Entry in list of pending tasks.
Definition scheduler.c:136
Handle to a client that is connected to a service.
Definition service.c:249
Handle to a service.
Definition service.c:116
Handle for the service.
Time for absolute time used by GNUnet, in microseconds and in network byte order.
Time for absolute times used by GNUnet, in microseconds.
uint64_t abs_value_us
The actual value.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
Per-peer information.
struct GNUNET_PILS_Operation * pils_op
PILS Operation.
struct GNUNET_MQ_Handle * mq
Core handle for sending messages to this peer.
struct GNUNET_SCHEDULER_Task * transmit_task
Task scheduled to send message to this peer.
const struct GNUNET_PeerIdentity * id
What is the identity of the peer?
int previous_round
Did we receive or send a message about the previous round to this peer yet? GNUNET_YES if the previou...
uint32_t next_index_to_send
Message to be sent.

◆ WEST

#define WEST   1

◆ ROUND_SIZE

#define ROUND_SIZE   10

Function Documentation

◆ setup_estimate_message()

static void setup_estimate_message ( struct GNUNET_NSE_ClientMessage em)
static

Initialize a message to clients with the current network size estimate.

Parameters
emmessage to fill in

Definition at line 342 of file gnunet-service-nse.c.

343{
344 double mean;
345 double sum;
346 double std_dev;
347 double variance;
348 double val;
349 double nsize;
350
351#define WEST 1
352 /* Weighted incremental algorithm for stddev according to West (1979) */
353#if WEST
354 double sumweight;
355 double weight;
356 double q;
357 double r;
358 double temp;
359
360 mean = 0.0;
361 sum = 0.0;
362 sumweight = 0.0;
363 variance = 0.0;
364 for (unsigned int i = 0; i < estimate_count; i++)
365 {
366 unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE;
367
368 val = htonl (size_estimate_messages[j].matching_bits);
369 weight = estimate_count + 1 - i;
370
371 temp = weight + sumweight;
372 q = val - mean;
373 r = q * weight / temp;
374 mean += r;
375 sum += sumweight * q * r;
376 sumweight = temp;
377 }
378 if (estimate_count > 0)
379 variance = (sum / sumweight) * estimate_count / (estimate_count - 1.0);
380#else
381 /* trivial version for debugging */
382 double vsq;
383
384 /* non-weighted trivial version */
385 sum = 0.0;
386 vsq = 0.0;
387 variance = 0.0;
388 mean = 0.0;
389
390 for (unsigned int i = 0; i < estimate_count; i++)
391 {
392 unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE;
393
394 val = htonl (size_estimate_messages[j].matching_bits);
395 sum += val;
396 vsq += val * val;
397 }
398 if (0 != estimate_count)
399 {
400 mean = sum / estimate_count;
401 variance = (vsq - mean * sum)
402 / (estimate_count - 1.0); // terrible for numerical stability...
403 }
404#endif
405 if (variance >= 0)
406 std_dev = sqrt (variance);
407 else
408 std_dev = variance; /* return NaN (due to estimate_count == 0 causing 0.0/0.0) */
409 current_std_dev = std_dev;
411
412 em->header.size = htons (sizeof(struct GNUNET_NSE_ClientMessage));
414 em->reserved = htonl (0);
416 {
417 double se = mean - 0.332747;
418 unsigned int j = GNUNET_CONTAINER_multipeermap_size (peers);
419 if (0 == j)
420 j = 1; /* Avoid log2(0); can only happen if CORE didn't report
421 connection to self yet */
422 nsize = log2 (j);
423 em->size_estimate = GNUNET_hton_double (GNUNET_MAX (se, nsize));
424 em->std_deviation = GNUNET_hton_double (std_dev);
426 "# nodes in the network (estimate)",
427 (uint64_t) pow (2, GNUNET_MAX (se, nsize)),
428 GNUNET_NO);
429 }
430}
uint32_t reserved
For alignment.
Definition nse.h:52
double size_estimate
The current estimated network size.
Definition nse.h:62
struct GNUNET_TIME_AbsoluteNBO timestamp
Timestamp at which the server received the message.
Definition nse.h:57
double std_deviation
The standard deviation (rounded down to the nearest integer) of size estimations.
Definition nse.h:69
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_NSE_ESTIMATE.
Definition nse.h:47

References current_size_estimate, current_std_dev, estimate_count, estimate_index, GNUNET_CONTAINER_multipeermap_size(), GNUNET_hton_double(), GNUNET_MAX, GNUNET_MESSAGE_TYPE_NSE_ESTIMATE, GNUNET_NO, GNUNET_STATISTICS_set(), GNUNET_TIME_absolute_get(), GNUNET_TIME_absolute_hton(), GNUNET_NSE_ClientMessage::header, HISTORY_SIZE, matching_bits, peers, q, GNUNET_NSE_ClientMessage::reserved, GNUNET_MessageHeader::size, GNUNET_NSE_ClientMessage::size_estimate, size_estimate_messages, stats, GNUNET_NSE_ClientMessage::std_deviation, GNUNET_NSE_ClientMessage::timestamp, and GNUNET_MessageHeader::type.

Referenced by handle_start(), and update_network_size_estimate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_start()

static void handle_start ( void *  cls,
const struct GNUNET_MessageHeader message 
)
static

Handler for START message from client, triggers an immediate current network estimate notification.

Also, we remember the client for updates upon future estimate measurements.

Parameters
clsclient who sent the message
messagethe message received

Definition at line 443 of file gnunet-service-nse.c.

444{
445 struct GNUNET_SERVICE_Client *client = cls;
446 struct GNUNET_MQ_Handle *mq;
447 struct GNUNET_NSE_ClientMessage em;
448 struct GNUNET_MQ_Envelope *env;
449
450 (void) message;
451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received START message from client\n");
455 env = GNUNET_MQ_msg_copy (&em.header);
458}

References env, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_MQ_msg_copy(), GNUNET_MQ_send(), GNUNET_notification_context_add(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_get_mq(), GNUNET_NSE_ClientMessage::header, mq, nc, and setup_estimate_message().

Here is the call graph for this function:

◆ get_matching_bits_delay()

static double get_matching_bits_delay ( uint32_t  matching_bits)
static

How long should we delay a message to go the given number of matching bits?

Parameters
matching_bitsnumber of matching bits to consider

Definition at line 468 of file gnunet-service-nse.c.

469{
470 /* Calculated as: S + f/2 - (f / pi) * (atan(x - p')) */
471 // S is next_timestamp (ignored in return value)
472 // f is frequency (gnunet_nse_interval)
473 // x is matching_bits
474 // p' is current_size_estimate
475 return ((double) gnunet_nse_interval.rel_value_us / (double) 2.0)
478}

References current_size_estimate, gnunet_nse_interval, matching_bits, and GNUNET_TIME_Relative::rel_value_us.

Referenced by get_delay_randomization(), and get_transmit_delay().

Here is the caller graph for this function:

◆ get_delay_randomization()

static struct GNUNET_TIME_Relative get_delay_randomization ( uint32_t  matching_bits)
static

What delay randomization should we apply for a given number of matching bits?

Parameters
matching_bitsnumber of matching bits
Returns
random delay to apply

Definition at line 488 of file gnunet-service-nse.c.

489{
490#if USE_RANDOM_DELAYS
492 uint32_t i;
493 double d;
494
496 i = (uint32_t) (d / (double) (hop_count_max + 1));
497 ret.rel_value_us = i;
499 "Randomizing flood using latencies up to %s\n",
501 ret.rel_value_us =
503 return ret;
504#else
506#endif
507}

References d, get_matching_bits_delay(), GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CRYPTO_random_u32(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_STRINGS_relative_time_to_string(), GNUNET_TIME_UNIT_ZERO, GNUNET_YES, hop_count_max, matching_bits, and ret.

Referenced by get_transmit_delay().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_matching_bits()

static uint32_t get_matching_bits ( struct GNUNET_TIME_Absolute  timestamp,
const struct GNUNET_PeerIdentity id 
)
static

Get the number of matching bits that the given timestamp has to the given peer ID.

Parameters
timestamptime to generate key
idpeer identity to compare with
Returns
number of matching bits

Definition at line 518 of file gnunet-service-nse.c.

520{
521 struct GNUNET_HashCode timestamp_hash;
522 struct GNUNET_HashCode pid_hash;
523 struct GNUNET_HashCode xor;
524
525 GNUNET_CRYPTO_hash (&timestamp.abs_value_us,
526 sizeof(timestamp.abs_value_us),
527 &timestamp_hash);
529 sizeof(struct GNUNET_PeerIdentity),
530 &pid_hash);
531 GNUNET_CRYPTO_hash_xor (&pid_hash,
532 &timestamp_hash,
533 &xor);
535}

References GNUNET_CRYPTO_hash(), GNUNET_CRYPTO_hash_count_leading_zeros(), GNUNET_CRYPTO_hash_xor(), and timestamp().

Referenced by setup_flood_message(), and update_flood_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_transmit_delay()

static struct GNUNET_TIME_Relative get_transmit_delay ( int  round_offset)
static

Get the transmission delay that should be applied for a particular round.

Parameters
round_offset-1 for the previous round (random delay between 0 and 50ms) 0 for the current round (based on our proximity to time key)
Returns
delay that should be applied

Definition at line 547 of file gnunet-service-nse.c.

548{
550 struct GNUNET_TIME_Absolute tgt;
551 double dist_delay;
552 uint32_t matching_bits;
553
554 switch (round_offset)
555 {
556 case -1:
557 /* previous round is randomized between 0 and 50 ms */
558#if USE_RANDOM_DELAYS
559 ret.rel_value_us =
561#else
563#endif
565 "Transmitting previous round behind schedule in %s\n",
567 return ret;
568
569 case 0:
570 /* current round is based on best-known matching_bits */
575 ret.rel_value_us = (uint64_t) dist_delay;
577 "For round %s, delay for %u matching bits is %s\n",
579 (unsigned int) matching_bits,
581 /* now consider round start time and add delay to it */
584 }
585 GNUNET_break (0);
587}

References current_timestamp, estimate_index, get_delay_randomization(), get_matching_bits_delay(), GNUNET_break, GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CRYPTO_random_u64(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_STRINGS_absolute_time_to_string(), GNUNET_STRINGS_relative_time_to_string(), GNUNET_TIME_absolute_add(), GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_TIME_UNIT_ZERO, GNUNET_YES, matching_bits, GNUNET_TIME_Relative::rel_value_us, ret, and size_estimate_messages.

Referenced by handle_core_connect(), schedule_current_round(), transmit_task_cb(), and update_flood_times().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sign_message_before_send_cb()

static void sign_message_before_send_cb ( void *  cls,
const struct GNUNET_PeerIdentity pid,
const struct GNUNET_CRYPTO_EddsaSignature sig 
)
static

Definition at line 590 of file gnunet-service-nse.c.

593{
594 struct NSEPeerEntry *pe = cls;
595 struct GNUNET_MQ_Envelope *env;
596 struct GNUNET_NSE_FloodMessage *fm;
597
598 pe->pils_op = NULL;
600 fm->signature = *sig;
602 GNUNET_MQ_send (pe->mq, env);
603}

References env, GNUNET_MQ_msg_copy(), GNUNET_MQ_send(), GNUNET_NSE_FloodMessage::header, NSEPeerEntry::mq, NSEPeerEntry::next_index_to_send, NSEPeerEntry::pils_op, GNUNET_NSE_FloodMessage::signature, and size_estimate_messages.

Referenced by transmit_task_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ transmit_task_cb()

static void transmit_task_cb ( void *  cls)
static

Task that triggers a NSE P2P transmission.

Parameters
clsthe struct NSEPeerEntry *

Definition at line 612 of file gnunet-service-nse.c.

613{
614 struct NSEPeerEntry *peer_entry = cls;
615 unsigned int idx;
616
617 peer_entry->transmit_task = NULL;
618 idx = estimate_index;
619 if (GNUNET_NO == peer_entry->previous_round)
620 {
621 idx = (idx + HISTORY_SIZE - 1) % HISTORY_SIZE;
622 peer_entry->previous_round = GNUNET_YES;
623 peer_entry->transmit_task =
626 peer_entry);
627 }
628 if ((0 == ntohl (size_estimate_messages[idx].hop_count)) &&
629 (NULL != proof_task))
630 {
632 "# flood messages not generated (no proof yet)",
633 1,
634 GNUNET_NO);
635 return;
636 }
637 if (0 == ntohs (size_estimate_messages[idx].header.size))
638 {
640 "# flood messages not generated (lack of history)",
641 1,
642 GNUNET_NO);
643 return;
644 }
646 "In round %s, sending to `%s' estimate with %u bits\n",
650 GNUNET_i2s (peer_entry->id),
651 (unsigned int) ntohl (size_estimate_messages[idx].matching_bits));
652 if (0 == ntohl (size_estimate_messages[idx].hop_count))
653 GNUNET_STATISTICS_update (stats, "# flood messages started", 1, GNUNET_NO);
655 "# flood messages transmitted",
656 1,
657 GNUNET_NO);
658#if ENABLE_NSE_HISTOGRAM
659 peer_entry->transmitted_messages++;
660 peer_entry->last_transmitted_size =
662#endif
663 peer_entry->next_index_to_send = idx;
665 pils,
666 &size_estimate_messages[idx].purpose,
668 peer_entry);
669}

References estimate_index, get_transmit_delay(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_PILS_sign_by_peer_identity(), GNUNET_SCHEDULER_add_delayed(), GNUNET_STATISTICS_update(), GNUNET_STRINGS_absolute_time_to_string(), GNUNET_TIME_absolute_ntoh(), GNUNET_YES, HISTORY_SIZE, NSEPeerEntry::id, matching_bits, NSEPeerEntry::next_index_to_send, pils, NSEPeerEntry::pils_op, NSEPeerEntry::previous_round, proof_task, sign_message_before_send_cb(), size_estimate_messages, stats, timestamp(), NSEPeerEntry::transmit_task, and transmit_task_cb().

Referenced by handle_core_connect(), handle_p2p_estimate(), schedule_current_round(), transmit_task_cb(), and update_flood_times().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_network_size_estimate()

static void update_network_size_estimate ( )
static

We've sent on our flood message or one that we received which was validated and closer than ours.

Update the global list of recent messages and the average. Also re-broadcast the message to any clients.

Definition at line 680 of file gnunet-service-nse.c.

681{
682 struct GNUNET_NSE_ClientMessage em;
683
686}

References GNUNET_notification_context_broadcast(), GNUNET_YES, GNUNET_NSE_ClientMessage::header, nc, and setup_estimate_message().

Referenced by handle_p2p_estimate(), and load_underlay().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setup_flood_message()

static void setup_flood_message ( unsigned int  slot,
struct GNUNET_TIME_Absolute  ts 
)
static

Setup a flood message in our history array at the given slot offset for the given timestamp.

Parameters
slotindex to use
tstimestamp to use

Definition at line 697 of file gnunet-service-nse.c.

698{
699 struct GNUNET_NSE_FloodMessage *fm;
700 uint32_t matching_bits;
701
703 fm = &size_estimate_messages[slot];
704 fm->header.size = htons (sizeof(struct GNUNET_NSE_FloodMessage));
706 fm->hop_count = htonl (0);
708 fm->purpose.size =
709 htonl (sizeof(struct GNUNET_NSE_FloodMessage)
710 - sizeof(struct GNUNET_MessageHeader) - sizeof(uint32_t)
711 - sizeof(struct GNUNET_CRYPTO_EddsaSignature));
712 fm->matching_bits = htonl (matching_bits);
714 fm->origin = my_identity;
716 /* FIXME: We now sign asyncronuously later per sent message because
717 * of PILS. This is probably inefficient. But it may also cause race
718 * conditions wrt the signature (?)
719 * if (nse_work_required > 0)
720 GNUNET_assert (GNUNET_OK ==
721 GNUNET_CRYPTO_eddsa_sign_ (my_private_key,
722 &fm->purpose,
723 &fm->signature));
724 else
725 memset (&fm->signature, 0, sizeof(fm->signature));*/
726}

References get_matching_bits(), GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD, GNUNET_SIGNATURE_PURPOSE_NSE_SEND, GNUNET_TIME_absolute_hton(), GNUNET_NSE_FloodMessage::header, GNUNET_NSE_FloodMessage::hop_count, matching_bits, GNUNET_NSE_FloodMessage::matching_bits, my_identity, my_proof, GNUNET_NSE_FloodMessage::origin, GNUNET_NSE_FloodMessage::proof_of_work, GNUNET_CRYPTO_EccSignaturePurpose::purpose, GNUNET_NSE_FloodMessage::purpose, GNUNET_MessageHeader::size, GNUNET_CRYPTO_EccSignaturePurpose::size, size_estimate_messages, GNUNET_NSE_FloodMessage::timestamp, and GNUNET_MessageHeader::type.

Referenced by find_proof(), identity_changed(), and update_flood_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ schedule_current_round()

static int schedule_current_round ( void *  cls,
const struct GNUNET_PeerIdentity key,
void *  value 
)
static

Schedule transmission for the given peer for the current round based on what we know about the desired delay.

Parameters
clsunused
keyhash of peer identity
valuethe struct NSEPeerEntry
Returns
GNUNET_OK (continue to iterate)

Definition at line 739 of file gnunet-service-nse.c.

742{
743 struct NSEPeerEntry *peer_entry = value;
744 struct GNUNET_TIME_Relative delay;
745
746 (void) cls;
747 (void) key;
748 if (NULL != peer_entry->transmit_task)
749 {
751 peer_entry->previous_round = GNUNET_NO;
752 }
753#if ENABLE_NSE_HISTOGRAM
754 if (peer_entry->received_messages > 1)
756 "# extra messages",
757 peer_entry->received_messages - 1,
758 GNUNET_NO);
759 peer_entry->transmitted_messages = 0;
760 peer_entry->last_transmitted_size = 0;
761 peer_entry->received_messages = 0;
762#endif
763 delay =
764 get_transmit_delay ((GNUNET_NO == peer_entry->previous_round) ? -1 : 0);
765 peer_entry->transmit_task =
767 return GNUNET_OK;
768}

References get_transmit_delay(), GNUNET_NO, GNUNET_OK, GNUNET_SCHEDULER_add_delayed(), GNUNET_SCHEDULER_cancel(), GNUNET_STATISTICS_update(), key, NSEPeerEntry::previous_round, stats, NSEPeerEntry::transmit_task, transmit_task_cb(), and value.

Referenced by update_flood_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_flood_message()

static void update_flood_message ( void *  cls)
static

Update our flood message to be sent (and our timestamps).

Parameters
clsunused

Definition at line 777 of file gnunet-service-nse.c.

778{
779 struct GNUNET_TIME_Relative offset;
780
781 (void) cls;
782 flood_task = NULL;
784 if (0 != offset.rel_value_us)
785 {
786 /* somehow run early, delay more */
787 flood_task =
789 return;
790 }
801 {
802 /* we received a message for this round way early, use it! */
805 htonl (1 + ntohl (next_message.hop_count));
806 }
807 else
809 next_message.matching_bits = htonl (0); /* reset for 'next' round */
810 hop_count_max = 0;
811 for (unsigned int i = 0; i < HISTORY_SIZE; i++)
813 GNUNET_MAX (ntohl (size_estimate_messages[i].hop_count), hop_count_max);
815 flood_task =
817}

References GNUNET_TIME_Absolute::abs_value_us, current_timestamp, estimate_count, estimate_index, flood_task, get_matching_bits(), GNUNET_CONTAINER_multipeermap_iterate(), GNUNET_MAX, gnunet_nse_interval, GNUNET_SCHEDULER_add_at(), GNUNET_SCHEDULER_add_delayed(), GNUNET_TIME_absolute_add(), GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_absolute_ntoh(), HISTORY_SIZE, GNUNET_NSE_FloodMessage::hop_count, hop_count_max, GNUNET_NSE_FloodMessage::matching_bits, my_identity, next_message, next_timestamp, peers, GNUNET_TIME_Relative::rel_value_us, schedule_current_round(), setup_flood_message(), size_estimate_messages, GNUNET_NSE_FloodMessage::timestamp, and update_flood_message().

Referenced by identity_changed(), and update_flood_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_proof_of_work()

static enum GNUNET_GenericReturnValue check_proof_of_work ( const struct GNUNET_CRYPTO_EddsaPublicKey pkey,
uint64_t  val 
)
static

Check whether the given public key and integer are a valid proof of work.

Parameters
pkeythe public key
valthe integer
Returns
GNUNET_YES if valid, GNUNET_NO if not

Definition at line 829 of file gnunet-service-nse.c.

831{
832 char buf[sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
833 + sizeof(val)] GNUNET_ALIGN;
834 struct GNUNET_HashCode result;
835
836 GNUNET_memcpy (buf, &val, sizeof(val));
837 GNUNET_memcpy (&buf[sizeof(val)],
838 pkey,
839 sizeof(struct GNUNET_CRYPTO_EddsaPublicKey));
841 buf,
842 sizeof(buf),
843 &result);
846 ? GNUNET_YES
847 : GNUNET_NO;
848}

References GNUNET_ALIGN, GNUNET_CRYPTO_hash_count_leading_zeros(), GNUNET_CRYPTO_pow_hash(), GNUNET_memcpy, GNUNET_NO, GNUNET_YES, nse_work_required, pkey, result, and salt.

Referenced by identity_changed(), and verify_message_crypto().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ write_proof()

static void write_proof ( void  )
static

Write our current proof to disk.

Definition at line 855 of file gnunet-service-nse.c.

856{
857 char *proof;
858
859 if (GNUNET_OK !=
861 "NSE",
862 "PROOFFILE",
863 &proof))
864 return;
866 if (GNUNET_OK !=
868 &my_proof,
869 sizeof(my_proof),
873 "write",
874 proof);
876}

References cfg, GNUNET_CONFIGURATION_get_value_filename(), GNUNET_DISK_directory_remove(), GNUNET_DISK_fn_write(), GNUNET_DISK_PERM_USER_READ, GNUNET_DISK_PERM_USER_WRITE, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log_strerror_file, GNUNET_OK, my_proof, and proof.

Referenced by find_proof(), and shutdown_task().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_proof()

static void find_proof ( void *  cls)
static

Find our proof of work.

Parameters
clsclosure (unused)

Definition at line 885 of file gnunet-service-nse.c.

886{
887#define ROUND_SIZE 10
888 uint64_t counter;
889 char buf[sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
890 + sizeof(uint64_t)] GNUNET_ALIGN;
891 struct GNUNET_HashCode result;
892 unsigned int i;
893
894 (void) cls;
895 proof_task = NULL;
896 GNUNET_memcpy (&buf[sizeof(uint64_t)],
898 sizeof(struct GNUNET_PeerIdentity));
899 i = 0;
900 counter = my_proof;
901 while ((counter != UINT64_MAX) && (i < ROUND_SIZE))
902 {
903 GNUNET_memcpy (buf, &counter, sizeof(uint64_t));
905 buf,
906 sizeof(buf),
907 &result);
908 if (nse_work_required <=
910 {
911 my_proof = counter;
913 "Proof of work found: %llu!\n",
914 (unsigned long long) GNUNET_ntohll (counter));
915 write_proof ();
917 return;
918 }
919 counter++;
920 i++;
921 }
922 if (my_proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE))
923 {
925 "Testing proofs currently at %llu\n",
926 (unsigned long long) counter);
927 /* remember progress every 100 rounds */
928 my_proof = counter;
929 write_proof ();
930 }
931 else
932 {
933 my_proof = counter;
934 }
935 proof_task =
938 &find_proof,
939 NULL);
940}

References current_timestamp, estimate_index, find_proof(), GNUNET_ALIGN, GNUNET_CRYPTO_hash_count_leading_zeros(), GNUNET_CRYPTO_pow_hash(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_ntohll(), GNUNET_SCHEDULER_add_delayed_with_priority(), GNUNET_SCHEDULER_PRIORITY_IDLE, my_identity, my_proof, nse_work_required, proof_find_delay, proof_task, result, ROUND_SIZE, salt, setup_flood_message(), and write_proof().

Referenced by find_proof(), and run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ verify_message_crypto()

static int verify_message_crypto ( const struct GNUNET_NSE_FloodMessage incoming_flood)
static

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.

Parameters
incoming_floodthe message to verify
Returns
GNUNET_YES if the message is verified GNUNET_NO if the key/signature don't verify

Definition at line 953 of file gnunet-service-nse.c.

954{
955 if (GNUNET_YES != check_proof_of_work (&incoming_flood->origin.public_key,
956 incoming_flood->proof_of_work))
957 {
959 "Proof of work invalid: %llu!\n",
960 (unsigned long long) GNUNET_ntohll (
961 incoming_flood->proof_of_work));
962 GNUNET_break_op (0);
963 return GNUNET_NO;
964 }
965 if ((nse_work_required > 0) &&
966 (GNUNET_OK !=
968 &incoming_flood->purpose,
969 &incoming_flood->signature,
970 &incoming_flood->origin.public_key)))
971 {
972 GNUNET_break_op (0);
973 return GNUNET_NO;
974 }
975 return GNUNET_YES;
976}

References check_proof_of_work(), GNUNET_break_op, GNUNET_CRYPTO_eddsa_verify_(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_NO, GNUNET_ntohll(), GNUNET_OK, GNUNET_SIGNATURE_PURPOSE_NSE_SEND, GNUNET_YES, nse_work_required, GNUNET_NSE_FloodMessage::origin, GNUNET_NSE_FloodMessage::proof_of_work, GNUNET_PeerIdentity::public_key, GNUNET_NSE_FloodMessage::purpose, and GNUNET_NSE_FloodMessage::signature.

Referenced by handle_p2p_estimate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_flood_times()

static int update_flood_times ( void *  cls,
const struct GNUNET_PeerIdentity key,
void *  value 
)
static

Update transmissions for the given peer for the current round based on updated proximity information.

Parameters
clspeer entry to exclude from updates
keyhash of peer identity
valuethe struct NSEPeerEntry * of a peer to transmit to
Returns
GNUNET_OK (continue to iterate)

Definition at line 989 of file gnunet-service-nse.c.

992{
993 struct NSEPeerEntry *exclude = cls;
994 struct NSEPeerEntry *peer_entry = value;
995 struct GNUNET_TIME_Relative delay;
996
997 (void) key;
998 if (peer_entry == exclude)
999 return GNUNET_OK; /* trigger of the update */
1000 if (GNUNET_NO == peer_entry->previous_round)
1001 {
1002 /* still stuck in previous round, no point to update, check that
1003 * we are active here though... */
1004 if (NULL == peer_entry->transmit_task)
1005 {
1006 GNUNET_break (0);
1007 }
1008 return GNUNET_OK;
1009 }
1010 if (NULL != peer_entry->transmit_task)
1011 {
1013 peer_entry->transmit_task = NULL;
1014 }
1015 delay = get_transmit_delay (0);
1016 peer_entry->transmit_task =
1017 GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
1018 return GNUNET_OK;
1019}

References get_transmit_delay(), GNUNET_break, GNUNET_NO, GNUNET_OK, GNUNET_SCHEDULER_add_delayed(), GNUNET_SCHEDULER_cancel(), key, NSEPeerEntry::previous_round, NSEPeerEntry::transmit_task, transmit_task_cb(), and value.

Referenced by handle_p2p_estimate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_p2p_estimate()

static void handle_p2p_estimate ( void *  cls,
const struct GNUNET_NSE_FloodMessage incoming_flood 
)
static

Core handler for size estimate flooding messages.

Parameters
clspeer this message is from
incoming_floodreceived message

Definition at line 1029 of file gnunet-service-nse.c.

1031{
1032 struct NSEPeerEntry *peer_entry = cls;
1033 struct GNUNET_TIME_Absolute ts;
1034 uint32_t matching_bits;
1035 unsigned int idx;
1036
1037#if ENABLE_NSE_HISTOGRAM
1038 {
1039 uint64_t t;
1040
1042 if (NULL != lh)
1043 GNUNET_TESTBED_LOGGER_write (lh, &t, sizeof(uint64_t));
1044 if (NULL != histogram)
1045 GNUNET_BIO_write_int64 (histogram, "histogram-time", t);
1046 }
1047#endif
1048 GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO);
1049 matching_bits = ntohl (incoming_flood->matching_bits);
1050#if DEBUG_NSE
1051 {
1052 char origin[5];
1053 char pred[5];
1054 struct GNUNET_PeerIdentity os;
1055
1057 sizeof(origin),
1058 "%s",
1059 GNUNET_i2s (&incoming_flood->origin));
1060 GNUNET_snprintf (pred, sizeof(pred), "%s", GNUNET_i2s (peer_entry->id));
1062 "Flood at %s from `%s' via `%s' at `%s' with bits %u\n",
1064 GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp)),
1065 origin,
1066 pred,
1068 (unsigned int) matching_bits);
1069 }
1070#endif
1071
1072#if ENABLE_NSE_HISTOGRAM
1073 peer_entry->received_messages++;
1074 if ((peer_entry->transmitted_messages > 0) &&
1075 (peer_entry->last_transmitted_size >= matching_bits) )
1076 GNUNET_STATISTICS_update (stats, "# cross messages", 1, GNUNET_NO);
1077#endif
1078
1079 ts = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp);
1080 if (ts.abs_value_us == current_timestamp.abs_value_us)
1081 idx = estimate_index;
1082 else if (ts.abs_value_us ==
1085 else if (ts.abs_value_us == next_timestamp.abs_value_us)
1086 {
1088 return; /* ignore, simply too early/late */
1089 if (GNUNET_YES != verify_message_crypto (incoming_flood))
1090 {
1092 "Peer %s is likely ill-configured!\n",
1093 GNUNET_i2s (peer_entry->id));
1094 GNUNET_break_op (0);
1095 return;
1096 }
1097 next_message = *incoming_flood;
1098 return;
1099 }
1100 else
1101 {
1103 "# flood messages discarded (clock skew too large)",
1104 1,
1105 GNUNET_NO);
1106 return;
1107 }
1108 if (0 == (GNUNET_memcmp (peer_entry->id, &my_identity)))
1109 {
1110 /* send to self, update our own estimate IF this also comes from us! */
1111 if (0 == GNUNET_memcmp (&incoming_flood->origin, &my_identity))
1113 return;
1114 }
1116 {
1117 /* Cancel transmission in the other direction, as this peer clearly has
1118 up-to-date information already. Even if we didn't talk to this peer in
1119 the previous round, we should no longer send it stale information as it
1120 told us about the current round! */
1121 peer_entry->previous_round = GNUNET_YES;
1122 if (idx != estimate_index)
1123 {
1124 /* do not transmit information for the previous round to this peer
1125 anymore (but allow current round) */
1126 return;
1127 }
1128 /* got up-to-date information for current round, cancel transmission to
1129 * this peer altogether */
1130 if (NULL != peer_entry->transmit_task)
1131 {
1133 peer_entry->transmit_task = NULL;
1134 }
1135 return;
1136 }
1138 {
1139 if ((idx < estimate_index) && (peer_entry->previous_round == GNUNET_YES))
1140 {
1141 peer_entry->previous_round = GNUNET_NO;
1142 }
1143 /* push back our result now, that peer is spreading bad information... */
1144 if (NULL != peer_entry->transmit_task)
1146 peer_entry->transmit_task =
1148 /* Not closer than our most recent message, no need to do work here */
1150 "# flood messages ignored (had closer already)",
1151 1,
1152 GNUNET_NO);
1153 return;
1154 }
1155 if (GNUNET_YES != verify_message_crypto (incoming_flood))
1156 {
1157 GNUNET_break_op (0);
1158 return;
1159 }
1162 /* Cancel transmission in the other direction, as this peer clearly has
1163 * up-to-date information already.
1164 */
1165 peer_entry->previous_round = GNUNET_YES;
1166 if (idx == estimate_index)
1167 {
1168 /* cancel any activity for current round */
1169 if (NULL != peer_entry->transmit_task)
1170 {
1172 peer_entry->transmit_task = NULL;
1173 }
1174 }
1175 size_estimate_messages[idx] = *incoming_flood;
1177 htonl (ntohl (incoming_flood->hop_count) + 1);
1179 GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1, hop_count_max);
1181 "# estimated network diameter",
1183 GNUNET_NO);
1184
1185 /* have a new, better size estimate, inform clients */
1187
1188 /* flood to rest */
1191 peer_entry);
1192}

References GNUNET_TIME_Absolute::abs_value_us, current_timestamp, estimate_index, GNUNET_assert, GNUNET_BIO_write_int64(), GNUNET_break_op, GNUNET_CONTAINER_multipeermap_iterate(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_i2s(), GNUNET_log, GNUNET_MAX, GNUNET_memcmp, GNUNET_NO, gnunet_nse_interval, GNUNET_SCHEDULER_add_now(), GNUNET_SCHEDULER_cancel(), GNUNET_snprintf(), GNUNET_STATISTICS_set(), GNUNET_STATISTICS_update(), GNUNET_STRINGS_absolute_time_to_string(), GNUNET_TIME_absolute_get(), GNUNET_TIME_absolute_ntoh(), GNUNET_YES, HISTORY_SIZE, GNUNET_NSE_FloodMessage::hop_count, hop_count_max, NSEPeerEntry::id, matching_bits, GNUNET_NSE_FloodMessage::matching_bits, my_identity, next_message, next_timestamp, origin, GNUNET_NSE_FloodMessage::origin, peers, NSEPeerEntry::previous_round, GNUNET_TIME_Relative::rel_value_us, size_estimate_messages, stats, t, GNUNET_NSE_FloodMessage::timestamp, NSEPeerEntry::transmit_task, transmit_task_cb(), update_flood_times(), update_network_size_estimate(), and verify_message_crypto().

Here is the call graph for this function:

◆ handle_core_connect()

static void * handle_core_connect ( void *  cls,
const struct GNUNET_PeerIdentity peer,
struct GNUNET_MQ_Handle mq,
enum GNUNET_CORE_PeerClass  class 
)
static

Method called whenever a peer connects.

Sets up the PeerEntry and schedules the initial size info transmission to this peer.

Parameters
clsclosure
peerpeer identity this notification is about
classclass of the connecting peer

Definition at line 1204 of file gnunet-service-nse.c.

1208{
1209 struct NSEPeerEntry *peer_entry;
1210
1211 (void) cls;
1213 "Peer `%s' connected to us\n",
1214 GNUNET_i2s (peer));
1215 /* set our default transmission options */
1217 /* create our peer entry for this peer */
1218 peer_entry = GNUNET_new (struct NSEPeerEntry);
1219 peer_entry->id = peer;
1220 peer_entry->mq = mq;
1223 peers,
1224 peer_entry->id,
1225 peer_entry,
1227 peer_entry->transmit_task =
1230 peer_entry);
1231 GNUNET_STATISTICS_update (stats, "# peers connected", 1, GNUNET_NO);
1232 return peer_entry;
1233}

References get_transmit_delay(), GNUNET_assert, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CONTAINER_multipeermap_put(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_MQ_set_options(), GNUNET_new, GNUNET_NO, GNUNET_OK, GNUNET_SCHEDULER_add_delayed(), GNUNET_STATISTICS_update(), NSEPeerEntry::id, mq, NSEPeerEntry::mq, NSE_PRIORITY, peers, stats, NSEPeerEntry::transmit_task, and transmit_task_cb().

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_core_disconnect()

static void handle_core_disconnect ( void *  cls,
const struct GNUNET_PeerIdentity peer,
void *  internal_cls 
)
static

Method called whenever a peer disconnects.

Deletes the PeerEntry and cancels any pending transmission requests to that peer.

Parameters
clsclosure
peerpeer identity this notification is about
internal_clsthe struct NSEPeerEntry for the peer

Definition at line 1245 of file gnunet-service-nse.c.

1248{
1249 struct NSEPeerEntry *pos = internal_cls;
1250
1251 (void) cls;
1253 "Peer `%s' disconnected from us\n",
1254 GNUNET_i2s (peer));
1257 if (NULL != pos->transmit_task)
1258 {
1260 pos->transmit_task = NULL;
1261 }
1262 GNUNET_free (pos);
1263 GNUNET_STATISTICS_update (stats, "# peers connected", -1, GNUNET_NO);
1264}

References GNUNET_assert, GNUNET_CONTAINER_multipeermap_remove(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_SCHEDULER_cancel(), GNUNET_STATISTICS_update(), GNUNET_YES, peers, stats, and NSEPeerEntry::transmit_task.

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ shutdown_task()

static void shutdown_task ( void *  cls)
static

Task run during shutdown.

Parameters
clsunused

Definition at line 1294 of file gnunet-service-nse.c.

1295{
1296 (void) cls;
1297 if (NULL != flood_task)
1298 {
1300 flood_task = NULL;
1301 }
1302 if (NULL != proof_task)
1303 {
1305 proof_task = NULL;
1306 write_proof (); /* remember progress */
1307 }
1308 if (NULL != nc)
1309 {
1311 nc = NULL;
1312 }
1313 if (NULL != core_api)
1314 {
1316 core_api = NULL;
1317 }
1318 if (NULL != stats)
1319 {
1321 stats = NULL;
1322 }
1323 if (NULL != peers)
1324 {
1326 peers = NULL;
1327 }
1328 if (NULL != my_private_key)
1329 {
1331 my_private_key = NULL;
1332 }
1333 if (NULL != pils)
1334 {
1336 pils = NULL;
1337 }
1338#if ENABLE_NSE_HISTOGRAM
1339 if (NULL != logger_test)
1340 {
1341 GNUNET_CLIENT_service_test_cancel (logger_test);
1342 logger_test = NULL;
1343 }
1344 if (NULL != lh)
1345 {
1346 GNUNET_TESTBED_LOGGER_flush (lh, &flush_comp_cb, NULL);
1347 }
1348 if (NULL != histogram)
1349 {
1350 GNUNET_BIO_write_close (histogram, NULL);
1351 histogram = NULL;
1352 }
1353#endif
1354}

References core_api, flood_task, GNUNET_BIO_write_close(), GNUNET_CONTAINER_multipeermap_destroy(), GNUNET_CORE_disconnect(), GNUNET_free, GNUNET_NO, GNUNET_notification_context_destroy(), GNUNET_PILS_disconnect(), GNUNET_SCHEDULER_cancel(), GNUNET_STATISTICS_destroy(), my_private_key, nc, peers, pils, proof_task, stats, and write_proof().

Here is the call graph for this function:

◆ identity_changed()

static void identity_changed ( const struct GNUNET_PeerIdentity identity)
static

Definition at line 1358 of file gnunet-service-nse.c.

1359{
1360 struct GNUNET_TIME_Absolute now;
1361 struct GNUNET_TIME_Absolute prev_time;
1362
1363 if (NULL == identity)
1364 {
1365 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection to core FAILED!\n");
1367 return;
1368 }
1370 now = GNUNET_TIME_absolute_get ();
1372 (now.abs_value_us / gnunet_nse_interval.rel_value_us)
1377 estimate_count = 0;
1379 {
1380 int idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1381 prev_time.abs_value_us =
1383 setup_flood_message (idx, prev_time);
1386 }
1387 if (NULL != flood_task)
1389 flood_task =
1391}

References GNUNET_TIME_Absolute::abs_value_us, check_proof_of_work(), current_timestamp, estimate_count, estimate_index, flood_task, GNUNET_assert, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_memcmp, gnunet_nse_interval, GNUNET_SCHEDULER_add_at(), GNUNET_SCHEDULER_cancel(), GNUNET_SCHEDULER_shutdown(), GNUNET_TIME_absolute_add(), GNUNET_TIME_absolute_get(), GNUNET_YES, HISTORY_SIZE, identity, my_identity, my_proof, next_timestamp, GNUNET_PeerIdentity::public_key, GNUNET_TIME_Relative::rel_value_us, setup_flood_message(), and update_flood_message().

Referenced by core_init(), and pils_id_change_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pils_id_change_cb()

static void pils_id_change_cb ( void *  cls,
const struct GNUNET_HELLO_Parser parser,
const struct GNUNET_HashCode addr_hash 
)
static

Definition at line 1395 of file gnunet-service-nse.c.

1398{
1401}

References GNUNET_HELLO_parser_get_id(), identity_changed(), and my_identity.

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ core_init()

static void core_init ( void *  cls,
const struct GNUNET_PeerIdentity identity 
)
static

Called on core init/fail.

Parameters
clsservice closure
identitythe public identity of this peer

Definition at line 1411 of file gnunet-service-nse.c.

1412{
1413 (void) cls;
1415}

References identity, and identity_changed().

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run()

static void run ( void *  cls,
const struct GNUNET_CONFIGURATION_Handle c,
struct GNUNET_SERVICE_Handle service 
)
static

Handle network size estimate clients.

Parameters
clsclosure
cconfiguration to use
servicethe initialized service

Definition at line 1457 of file gnunet-service-nse.c.

1460{
1461 struct GNUNET_MQ_MessageHandler core_handlers[] =
1462 { GNUNET_MQ_hd_fixed_size (p2p_estimate,
1465 NULL),
1467 char *proof;
1469 const struct GNUNET_CORE_ServiceInfo service_info =
1470 {
1472 .version = { 1, 0 },
1473 .version_max = { 1, 0 },
1474 .version_min = { 1, 0 },
1475 };
1476
1477 (void) cls;
1478 (void) service;
1479 cfg = c;
1481 "NSE",
1482 "INTERVAL",
1484 {
1487 return;
1488 }
1490 "NSE",
1491 "WORKDELAY",
1493 {
1496 return;
1497 }
1499 "NSE",
1500 "WORKBITS",
1502 {
1505 return;
1506 }
1507 if (nse_work_required >= sizeof(struct GNUNET_HashCode) * 8)
1508 {
1510 "NSE",
1511 "WORKBITS",
1512 _ ("Value is too large.\n"));
1514 return;
1515 }
1516
1517#if ENABLE_NSE_HISTOGRAM
1518 {
1519 char *histogram_dir;
1520 char *histogram_fn;
1521
1523 "NSE",
1524 "HISTOGRAM_DIR",
1525 &histogram_dir))
1526 {
1528 0 < GNUNET_asprintf (&histogram_fn, "%s/timestamps", histogram_dir));
1529 GNUNET_free (histogram_dir);
1530 histogram = GNUNET_BIO_write_open_file (histogram_fn);
1531 if (NULL == histogram)
1533 "Unable to open histogram file `%s'\n",
1534 histogram_fn);
1535 GNUNET_free (histogram_fn);
1536 }
1537 logger_test = GNUNET_CLIENT_service_test ("testbed-logger",
1538 cfg,
1540 &status_cb,
1541 NULL);
1542 }
1543#endif
1544
1547 GNUNET_assert (NULL != pk);
1550 if (GNUNET_OK !=
1551 GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
1552 {
1555 my_private_key = NULL;
1557 return;
1558 }
1560 (sizeof(my_proof) !=
1562 my_proof = 0;
1564 proof_task =
1566 &find_proof,
1567 NULL);
1568
1571 /* Connect to core service and register core handlers */
1572 core_api =
1573 GNUNET_CORE_connect (cfg, /* Main configuration */
1574 NULL, /* Closure passed to functions */
1575 &core_init, /* Call core_init once connected */
1576 &handle_core_connect, /* Handle connects */
1577 &handle_core_disconnect, /* Handle disconnects */
1578 core_handlers, /* Register these handlers */
1579 &service_info );
1580 if (NULL == core_api)
1581 {
1583 return;
1584 }
1586 if (NULL == pils)
1587 {
1588 GNUNET_break (0);
1590 return;
1591 }
1593}

References _, cfg, core_api, core_init(), find_proof(), GNUNET_asprintf(), GNUNET_assert, GNUNET_BIO_write_open_file(), GNUNET_break, GNUNET_CONFIGURATION_get_value_filename(), GNUNET_CONFIGURATION_get_value_number(), GNUNET_CONFIGURATION_get_value_time(), GNUNET_CONTAINER_multipeermap_create(), GNUNET_CORE_connect(), GNUNET_CORE_SERVICE_NSE, GNUNET_CRYPTO_eddsa_key_create_from_configuration(), GNUNET_CRYPTO_eddsa_key_get_public(), GNUNET_DISK_file_test(), GNUNET_DISK_fn_read(), GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, GNUNET_log_config_invalid(), GNUNET_log_config_missing(), GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD, GNUNET_MQ_handler_end, GNUNET_MQ_hd_fixed_size, GNUNET_notification_context_create(), gnunet_nse_interval, GNUNET_OK, GNUNET_PILS_connect(), GNUNET_SCHEDULER_add_shutdown(), GNUNET_SCHEDULER_add_with_priority(), GNUNET_SCHEDULER_PRIORITY_IDLE, GNUNET_SCHEDULER_shutdown(), GNUNET_STATISTICS_create(), GNUNET_TIME_UNIT_SECONDS, GNUNET_YES, handle_core_connect(), handle_core_disconnect(), my_identity, my_private_key, my_proof, nc, nse_work_required, peers, pils, pils_id_change_cb(), pk, proof, proof_find_delay, proof_task, GNUNET_PeerIdentity::public_key, GNUNET_CORE_ServiceInfo::service, service, shutdown_task, and stats.

Here is the call graph for this function:

◆ client_connect_cb()

static void * client_connect_cb ( void *  cls,
struct GNUNET_SERVICE_Client c,
struct GNUNET_MQ_Handle mq 
)
static

Callback called when a client connects to the service.

Parameters
clsclosure for the service
cthe new client that connected to the service
mqthe message queue used to send messages to the client
Returns
c

Definition at line 1605 of file gnunet-service-nse.c.

1608{
1609 (void) cls;
1610 (void) mq;
1611 return c;
1612}

References mq.

◆ client_disconnect_cb()

static void client_disconnect_cb ( void *  cls,
struct GNUNET_SERVICE_Client c,
void *  internal_cls 
)
static

Callback called when a client disconnected from the service.

Parameters
clsclosure for the service
cthe client that disconnected
internal_clsshould be equal to c

Definition at line 1623 of file gnunet-service-nse.c.

1626{
1627 (void) cls;
1628 GNUNET_assert (c == internal_cls);
1629}

References GNUNET_assert.

◆ GNUNET_SERVICE_MAIN()

GNUNET_SERVICE_MAIN ( GNUNET_OS_project_data_gnunet()  ,
"nse"  ,
GNUNET_SERVICE_OPTION_NONE  ,
run,
client_connect_cb,
client_disconnect_cb,
NULL  ,
GNUNET_MQ_hd_fixed_size(start, GNUNET_MESSAGE_TYPE_NSE_START, struct GNUNET_MessageHeader, NULL)  ,
GNUNET_MQ_handler_end()   
)

Define "main" method using service macro.

Variable Documentation

◆ nse_work_required

unsigned long long nse_work_required
static

Amount of work required (W-bit collisions) for NSE proofs, in collision-bits.

Definition at line 85 of file gnunet-service-nse.c.

Referenced by check_proof_of_work(), find_proof(), run(), and verify_message_crypto().

◆ gnunet_nse_interval

struct GNUNET_TIME_Relative gnunet_nse_interval
static

Interval for sending network size estimation flood requests.

Definition at line 90 of file gnunet-service-nse.c.

Referenced by get_matching_bits_delay(), handle_p2p_estimate(), identity_changed(), run(), and update_flood_message().

◆ proof_find_delay

struct GNUNET_TIME_Relative proof_find_delay
static

Interval between proof find runs.

Definition at line 95 of file gnunet-service-nse.c.

Referenced by find_proof(), and run().

◆ salt

struct GNUNET_CRYPTO_PowSalt salt = { "gnunet-nse-proof" }
static

Salt for PoW calculations.

Definition at line 119 of file gnunet-service-nse.c.

119{ "gnunet-nse-proof" };

Referenced by check_proof_of_work(), and find_proof().

◆ cfg

Handle to our current configuration.

Definition at line 235 of file gnunet-service-nse.c.

Referenced by run(), and write_proof().

◆ stats

◆ pils

struct GNUNET_PILS_Handle* pils
static

Handle to the PILS service.

Definition at line 245 of file gnunet-service-nse.c.

Referenced by run(), shutdown_task(), and transmit_task_cb().

◆ core_api

struct GNUNET_CORE_Handle* core_api
static

Handle to the core service.

Definition at line 250 of file gnunet-service-nse.c.

Referenced by run(), and shutdown_task().

◆ peers

◆ current_size_estimate

double current_size_estimate
static

The current network size estimate.

Number of bits matching on average thus far.

Definition at line 261 of file gnunet-service-nse.c.

Referenced by get_matching_bits_delay(), and setup_estimate_message().

◆ current_std_dev

double current_std_dev = NAN
static

The standard deviation of the last HISTORY_SIZE network size estimates.

Definition at line 267 of file gnunet-service-nse.c.

Referenced by setup_estimate_message().

◆ hop_count_max

uint32_t hop_count_max
static

Current hop counter estimate (estimate for network diameter).

Definition at line 272 of file gnunet-service-nse.c.

Referenced by get_delay_randomization(), handle_p2p_estimate(), and update_flood_message().

◆ next_message

struct GNUNET_NSE_FloodMessage next_message
static

Message for the next round, if we got any.

Definition at line 277 of file gnunet-service-nse.c.

Referenced by dequeue_message_from_room(), handle_p2p_estimate(), and update_flood_message().

◆ size_estimate_messages

struct GNUNET_NSE_FloodMessage size_estimate_messages[64]
static

◆ estimate_index

unsigned int estimate_index
static

◆ estimate_count

unsigned int estimate_count
static

Number of valid entries in the history.

Definition at line 292 of file gnunet-service-nse.c.

Referenced by identity_changed(), setup_estimate_message(), and update_flood_message().

◆ flood_task

struct GNUNET_SCHEDULER_Task* flood_task
static

Task scheduled to update our flood message for the next round.

Definition at line 297 of file gnunet-service-nse.c.

Referenced by identity_changed(), shutdown_task(), and update_flood_message().

◆ proof_task

struct GNUNET_SCHEDULER_Task* proof_task
static

Task scheduled to compute our proof.

Definition at line 302 of file gnunet-service-nse.c.

Referenced by find_proof(), run(), shutdown_task(), and transmit_task_cb().

◆ nc

struct GNUNET_NotificationContext* nc
static

Notification context, simplifies client broadcasts.

Definition at line 307 of file gnunet-service-nse.c.

Referenced by handle_start(), run(), shutdown_task(), and update_network_size_estimate().

◆ next_timestamp

struct GNUNET_TIME_Absolute next_timestamp
static

The next major time.

Definition at line 312 of file gnunet-service-nse.c.

Referenced by handle_p2p_estimate(), identity_changed(), and update_flood_message().

◆ current_timestamp

struct GNUNET_TIME_Absolute current_timestamp
static

The current major time.

Definition at line 317 of file gnunet-service-nse.c.

Referenced by find_proof(), get_transmit_delay(), handle_p2p_estimate(), identity_changed(), and update_flood_message().

◆ my_private_key

struct GNUNET_CRYPTO_EddsaPrivateKey* my_private_key
static

The private key of this peer.

Definition at line 322 of file gnunet-service-nse.c.

Referenced by run(), and shutdown_task().

◆ my_identity

struct GNUNET_PeerIdentity my_identity
static

The peer identity of this peer.

Definition at line 327 of file gnunet-service-nse.c.

Referenced by find_proof(), handle_p2p_estimate(), identity_changed(), pils_id_change_cb(), run(), setup_flood_message(), and update_flood_message().

◆ my_proof

uint64_t my_proof
static

Proof of work for this peer.

Definition at line 332 of file gnunet-service-nse.c.

Referenced by find_proof(), identity_changed(), run(), setup_flood_message(), and write_proof().