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