Merge branch 'master' into cadet_option
[oweals/gnunet.git] / src / nse / gnunet-service-nse.c
1 /*
2   This file is part of GNUnet.
3   Copyright (C) 2009, 2010, 2011, 2012, 2013, 2016 GNUnet e.V.
4
5   GNUnet is free software: you can redistribute it and/or modify it
6   under the terms of the GNU Affero General Public License as published
7   by the Free Software Foundation, either version 3 of the License,
8   or (at your option) any later version.
9
10   GNUnet is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Affero General Public License for more details.
14
15   You should have received a copy of the GNU Affero General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file nse/gnunet-service-nse.c
23  * @brief network size estimation service
24  * @author Nathan Evans
25  * @author Christian Grothoff
26  *
27  * The purpose of this service is to estimate the size of the network.
28  * Given a specified interval, each peer hashes the most recent
29  * timestamp which is evenly divisible by that interval.  This hash is
30  * compared in distance to the peer identity to choose an offset.  The
31  * closer the peer identity to the hashed timestamp, the earlier the
32  * peer sends out a "nearest peer" message.  The closest peer's
33  * message should thus be received before any others, which stops
34  * those peer from sending their messages at a later duration.  So
35  * every peer should receive the same nearest peer message, and from
36  * this can calculate the expected number of peers in the network.
37  */
38 #include "platform.h"
39 #include <math.h>
40 #include "gnunet_util_lib.h"
41 #include "gnunet_constants.h"
42 #include "gnunet_protocols.h"
43 #include "gnunet_signatures.h"
44 #include "gnunet_statistics_service.h"
45 #include "gnunet_core_service.h"
46 #include "gnunet_nse_service.h"
47 #if ENABLE_NSE_HISTOGRAM
48 #include "gnunet_testbed_logger_service.h"
49 #endif
50 #include "nse.h"
51 #include <gcrypt.h>
52
53
54 /**
55  * Should messages be delayed randomly?  This option should be set to
56  * #GNUNET_NO only for experiments, not in production.
57  */
58 #define USE_RANDOM_DELAYS GNUNET_YES
59
60 /**
61  * Generate extensive debug-level log messages?
62  */
63 #define DEBUG_NSE GNUNET_NO
64
65 /**
66  * Over how many values do we calculate the weighted average?
67  */
68 #define HISTORY_SIZE 64
69
70 /**
71  * Message priority to use.  No real rush, reliability not
72  * required. Corking OK.
73  */
74 #define NSE_PRIORITY                                       \
75   (GNUNET_MQ_PRIO_BACKGROUND | GNUNET_MQ_PREF_UNRELIABLE | \
76    GNUNET_MQ_PREF_CORK_ALLOWED)
77
78 #if FREEBSD
79 #define log2(a) (log (a) / log (2))
80 #endif
81
82 /**
83  * Amount of work required (W-bit collisions) for NSE proofs, in collision-bits.
84  */
85 static unsigned long long nse_work_required;
86
87 /**
88  * Interval for sending network size estimation flood requests.
89  */
90 static struct GNUNET_TIME_Relative gnunet_nse_interval;
91
92 /**
93  * Interval between proof find runs.
94  */
95 static struct GNUNET_TIME_Relative proof_find_delay;
96
97 #if ENABLE_NSE_HISTOGRAM
98
99 /**
100  * Handle to test if testbed logger service is running or not
101  */
102 struct GNUNET_CLIENT_TestHandle *logger_test;
103
104 /**
105  * Handle for writing when we received messages to disk.
106  */
107 static struct GNUNET_TESTBED_LOGGER_Handle *lh;
108
109 /**
110  * Handle for writing message received timestamp information to disk.
111  */
112 static struct GNUNET_BIO_WriteHandle *histogram;
113
114 #endif
115
116
117 /**
118  * Per-peer information.
119  */
120 struct NSEPeerEntry
121 {
122
123   /**
124    * Core handle for sending messages to this peer.
125    */
126   struct GNUNET_MQ_Handle *mq;
127
128   /**
129    * What is the identity of the peer?
130    */
131   const struct GNUNET_PeerIdentity *id;
132
133   /**
134    * Task scheduled to send message to this peer.
135    */
136   struct GNUNET_SCHEDULER_Task *transmit_task;
137
138   /**
139    * Did we receive or send a message about the previous round
140    * to this peer yet?   #GNUNET_YES if the previous round has
141    * been taken care of.
142    */
143   int previous_round;
144
145 #if ENABLE_NSE_HISTOGRAM
146
147   /**
148    * Amount of messages received from this peer on this round.
149    */
150   unsigned int received_messages;
151
152   /**
153    * Amount of messages transmitted to this peer on this round.
154    */
155   unsigned int transmitted_messages;
156
157   /**
158    * Which size did we tell the peer the network is?
159    */
160   unsigned int last_transmitted_size;
161
162 #endif
163 };
164
165
166 GNUNET_NETWORK_STRUCT_BEGIN
167
168 /**
169  * Network size estimate reply; sent when "this"
170  * peer's timer has run out before receiving a
171  * valid reply from another peer.
172  */
173 struct GNUNET_NSE_FloodMessage
174 {
175   /**
176    * Type: #GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD
177    */
178   struct GNUNET_MessageHeader header;
179
180   /**
181    * Number of hops this message has taken so far.
182    */
183   uint32_t hop_count GNUNET_PACKED;
184
185   /**
186    * Purpose.
187    */
188   struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
189
190   /**
191    * The current timestamp value (which all
192    * peers should agree on).
193    */
194   struct GNUNET_TIME_AbsoluteNBO timestamp;
195
196   /**
197    * Number of matching bits between the hash
198    * of timestamp and the initiator's public
199    * key.
200    */
201   uint32_t matching_bits GNUNET_PACKED;
202
203   /**
204    * Public key of the originator.
205    */
206   struct GNUNET_PeerIdentity origin;
207
208   /**
209    * Proof of work, causing leading zeros when hashed with pkey.
210    */
211   uint64_t proof_of_work GNUNET_PACKED;
212
213   /**
214    * Signature (over range specified in purpose).
215    */
216   struct GNUNET_CRYPTO_EddsaSignature signature;
217 };
218 GNUNET_NETWORK_STRUCT_END
219
220 /**
221  * Handle to our current configuration.
222  */
223 static const struct GNUNET_CONFIGURATION_Handle *cfg;
224
225 /**
226  * Handle to the statistics service.
227  */
228 static struct GNUNET_STATISTICS_Handle *stats;
229
230 /**
231  * Handle to the core service.
232  */
233 static struct GNUNET_CORE_Handle *core_api;
234
235 /**
236  * Map of all connected peers.
237  */
238 static struct GNUNET_CONTAINER_MultiPeerMap *peers;
239
240 /**
241  * The current network size estimate.  Number of bits matching on
242  * average thus far.
243  */
244 static double current_size_estimate;
245
246 /**
247  * The standard deviation of the last #HISTORY_SIZE network
248  * size estimates.
249  */
250 static double current_std_dev = NAN;
251
252 /**
253  * Current hop counter estimate (estimate for network diameter).
254  */
255 static uint32_t hop_count_max;
256
257 /**
258  * Message for the next round, if we got any.
259  */
260 static struct GNUNET_NSE_FloodMessage next_message;
261
262 /**
263  * Array of recent size estimate messages.
264  */
265 static struct GNUNET_NSE_FloodMessage size_estimate_messages[HISTORY_SIZE];
266
267 /**
268  * Index of most recent estimate.
269  */
270 static unsigned int estimate_index;
271
272 /**
273  * Number of valid entries in the history.
274  */
275 static unsigned int estimate_count;
276
277 /**
278  * Task scheduled to update our flood message for the next round.
279  */
280 static struct GNUNET_SCHEDULER_Task *flood_task;
281
282 /**
283  * Task scheduled to compute our proof.
284  */
285 static struct GNUNET_SCHEDULER_Task *proof_task;
286
287 /**
288  * Notification context, simplifies client broadcasts.
289  */
290 static struct GNUNET_NotificationContext *nc;
291
292 /**
293  * The next major time.
294  */
295 static struct GNUNET_TIME_Absolute next_timestamp;
296
297 /**
298  * The current major time.
299  */
300 static struct GNUNET_TIME_Absolute current_timestamp;
301
302 /**
303  * The private key of this peer.
304  */
305 static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
306
307 /**
308  * The peer identity of this peer.
309  */
310 static struct GNUNET_PeerIdentity my_identity;
311
312 /**
313  * Proof of work for this peer.
314  */
315 static uint64_t my_proof;
316
317
318 /**
319  * Initialize a message to clients with the current network
320  * size estimate.
321  *
322  * @param em message to fill in
323  */
324 static void
325 setup_estimate_message (struct GNUNET_NSE_ClientMessage *em)
326 {
327   double mean;
328   double sum;
329   double std_dev;
330   double variance;
331   double val;
332   double nsize;
333
334 #define WEST 1
335   /* Weighted incremental algorithm for stddev according to West (1979) */
336 #if WEST
337   double sumweight;
338   double weight;
339   double q;
340   double r;
341   double temp;
342
343   mean = 0.0;
344   sum = 0.0;
345   sumweight = 0.0;
346   variance = 0.0;
347   for (unsigned int i = 0; i < estimate_count; i++)
348   {
349     unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE;
350
351     val = htonl (size_estimate_messages[j].matching_bits);
352     weight = estimate_count + 1 - i;
353
354     temp = weight + sumweight;
355     q = val - mean;
356     r = q * weight / temp;
357     mean += r;
358     sum += sumweight * q * r;
359     sumweight = temp;
360   }
361   if (estimate_count > 0)
362     variance = (sum / sumweight) * estimate_count / (estimate_count - 1.0);
363 #else
364   /* trivial version for debugging */
365   double vsq;
366
367   /* non-weighted trivial version */
368   sum = 0.0;
369   vsq = 0.0;
370   variance = 0.0;
371   mean = 0.0;
372
373   for (unsigned int i = 0; i < estimate_count; i++)
374   {
375     unsigned int j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE;
376
377     val = htonl (size_estimate_messages[j].matching_bits);
378     sum += val;
379     vsq += val * val;
380   }
381   if (0 != estimate_count)
382   {
383     mean = sum / estimate_count;
384     variance = (vsq - mean * sum) /
385                (estimate_count - 1.0); // terrible for numerical stability...
386   }
387 #endif
388   if (variance >= 0)
389     std_dev = sqrt (variance);
390   else
391     std_dev = variance; /* must be infinity due to estimate_count == 0 */
392   current_std_dev = std_dev;
393   current_size_estimate = mean;
394
395   em->header.size = htons (sizeof (struct GNUNET_NSE_ClientMessage));
396   em->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE);
397   em->reserved = htonl (0);
398   em->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
399   {
400     double se = mean - 0.332747;
401     unsigned int j = GNUNET_CONTAINER_multipeermap_size (peers);
402     if (0 == j)
403       j = 1; /* Avoid log2(0); can only happen if CORE didn't report
404                 connection to self yet */
405     nsize = log2 (j);
406     em->size_estimate = GNUNET_hton_double (GNUNET_MAX (se, nsize));
407     em->std_deviation = GNUNET_hton_double (std_dev);
408     GNUNET_STATISTICS_set (stats,
409                            "# nodes in the network (estimate)",
410                            (uint64_t) pow (2, GNUNET_MAX (se, nsize)),
411                            GNUNET_NO);
412   }
413 }
414
415
416 /**
417  * Handler for START message from client, triggers an
418  * immediate current network estimate notification.
419  * Also, we remember the client for updates upon future
420  * estimate measurements.
421  *
422  * @param cls client who sent the message
423  * @param message the message received
424  */
425 static void
426 handle_start (void *cls, const struct GNUNET_MessageHeader *message)
427 {
428   struct GNUNET_SERVICE_Client *client = cls;
429   struct GNUNET_MQ_Handle *mq;
430   struct GNUNET_NSE_ClientMessage em;
431   struct GNUNET_MQ_Envelope *env;
432
433   (void) message;
434   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received START message from client\n");
435   mq = GNUNET_SERVICE_client_get_mq (client);
436   GNUNET_notification_context_add (nc, mq);
437   setup_estimate_message (&em);
438   env = GNUNET_MQ_msg_copy (&em.header);
439   GNUNET_MQ_send (mq, env);
440   GNUNET_SERVICE_client_continue (client);
441 }
442
443
444 /**
445  * How long should we delay a message to go the given number of
446  * matching bits?
447  *
448  * @param matching_bits number of matching bits to consider
449  */
450 static double
451 get_matching_bits_delay (uint32_t matching_bits)
452 {
453   /* Calculated as: S + f/2 - (f / pi) * (atan(x - p')) */
454   // S is next_timestamp (ignored in return value)
455   // f is frequency (gnunet_nse_interval)
456   // x is matching_bits
457   // p' is current_size_estimate
458   return ((double) gnunet_nse_interval.rel_value_us / (double) 2.0) -
459          ((gnunet_nse_interval.rel_value_us / M_PI) *
460           atan (matching_bits - current_size_estimate));
461 }
462
463
464 /**
465  * What delay randomization should we apply for a given number of matching bits?
466  *
467  * @param matching_bits number of matching bits
468  * @return random delay to apply
469  */
470 static struct GNUNET_TIME_Relative
471 get_delay_randomization (uint32_t matching_bits)
472 {
473 #if USE_RANDOM_DELAYS
474   struct GNUNET_TIME_Relative ret;
475   uint32_t i;
476   double d;
477
478   d = get_matching_bits_delay (matching_bits);
479   i = (uint32_t) (d / (double) (hop_count_max + 1));
480   ret.rel_value_us = i;
481   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
482               "Randomizing flood using latencies up to %s\n",
483               GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
484   ret.rel_value_us =
485     GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, i + 1);
486   return ret;
487 #else
488   return GNUNET_TIME_UNIT_ZERO;
489 #endif
490 }
491
492
493 /**
494  * Calculate the 'proof-of-work' hash (an expensive hash).
495  *
496  * @param buf data to hash
497  * @param buf_len number of bytes in @a buf
498  * @param result where to write the resulting hash
499  */
500 static void
501 pow_hash (const void *buf, size_t buf_len, struct GNUNET_HashCode *result)
502 {
503   GNUNET_break (
504     0 == gcry_kdf_derive (buf,
505                           buf_len,
506                           GCRY_KDF_SCRYPT,
507                           1 /* subalgo */,
508                           "gnunet-proof-of-work",
509                           strlen ("gnunet-proof-of-work"),
510                           2 /* iterations; keep cost of individual op small */,
511                           sizeof (struct GNUNET_HashCode),
512                           result));
513 }
514
515
516 /**
517  * Get the number of matching bits that the given timestamp has to the given peer ID.
518  *
519  * @param timestamp time to generate key
520  * @param id peer identity to compare with
521  * @return number of matching bits
522  */
523 static uint32_t
524 get_matching_bits (struct GNUNET_TIME_Absolute timestamp,
525                    const struct GNUNET_PeerIdentity *id)
526 {
527   struct GNUNET_HashCode timestamp_hash;
528   struct GNUNET_HashCode pid_hash;
529
530   GNUNET_CRYPTO_hash (&timestamp.abs_value_us,
531                       sizeof (timestamp.abs_value_us),
532                       &timestamp_hash);
533   GNUNET_CRYPTO_hash (id, sizeof (struct GNUNET_PeerIdentity), &pid_hash);
534   return GNUNET_CRYPTO_hash_matching_bits (&timestamp_hash, &pid_hash);
535 }
536
537
538 /**
539  * Get the transmission delay that should be applied for a
540  * particular round.
541  *
542  * @param round_offset -1 for the previous round (random delay between 0 and 50ms)
543  *                      0 for the current round (based on our proximity to time key)
544  * @return delay that should be applied
545  */
546 static struct GNUNET_TIME_Relative
547 get_transmit_delay (int round_offset)
548 {
549   struct GNUNET_TIME_Relative ret;
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 =
560       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, 50);
561 #else
562     ret = GNUNET_TIME_UNIT_ZERO;
563 #endif
564     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
565                 "Transmitting previous round behind schedule in %s\n",
566                 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
567     return ret;
568   case 0:
569     /* current round is based on best-known matching_bits */
570     matching_bits =
571       ntohl (size_estimate_messages[estimate_index].matching_bits);
572     dist_delay = get_matching_bits_delay (matching_bits);
573     dist_delay += get_delay_randomization (matching_bits).rel_value_us;
574     ret.rel_value_us = (uint64_t) dist_delay;
575     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576                 "For round %s, delay for %u matching bits is %s\n",
577                 GNUNET_STRINGS_absolute_time_to_string (current_timestamp),
578                 (unsigned int) matching_bits,
579                 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
580     /* now consider round start time and add delay to it */
581     tgt = GNUNET_TIME_absolute_add (current_timestamp, ret);
582     return GNUNET_TIME_absolute_get_remaining (tgt);
583   }
584   GNUNET_break (0);
585   return GNUNET_TIME_UNIT_FOREVER_REL;
586 }
587
588
589 /**
590  * Task that triggers a NSE P2P transmission.
591  *
592  * @param cls the `struct NSEPeerEntry *`
593  */
594 static void
595 transmit_task_cb (void *cls)
596 {
597   struct NSEPeerEntry *peer_entry = cls;
598   unsigned int idx;
599   struct GNUNET_MQ_Envelope *env;
600
601   peer_entry->transmit_task = NULL;
602   idx = estimate_index;
603   if (GNUNET_NO == peer_entry->previous_round)
604   {
605     idx = (idx + HISTORY_SIZE - 1) % HISTORY_SIZE;
606     peer_entry->previous_round = GNUNET_YES;
607     peer_entry->transmit_task =
608       GNUNET_SCHEDULER_add_delayed (get_transmit_delay (0),
609                                     &transmit_task_cb,
610                                     peer_entry);
611   }
612   if ((0 == ntohl (size_estimate_messages[idx].hop_count)) &&
613       (NULL != proof_task))
614   {
615     GNUNET_STATISTICS_update (stats,
616                               "# flood messages not generated (no proof yet)",
617                               1,
618                               GNUNET_NO);
619     return;
620   }
621   if (0 == ntohs (size_estimate_messages[idx].header.size))
622   {
623     GNUNET_STATISTICS_update (stats,
624                               "# flood messages not generated (lack of history)",
625                               1,
626                               GNUNET_NO);
627     return;
628   }
629   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
630               "In round %s, sending to `%s' estimate with %u bits\n",
631               GNUNET_STRINGS_absolute_time_to_string (
632                 GNUNET_TIME_absolute_ntoh (
633                   size_estimate_messages[idx].timestamp)),
634               GNUNET_i2s (peer_entry->id),
635               (unsigned int) ntohl (size_estimate_messages[idx].matching_bits));
636   if (0 == ntohl (size_estimate_messages[idx].hop_count))
637     GNUNET_STATISTICS_update (stats, "# flood messages started", 1, GNUNET_NO);
638   GNUNET_STATISTICS_update (stats,
639                             "# flood messages transmitted",
640                             1,
641                             GNUNET_NO);
642 #if ENABLE_NSE_HISTOGRAM
643   peer_entry->transmitted_messages++;
644   peer_entry->last_transmitted_size =
645     ntohl (size_estimate_messages[idx].matching_bits);
646 #endif
647   env = GNUNET_MQ_msg_copy (&size_estimate_messages[idx].header);
648   GNUNET_MQ_send (peer_entry->mq, env);
649 }
650
651
652 /**
653  * We've sent on our flood message or one that we received which was
654  * validated and closer than ours.  Update the global list of recent
655  * messages and the average.  Also re-broadcast the message to any
656  * clients.
657  */
658 static void
659 update_network_size_estimate ()
660 {
661   struct GNUNET_NSE_ClientMessage em;
662
663   setup_estimate_message (&em);
664   GNUNET_notification_context_broadcast (nc, &em.header, GNUNET_YES);
665 }
666
667
668 /**
669  * Setup a flood message in our history array at the given
670  * slot offset for the given timestamp.
671  *
672  * @param slot index to use
673  * @param ts timestamp to use
674  */
675 static void
676 setup_flood_message (unsigned int slot, struct GNUNET_TIME_Absolute ts)
677 {
678   struct GNUNET_NSE_FloodMessage *fm;
679   uint32_t matching_bits;
680
681   matching_bits = get_matching_bits (ts, &my_identity);
682   fm = &size_estimate_messages[slot];
683   fm->header.size = htons (sizeof (struct GNUNET_NSE_FloodMessage));
684   fm->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD);
685   fm->hop_count = htonl (0);
686   fm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND);
687   fm->purpose.size =
688     htonl (sizeof (struct GNUNET_NSE_FloodMessage) -
689            sizeof (struct GNUNET_MessageHeader) - sizeof (uint32_t) -
690            sizeof (struct GNUNET_CRYPTO_EddsaSignature));
691   fm->matching_bits = htonl (matching_bits);
692   fm->timestamp = GNUNET_TIME_absolute_hton (ts);
693   fm->origin = my_identity;
694   fm->proof_of_work = my_proof;
695   if (nse_work_required > 0)
696     GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (my_private_key,
697                                                           &fm->purpose,
698                                                           &fm->signature));
699   else
700     memset (&fm->signature, 0, sizeof (fm->signature));
701 }
702
703
704 /**
705  * Schedule transmission for the given peer for the current round based
706  * on what we know about the desired delay.
707  *
708  * @param cls unused
709  * @param key hash of peer identity
710  * @param value the `struct NSEPeerEntry`
711  * @return #GNUNET_OK (continue to iterate)
712  */
713 static int
714 schedule_current_round (void *cls,
715                         const struct GNUNET_PeerIdentity *key,
716                         void *value)
717 {
718   struct NSEPeerEntry *peer_entry = value;
719   struct GNUNET_TIME_Relative delay;
720
721   (void) cls;
722   (void) key;
723   if (NULL != peer_entry->transmit_task)
724   {
725     GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
726     peer_entry->previous_round = GNUNET_NO;
727   }
728 #if ENABLE_NSE_HISTOGRAM
729   if (peer_entry->received_messages > 1)
730     GNUNET_STATISTICS_update (stats,
731                               "# extra messages",
732                               peer_entry->received_messages - 1,
733                               GNUNET_NO);
734   peer_entry->transmitted_messages = 0;
735   peer_entry->last_transmitted_size = 0;
736   peer_entry->received_messages = 0;
737 #endif
738   delay =
739     get_transmit_delay ((GNUNET_NO == peer_entry->previous_round) ? -1 : 0);
740   peer_entry->transmit_task =
741     GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
742   return GNUNET_OK;
743 }
744
745
746 /**
747  * Update our flood message to be sent (and our timestamps).
748  *
749  * @param cls unused
750  */
751 static void
752 update_flood_message (void *cls)
753 {
754   struct GNUNET_TIME_Relative offset;
755
756   (void) cls;
757   flood_task = NULL;
758   offset = GNUNET_TIME_absolute_get_remaining (next_timestamp);
759   if (0 != offset.rel_value_us)
760   {
761     /* somehow run early, delay more */
762     flood_task =
763       GNUNET_SCHEDULER_add_delayed (offset, &update_flood_message, NULL);
764     return;
765   }
766   estimate_index = (estimate_index + 1) % HISTORY_SIZE;
767   if (estimate_count < HISTORY_SIZE)
768     estimate_count++;
769   current_timestamp = next_timestamp;
770   next_timestamp =
771     GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
772   if ((current_timestamp.abs_value_us ==
773        GNUNET_TIME_absolute_ntoh (next_message.timestamp).abs_value_us) &&
774       (get_matching_bits (current_timestamp, &my_identity) <
775        ntohl (next_message.matching_bits)))
776   {
777     /* we received a message for this round way early, use it! */
778     size_estimate_messages[estimate_index] = next_message;
779     size_estimate_messages[estimate_index].hop_count =
780       htonl (1 + ntohl (next_message.hop_count));
781   }
782   else
783     setup_flood_message (estimate_index, current_timestamp);
784   next_message.matching_bits = htonl (0); /* reset for 'next' round */
785   hop_count_max = 0;
786   for (unsigned int i = 0; i < HISTORY_SIZE; i++)
787     hop_count_max =
788       GNUNET_MAX (ntohl (size_estimate_messages[i].hop_count), hop_count_max);
789   GNUNET_CONTAINER_multipeermap_iterate (peers, &schedule_current_round, NULL);
790   flood_task =
791     GNUNET_SCHEDULER_add_at (next_timestamp, &update_flood_message, NULL);
792 }
793
794
795 /**
796  * Count the leading zeroes in hash.
797  *
798  * @param hash to count leading zeros in
799  * @return the number of leading zero bits.
800  */
801 static unsigned int
802 count_leading_zeroes (const struct GNUNET_HashCode *hash)
803 {
804   unsigned int hash_count;
805
806   hash_count = 0;
807   while (0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count))
808     hash_count++;
809   return hash_count;
810 }
811
812
813 /**
814  * Check whether the given public key and integer are a valid proof of
815  * work.
816  *
817  * @param pkey the public key
818  * @param val the integer
819  * @return #GNUNET_YES if valid, #GNUNET_NO if not
820  */
821 static int
822 check_proof_of_work (const struct GNUNET_CRYPTO_EddsaPublicKey *pkey,
823                      uint64_t val)
824 {
825   char buf[sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
826            sizeof (val)] GNUNET_ALIGN;
827   struct GNUNET_HashCode result;
828
829   GNUNET_memcpy (buf, &val, sizeof (val));
830   GNUNET_memcpy (&buf[sizeof (val)],
831                  pkey,
832                  sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
833   pow_hash (buf, sizeof (buf), &result);
834   return (count_leading_zeroes (&result) >= nse_work_required) ? GNUNET_YES
835                                                                : GNUNET_NO;
836 }
837
838
839 /**
840  * Write our current proof to disk.
841  */
842 static void
843 write_proof ()
844 {
845   char *proof;
846
847   if (GNUNET_OK !=
848       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
849     return;
850   if (sizeof (my_proof) != GNUNET_DISK_fn_write (proof,
851                                                  &my_proof,
852                                                  sizeof (my_proof),
853                                                  GNUNET_DISK_PERM_USER_READ |
854                                                    GNUNET_DISK_PERM_USER_WRITE))
855     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", proof);
856   GNUNET_free (proof);
857 }
858
859
860 /**
861  * Find our proof of work.
862  *
863  * @param cls closure (unused)
864  */
865 static void
866 find_proof (void *cls)
867 {
868 #define ROUND_SIZE 10
869   uint64_t counter;
870   char buf[sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
871            sizeof (uint64_t)] GNUNET_ALIGN;
872   struct GNUNET_HashCode result;
873   unsigned int i;
874
875   (void) cls;
876   proof_task = NULL;
877   GNUNET_memcpy (&buf[sizeof (uint64_t)],
878                  &my_identity,
879                  sizeof (struct GNUNET_PeerIdentity));
880   i = 0;
881   counter = my_proof;
882   while ((counter != UINT64_MAX) && (i < ROUND_SIZE))
883   {
884     GNUNET_memcpy (buf, &counter, sizeof (uint64_t));
885     pow_hash (buf, sizeof (buf), &result);
886     if (nse_work_required <= count_leading_zeroes (&result))
887     {
888       my_proof = counter;
889       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
890                   "Proof of work found: %llu!\n",
891                   (unsigned long long) GNUNET_ntohll (counter));
892       write_proof ();
893       setup_flood_message (estimate_index, current_timestamp);
894       return;
895     }
896     counter++;
897     i++;
898   }
899   if (my_proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE))
900   {
901     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
902                 "Testing proofs currently at %llu\n",
903                 (unsigned long long) counter);
904     /* remember progress every 100 rounds */
905     my_proof = counter;
906     write_proof ();
907   }
908   else
909   {
910     my_proof = counter;
911   }
912   proof_task =
913     GNUNET_SCHEDULER_add_delayed_with_priority (proof_find_delay,
914                                                 GNUNET_SCHEDULER_PRIORITY_IDLE,
915                                                 &find_proof,
916                                                 NULL);
917 }
918
919
920 /**
921  * An incoming flood message has been received which claims
922  * to have more bits matching than any we know in this time
923  * period.  Verify the signature and/or proof of work.
924  *
925  * @param incoming_flood the message to verify
926  * @return #GNUNET_YES if the message is verified
927  *         #GNUNET_NO if the key/signature don't verify
928  */
929 static int
930 verify_message_crypto (const struct GNUNET_NSE_FloodMessage *incoming_flood)
931 {
932   if (GNUNET_YES != check_proof_of_work (&incoming_flood->origin.public_key,
933                                          incoming_flood->proof_of_work))
934   {
935     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
936                 "Proof of work invalid: %llu!\n",
937                 (unsigned long long) GNUNET_ntohll (
938                   incoming_flood->proof_of_work));
939     GNUNET_break_op (0);
940     return GNUNET_NO;
941   }
942   if ((nse_work_required > 0) &&
943       (GNUNET_OK !=
944        GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND,
945                                    &incoming_flood->purpose,
946                                    &incoming_flood->signature,
947                                    &incoming_flood->origin.public_key)))
948   {
949     GNUNET_break_op (0);
950     return GNUNET_NO;
951   }
952   return GNUNET_YES;
953 }
954
955
956 /**
957  * Update transmissions for the given peer for the current round based
958  * on updated proximity information.
959  *
960  * @param cls peer entry to exclude from updates
961  * @param key hash of peer identity
962  * @param value the `struct NSEPeerEntry *` of a peer to transmit to
963  * @return #GNUNET_OK (continue to iterate)
964  */
965 static int
966 update_flood_times (void *cls,
967                     const struct GNUNET_PeerIdentity *key,
968                     void *value)
969 {
970   struct NSEPeerEntry *exclude = cls;
971   struct NSEPeerEntry *peer_entry = value;
972   struct GNUNET_TIME_Relative delay;
973
974   (void) key;
975   if (peer_entry == exclude)
976     return GNUNET_OK; /* trigger of the update */
977   if (GNUNET_NO == peer_entry->previous_round)
978   {
979     /* still stuck in previous round, no point to update, check that
980      * we are active here though... */
981     if (NULL == peer_entry->transmit_task)
982     {
983       GNUNET_break (0);
984     }
985     return GNUNET_OK;
986   }
987   if (NULL != peer_entry->transmit_task)
988   {
989     GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
990     peer_entry->transmit_task = NULL;
991   }
992   delay = get_transmit_delay (0);
993   peer_entry->transmit_task =
994     GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
995   return GNUNET_OK;
996 }
997
998
999 /**
1000  * Core handler for size estimate flooding messages.
1001  *
1002  * @param cls peer this message is from
1003  * @param incoming_flood received message
1004  */
1005 static void
1006 handle_p2p_estimate (void *cls,
1007                      const struct GNUNET_NSE_FloodMessage *incoming_flood)
1008 {
1009   struct NSEPeerEntry *peer_entry = cls;
1010   struct GNUNET_TIME_Absolute ts;
1011   uint32_t matching_bits;
1012   unsigned int idx;
1013
1014 #if ENABLE_NSE_HISTOGRAM
1015   {
1016     uint64_t t;
1017
1018     t = GNUNET_TIME_absolute_get ().abs_value_us;
1019     if (NULL != lh)
1020       GNUNET_TESTBED_LOGGER_write (lh, &t, sizeof (uint64_t));
1021     if (NULL != histogram)
1022       GNUNET_BIO_write_int64 (histogram, t);
1023   }
1024 #endif
1025   GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO);
1026   matching_bits = ntohl (incoming_flood->matching_bits);
1027 #if DEBUG_NSE
1028   {
1029     char origin[5];
1030     char pred[5];
1031     struct GNUNET_PeerIdentity os;
1032
1033     GNUNET_snprintf (origin,
1034                      sizeof (origin),
1035                      "%s",
1036                      GNUNET_i2s (&incoming_flood->origin));
1037     GNUNET_snprintf (pred, sizeof (pred), "%s", GNUNET_i2s (peer_entry->id));
1038     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1039                 "Flood at %s from `%s' via `%s' at `%s' with bits %u\n",
1040                 GNUNET_STRINGS_absolute_time_to_string (
1041                   GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp)),
1042                 origin,
1043                 pred,
1044                 GNUNET_i2s (&my_identity),
1045                 (unsigned int) matching_bits);
1046   }
1047 #endif
1048
1049 #if ENABLE_NSE_HISTOGRAM
1050   peer_entry->received_messages++;
1051   if (peer_entry->transmitted_messages > 0 &&
1052       peer_entry->last_transmitted_size >= matching_bits)
1053     GNUNET_STATISTICS_update (stats, "# cross messages", 1, GNUNET_NO);
1054 #endif
1055
1056   ts = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp);
1057   if (ts.abs_value_us == current_timestamp.abs_value_us)
1058     idx = estimate_index;
1059   else if (ts.abs_value_us ==
1060            current_timestamp.abs_value_us - gnunet_nse_interval.rel_value_us)
1061     idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1062   else if (ts.abs_value_us == next_timestamp.abs_value_us)
1063   {
1064     if (matching_bits <= ntohl (next_message.matching_bits))
1065       return; /* ignore, simply too early/late */
1066     if (GNUNET_YES != verify_message_crypto (incoming_flood))
1067     {
1068       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1069                   "Peer %s is likely ill-configured!\n",
1070                   GNUNET_i2s (peer_entry->id));
1071       GNUNET_break_op (0);
1072       return;
1073     }
1074     next_message = *incoming_flood;
1075     return;
1076   }
1077   else
1078   {
1079     GNUNET_STATISTICS_update (stats,
1080                               "# flood messages discarded (clock skew too large)",
1081                               1,
1082                               GNUNET_NO);
1083     return;
1084   }
1085   if (0 == (GNUNET_memcmp (peer_entry->id, &my_identity)))
1086   {
1087     /* send to self, update our own estimate IF this also comes from us! */
1088     if (0 == GNUNET_memcmp (&incoming_flood->origin, &my_identity))
1089       update_network_size_estimate ();
1090     return;
1091   }
1092   if (matching_bits == ntohl (size_estimate_messages[idx].matching_bits))
1093   {
1094     /* Cancel transmission in the other direction, as this peer clearly has
1095        up-to-date information already. Even if we didn't talk to this peer in
1096        the previous round, we should no longer send it stale information as it
1097        told us about the current round! */
1098     peer_entry->previous_round = GNUNET_YES;
1099     if (idx != estimate_index)
1100     {
1101       /* do not transmit information for the previous round to this peer
1102          anymore (but allow current round) */
1103       return;
1104     }
1105     /* got up-to-date information for current round, cancel transmission to
1106      * this peer altogether */
1107     if (NULL != peer_entry->transmit_task)
1108     {
1109       GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1110       peer_entry->transmit_task = NULL;
1111     }
1112     return;
1113   }
1114   if (matching_bits < ntohl (size_estimate_messages[idx].matching_bits))
1115   {
1116     if ((idx < estimate_index) && (peer_entry->previous_round == GNUNET_YES))
1117     {
1118       peer_entry->previous_round = GNUNET_NO;
1119     }
1120     /* push back our result now, that peer is spreading bad information... */
1121     if (NULL != peer_entry->transmit_task)
1122       GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1123     peer_entry->transmit_task =
1124       GNUNET_SCHEDULER_add_now (&transmit_task_cb, peer_entry);
1125     /* Not closer than our most recent message, no need to do work here */
1126     GNUNET_STATISTICS_update (stats,
1127                               "# flood messages ignored (had closer already)",
1128                               1,
1129                               GNUNET_NO);
1130     return;
1131   }
1132   if (GNUNET_YES != verify_message_crypto (incoming_flood))
1133   {
1134     GNUNET_break_op (0);
1135     return;
1136   }
1137   GNUNET_assert (matching_bits >
1138                  ntohl (size_estimate_messages[idx].matching_bits));
1139   /* Cancel transmission in the other direction, as this peer clearly has
1140    * up-to-date information already.
1141    */
1142   peer_entry->previous_round = GNUNET_YES;
1143   if (idx == estimate_index)
1144   {
1145     /* cancel any activity for current round */
1146     if (NULL != peer_entry->transmit_task)
1147     {
1148       GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1149       peer_entry->transmit_task = NULL;
1150     }
1151   }
1152   size_estimate_messages[idx] = *incoming_flood;
1153   size_estimate_messages[idx].hop_count =
1154     htonl (ntohl (incoming_flood->hop_count) + 1);
1155   hop_count_max =
1156     GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1, hop_count_max);
1157   GNUNET_STATISTICS_set (stats,
1158                          "# estimated network diameter",
1159                          hop_count_max,
1160                          GNUNET_NO);
1161
1162   /* have a new, better size estimate, inform clients */
1163   update_network_size_estimate ();
1164
1165   /* flood to rest */
1166   GNUNET_CONTAINER_multipeermap_iterate (peers,
1167                                          &update_flood_times,
1168                                          peer_entry);
1169 }
1170
1171
1172 /**
1173  * Method called whenever a peer connects. Sets up the PeerEntry and
1174  * schedules the initial size info transmission to this peer.
1175  *
1176  * @param cls closure
1177  * @param peer peer identity this notification is about
1178  */
1179 static void *
1180 handle_core_connect (void *cls,
1181                      const struct GNUNET_PeerIdentity *peer,
1182                      struct GNUNET_MQ_Handle *mq)
1183 {
1184   struct NSEPeerEntry *peer_entry;
1185
1186   (void) cls;
1187   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1188               "Peer `%s' connected to us\n",
1189               GNUNET_i2s (peer));
1190   /* set our default transmission options */
1191   GNUNET_MQ_set_options (mq, NSE_PRIORITY);
1192   /* create our peer entry for this peer */
1193   peer_entry = GNUNET_new (struct NSEPeerEntry);
1194   peer_entry->id = peer;
1195   peer_entry->mq = mq;
1196   GNUNET_assert (GNUNET_OK ==
1197                  GNUNET_CONTAINER_multipeermap_put (
1198                    peers,
1199                    peer_entry->id,
1200                    peer_entry,
1201                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1202   peer_entry->transmit_task =
1203     GNUNET_SCHEDULER_add_delayed (get_transmit_delay (-1),
1204                                   &transmit_task_cb,
1205                                   peer_entry);
1206   GNUNET_STATISTICS_update (stats, "# peers connected", 1, GNUNET_NO);
1207   return peer_entry;
1208 }
1209
1210
1211 /**
1212  * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
1213  * any pending transmission requests to that peer.
1214  *
1215  * @param cls closure
1216  * @param peer peer identity this notification is about
1217  * @parma internal_cls the `struct NSEPeerEntry` for the @a peer
1218  */
1219 static void
1220 handle_core_disconnect (void *cls,
1221                         const struct GNUNET_PeerIdentity *peer,
1222                         void *internal_cls)
1223 {
1224   struct NSEPeerEntry *pos = internal_cls;
1225
1226   (void) cls;
1227   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1228               "Peer `%s' disconnected from us\n",
1229               GNUNET_i2s (peer));
1230   GNUNET_assert (GNUNET_YES ==
1231                  GNUNET_CONTAINER_multipeermap_remove (peers, peer, pos));
1232   if (NULL != pos->transmit_task)
1233   {
1234     GNUNET_SCHEDULER_cancel (pos->transmit_task);
1235     pos->transmit_task = NULL;
1236   }
1237   GNUNET_free (pos);
1238   GNUNET_STATISTICS_update (stats, "# peers connected", -1, GNUNET_NO);
1239 }
1240
1241
1242 #if ENABLE_NSE_HISTOGRAM
1243 /**
1244  * Functions of this type are called to notify a successful transmission of the
1245  * message to the logger service
1246  *
1247  * @param cls NULL
1248  * @param size the amount of data sent (ignored)
1249  */
1250 static void
1251 flush_comp_cb (void *cls, size_t size)
1252 {
1253   (void) cls;
1254   (void) size;
1255   GNUNET_TESTBED_LOGGER_disconnect (lh);
1256   lh = NULL;
1257 }
1258 #endif
1259
1260
1261 /**
1262  * Task run during shutdown.
1263  *
1264  * @param cls unused
1265  */
1266 static void
1267 shutdown_task (void *cls)
1268 {
1269   (void) cls;
1270   if (NULL != flood_task)
1271   {
1272     GNUNET_SCHEDULER_cancel (flood_task);
1273     flood_task = NULL;
1274   }
1275   if (NULL != proof_task)
1276   {
1277     GNUNET_SCHEDULER_cancel (proof_task);
1278     proof_task = NULL;
1279     write_proof (); /* remember progress */
1280   }
1281   if (NULL != nc)
1282   {
1283     GNUNET_notification_context_destroy (nc);
1284     nc = NULL;
1285   }
1286   if (NULL != core_api)
1287   {
1288     GNUNET_CORE_disconnect (core_api);
1289     core_api = NULL;
1290   }
1291   if (NULL != stats)
1292   {
1293     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1294     stats = NULL;
1295   }
1296   if (NULL != peers)
1297   {
1298     GNUNET_CONTAINER_multipeermap_destroy (peers);
1299     peers = NULL;
1300   }
1301   if (NULL != my_private_key)
1302   {
1303     GNUNET_free (my_private_key);
1304     my_private_key = NULL;
1305   }
1306 #if ENABLE_NSE_HISTOGRAM
1307   if (NULL != logger_test)
1308   {
1309     GNUNET_CLIENT_service_test_cancel (logger_test);
1310     logger_test = NULL;
1311   }
1312   if (NULL != lh)
1313   {
1314     GNUNET_TESTBED_LOGGER_flush (lh, &flush_comp_cb, NULL);
1315   }
1316   if (NULL != histogram)
1317   {
1318     GNUNET_BIO_write_close (histogram);
1319     histogram = NULL;
1320   }
1321 #endif
1322 }
1323
1324
1325 /**
1326  * Called on core init/fail.
1327  *
1328  * @param cls service closure
1329  * @param identity the public identity of this peer
1330  */
1331 static void
1332 core_init (void *cls, const struct GNUNET_PeerIdentity *identity)
1333 {
1334   struct GNUNET_TIME_Absolute now;
1335   struct GNUNET_TIME_Absolute prev_time;
1336
1337   (void) cls;
1338   if (NULL == identity)
1339   {
1340     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection to core FAILED!\n");
1341     GNUNET_SCHEDULER_shutdown ();
1342     return;
1343   }
1344   GNUNET_assert (0 == GNUNET_memcmp (&my_identity, identity));
1345   now = GNUNET_TIME_absolute_get ();
1346   current_timestamp.abs_value_us =
1347     (now.abs_value_us / gnunet_nse_interval.rel_value_us) *
1348     gnunet_nse_interval.rel_value_us;
1349   next_timestamp =
1350     GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
1351   estimate_index = HISTORY_SIZE - 1;
1352   estimate_count = 0;
1353   if (GNUNET_YES == check_proof_of_work (&my_identity.public_key, my_proof))
1354   {
1355     int idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1356     prev_time.abs_value_us =
1357       current_timestamp.abs_value_us - gnunet_nse_interval.rel_value_us;
1358     setup_flood_message (idx, prev_time);
1359     setup_flood_message (estimate_index, current_timestamp);
1360     estimate_count++;
1361   }
1362   flood_task =
1363     GNUNET_SCHEDULER_add_at (next_timestamp, &update_flood_message, NULL);
1364 }
1365
1366
1367 #if ENABLE_NSE_HISTOGRAM
1368 /**
1369  * Function called with the status of the testbed logger service
1370  *
1371  * @param cls NULL
1372  * @param status #GNUNET_YES if the service is running,
1373  *               #GNUNET_NO if the service is not running
1374  *               #GNUNET_SYSERR if the configuration is invalid
1375  */
1376 static void
1377 status_cb (void *cls, int status)
1378 {
1379   (void) cls;
1380   logger_test = NULL;
1381   if (GNUNET_YES != status)
1382   {
1383     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed logger not running\n");
1384     return;
1385   }
1386   if (NULL == (lh = GNUNET_TESTBED_LOGGER_connect (cfg)))
1387   {
1388     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1389                 "Cannot connect to the testbed logger.  Exiting.\n");
1390     GNUNET_SCHEDULER_shutdown ();
1391   }
1392 }
1393 #endif
1394
1395
1396 /**
1397  * Handle network size estimate clients.
1398  *
1399  * @param cls closure
1400  * @param c configuration to use
1401  * @param service the initialized service
1402  */
1403 static void
1404 run (void *cls,
1405      const struct GNUNET_CONFIGURATION_Handle *c,
1406      struct GNUNET_SERVICE_Handle *service)
1407 {
1408   struct GNUNET_MQ_MessageHandler core_handlers[] =
1409     {GNUNET_MQ_hd_fixed_size (p2p_estimate,
1410                               GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD,
1411                               struct GNUNET_NSE_FloodMessage,
1412                               NULL),
1413      GNUNET_MQ_handler_end ()};
1414   char *proof;
1415   struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
1416
1417   (void) cls;
1418   (void) service;
1419   cfg = c;
1420   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
1421                                                         "NSE",
1422                                                         "INTERVAL",
1423                                                         &gnunet_nse_interval))
1424   {
1425     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "INTERVAL");
1426     GNUNET_SCHEDULER_shutdown ();
1427     return;
1428   }
1429   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
1430                                                         "NSE",
1431                                                         "WORKDELAY",
1432                                                         &proof_find_delay))
1433   {
1434     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKDELAY");
1435     GNUNET_SCHEDULER_shutdown ();
1436     return;
1437   }
1438   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
1439                                                           "NSE",
1440                                                           "WORKBITS",
1441                                                           &nse_work_required))
1442   {
1443     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKBITS");
1444     GNUNET_SCHEDULER_shutdown ();
1445     return;
1446   }
1447   if (nse_work_required >= sizeof (struct GNUNET_HashCode) * 8)
1448   {
1449     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1450                                "NSE",
1451                                "WORKBITS",
1452                                _ ("Value is too large.\n"));
1453     GNUNET_SCHEDULER_shutdown ();
1454     return;
1455   }
1456
1457 #if ENABLE_NSE_HISTOGRAM
1458   {
1459     char *histogram_dir;
1460     char *histogram_fn;
1461
1462     if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
1463                                                               "NSE",
1464                                                               "HISTOGRAM_DIR",
1465                                                               &histogram_dir))
1466     {
1467       GNUNET_assert (
1468         0 < GNUNET_asprintf (&histogram_fn, "%s/timestamps", histogram_dir));
1469       GNUNET_free (histogram_dir);
1470       histogram = GNUNET_BIO_write_open (histogram_fn);
1471       if (NULL == histogram)
1472         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1473                     "Unable to open histogram file `%s'\n",
1474                     histogram_fn);
1475       GNUNET_free (histogram_fn);
1476     }
1477     logger_test = GNUNET_CLIENT_service_test ("testbed-logger",
1478                                               cfg,
1479                                               GNUNET_TIME_UNIT_SECONDS,
1480                                               &status_cb,
1481                                               NULL);
1482   }
1483 #endif
1484
1485   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1486   pk = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
1487   GNUNET_assert (NULL != pk);
1488   my_private_key = pk;
1489   GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
1490   if (GNUNET_OK !=
1491       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
1492   {
1493     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "PROOFFILE");
1494     GNUNET_free (my_private_key);
1495     my_private_key = NULL;
1496     GNUNET_SCHEDULER_shutdown ();
1497     return;
1498   }
1499   if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) ||
1500       (sizeof (my_proof) !=
1501        GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof))))
1502     my_proof = 0;
1503   GNUNET_free (proof);
1504   proof_task =
1505     GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1506                                         &find_proof,
1507                                         NULL);
1508
1509   peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
1510   nc = GNUNET_notification_context_create (1);
1511   /* Connect to core service and register core handlers */
1512   core_api =
1513     GNUNET_CORE_connect (cfg, /* Main configuration */
1514                          NULL, /* Closure passed to functions */
1515                          &core_init, /* Call core_init once connected */
1516                          &handle_core_connect, /* Handle connects */
1517                          &handle_core_disconnect, /* Handle disconnects */
1518                          core_handlers); /* Register these handlers */
1519   if (NULL == core_api)
1520   {
1521     GNUNET_SCHEDULER_shutdown ();
1522     return;
1523   }
1524   stats = GNUNET_STATISTICS_create ("nse", cfg);
1525 }
1526
1527
1528 /**
1529  * Callback called when a client connects to the service.
1530  *
1531  * @param cls closure for the service
1532  * @param c the new client that connected to the service
1533  * @param mq the message queue used to send messages to the client
1534  * @return @a c
1535  */
1536 static void *
1537 client_connect_cb (void *cls,
1538                    struct GNUNET_SERVICE_Client *c,
1539                    struct GNUNET_MQ_Handle *mq)
1540 {
1541   (void) cls;
1542   (void) mq;
1543   return c;
1544 }
1545
1546
1547 /**
1548  * Callback called when a client disconnected from the service
1549  *
1550  * @param cls closure for the service
1551  * @param c the client that disconnected
1552  * @param internal_cls should be equal to @a c
1553  */
1554 static void
1555 client_disconnect_cb (void *cls,
1556                       struct GNUNET_SERVICE_Client *c,
1557                       void *internal_cls)
1558 {
1559   (void) cls;
1560   GNUNET_assert (c == internal_cls);
1561 }
1562
1563
1564 /**
1565  * Define "main" method using service macro.
1566  */
1567 GNUNET_SERVICE_MAIN ("nse",
1568                      GNUNET_SERVICE_OPTION_NONE,
1569                      &run,
1570                      &client_connect_cb,
1571                      &client_disconnect_cb,
1572                      NULL,
1573                      GNUNET_MQ_hd_fixed_size (start,
1574                                               GNUNET_MESSAGE_TYPE_NSE_START,
1575                                               struct GNUNET_MessageHeader,
1576                                               NULL),
1577                      GNUNET_MQ_handler_end ());
1578
1579
1580 #if defined(LINUX) && defined(__GLIBC__)
1581 #include <malloc.h>
1582
1583 /**
1584  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1585  */
1586 void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
1587 {
1588   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1589   mallopt (M_TOP_PAD, 1 * 1024);
1590   malloc_trim (0);
1591 }
1592 #endif
1593
1594
1595 /* end of gnunet-service-nse.c */