remove argon2 dependency. Use limited libsodium argon2id function for GNS and NSE
[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 #ifdef BSD
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  * Get the number of matching bits that the given timestamp has to the given peer ID.
492  *
493  * @param timestamp time to generate key
494  * @param id peer identity to compare with
495  * @return number of matching bits
496  */
497 static uint32_t
498 get_matching_bits (struct GNUNET_TIME_Absolute timestamp,
499                    const struct GNUNET_PeerIdentity *id)
500 {
501   struct GNUNET_HashCode timestamp_hash;
502   struct GNUNET_HashCode pid_hash;
503
504   GNUNET_CRYPTO_hash (&timestamp.abs_value_us,
505                       sizeof(timestamp.abs_value_us),
506                       &timestamp_hash);
507   GNUNET_CRYPTO_hash (id, sizeof(struct GNUNET_PeerIdentity), &pid_hash);
508   return GNUNET_CRYPTO_hash_matching_bits (&timestamp_hash, &pid_hash);
509 }
510
511
512 /**
513  * Get the transmission delay that should be applied for a
514  * particular round.
515  *
516  * @param round_offset -1 for the previous round (random delay between 0 and 50ms)
517  *                      0 for the current round (based on our proximity to time key)
518  * @return delay that should be applied
519  */
520 static struct GNUNET_TIME_Relative
521 get_transmit_delay (int round_offset)
522 {
523   struct GNUNET_TIME_Relative ret;
524   struct GNUNET_TIME_Absolute tgt;
525   double dist_delay;
526   uint32_t matching_bits;
527
528   switch (round_offset)
529   {
530   case -1:
531     /* previous round is randomized between 0 and 50 ms */
532 #if USE_RANDOM_DELAYS
533     ret.rel_value_us =
534       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, 50);
535 #else
536     ret = GNUNET_TIME_UNIT_ZERO;
537 #endif
538     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
539                 "Transmitting previous round behind schedule in %s\n",
540                 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
541     return ret;
542
543   case 0:
544     /* current round is based on best-known matching_bits */
545     matching_bits =
546       ntohl (size_estimate_messages[estimate_index].matching_bits);
547     dist_delay = get_matching_bits_delay (matching_bits);
548     dist_delay += get_delay_randomization (matching_bits).rel_value_us;
549     ret.rel_value_us = (uint64_t) dist_delay;
550     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
551                 "For round %s, delay for %u matching bits is %s\n",
552                 GNUNET_STRINGS_absolute_time_to_string (current_timestamp),
553                 (unsigned int) matching_bits,
554                 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
555     /* now consider round start time and add delay to it */
556     tgt = GNUNET_TIME_absolute_add (current_timestamp, ret);
557     return GNUNET_TIME_absolute_get_remaining (tgt);
558   }
559   GNUNET_break (0);
560   return GNUNET_TIME_UNIT_FOREVER_REL;
561 }
562
563
564 /**
565  * Task that triggers a NSE P2P transmission.
566  *
567  * @param cls the `struct NSEPeerEntry *`
568  */
569 static void
570 transmit_task_cb (void *cls)
571 {
572   struct NSEPeerEntry *peer_entry = cls;
573   unsigned int idx;
574   struct GNUNET_MQ_Envelope *env;
575
576   peer_entry->transmit_task = NULL;
577   idx = estimate_index;
578   if (GNUNET_NO == peer_entry->previous_round)
579   {
580     idx = (idx + HISTORY_SIZE - 1) % HISTORY_SIZE;
581     peer_entry->previous_round = GNUNET_YES;
582     peer_entry->transmit_task =
583       GNUNET_SCHEDULER_add_delayed (get_transmit_delay (0),
584                                     &transmit_task_cb,
585                                     peer_entry);
586   }
587   if ((0 == ntohl (size_estimate_messages[idx].hop_count)) &&
588       (NULL != proof_task))
589   {
590     GNUNET_STATISTICS_update (stats,
591                               "# flood messages not generated (no proof yet)",
592                               1,
593                               GNUNET_NO);
594     return;
595   }
596   if (0 == ntohs (size_estimate_messages[idx].header.size))
597   {
598     GNUNET_STATISTICS_update (stats,
599                               "# flood messages not generated (lack of history)",
600                               1,
601                               GNUNET_NO);
602     return;
603   }
604   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
605               "In round %s, sending to `%s' estimate with %u bits\n",
606               GNUNET_STRINGS_absolute_time_to_string (
607                 GNUNET_TIME_absolute_ntoh (
608                   size_estimate_messages[idx].timestamp)),
609               GNUNET_i2s (peer_entry->id),
610               (unsigned int) ntohl (size_estimate_messages[idx].matching_bits));
611   if (0 == ntohl (size_estimate_messages[idx].hop_count))
612     GNUNET_STATISTICS_update (stats, "# flood messages started", 1, GNUNET_NO);
613   GNUNET_STATISTICS_update (stats,
614                             "# flood messages transmitted",
615                             1,
616                             GNUNET_NO);
617 #if ENABLE_NSE_HISTOGRAM
618   peer_entry->transmitted_messages++;
619   peer_entry->last_transmitted_size =
620     ntohl (size_estimate_messages[idx].matching_bits);
621 #endif
622   env = GNUNET_MQ_msg_copy (&size_estimate_messages[idx].header);
623   GNUNET_MQ_send (peer_entry->mq, env);
624 }
625
626
627 /**
628  * We've sent on our flood message or one that we received which was
629  * validated and closer than ours.  Update the global list of recent
630  * messages and the average.  Also re-broadcast the message to any
631  * clients.
632  */
633 static void
634 update_network_size_estimate ()
635 {
636   struct GNUNET_NSE_ClientMessage em;
637
638   setup_estimate_message (&em);
639   GNUNET_notification_context_broadcast (nc, &em.header, GNUNET_YES);
640 }
641
642
643 /**
644  * Setup a flood message in our history array at the given
645  * slot offset for the given timestamp.
646  *
647  * @param slot index to use
648  * @param ts timestamp to use
649  */
650 static void
651 setup_flood_message (unsigned int slot, struct GNUNET_TIME_Absolute ts)
652 {
653   struct GNUNET_NSE_FloodMessage *fm;
654   uint32_t matching_bits;
655
656   matching_bits = get_matching_bits (ts, &my_identity);
657   fm = &size_estimate_messages[slot];
658   fm->header.size = htons (sizeof(struct GNUNET_NSE_FloodMessage));
659   fm->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD);
660   fm->hop_count = htonl (0);
661   fm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND);
662   fm->purpose.size =
663     htonl (sizeof(struct GNUNET_NSE_FloodMessage)
664            - sizeof(struct GNUNET_MessageHeader) - sizeof(uint32_t)
665            - sizeof(struct GNUNET_CRYPTO_EddsaSignature));
666   fm->matching_bits = htonl (matching_bits);
667   fm->timestamp = GNUNET_TIME_absolute_hton (ts);
668   fm->origin = my_identity;
669   fm->proof_of_work = my_proof;
670   if (nse_work_required > 0)
671     GNUNET_assert (GNUNET_OK ==
672                    GNUNET_CRYPTO_eddsa_sign_ (my_private_key,
673                                               &fm->purpose,
674                                               &fm->signature));
675   else
676     memset (&fm->signature, 0, sizeof(fm->signature));
677 }
678
679
680 /**
681  * Schedule transmission for the given peer for the current round based
682  * on what we know about the desired delay.
683  *
684  * @param cls unused
685  * @param key hash of peer identity
686  * @param value the `struct NSEPeerEntry`
687  * @return #GNUNET_OK (continue to iterate)
688  */
689 static int
690 schedule_current_round (void *cls,
691                         const struct GNUNET_PeerIdentity *key,
692                         void *value)
693 {
694   struct NSEPeerEntry *peer_entry = value;
695   struct GNUNET_TIME_Relative delay;
696
697   (void) cls;
698   (void) key;
699   if (NULL != peer_entry->transmit_task)
700   {
701     GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
702     peer_entry->previous_round = GNUNET_NO;
703   }
704 #if ENABLE_NSE_HISTOGRAM
705   if (peer_entry->received_messages > 1)
706     GNUNET_STATISTICS_update (stats,
707                               "# extra messages",
708                               peer_entry->received_messages - 1,
709                               GNUNET_NO);
710   peer_entry->transmitted_messages = 0;
711   peer_entry->last_transmitted_size = 0;
712   peer_entry->received_messages = 0;
713 #endif
714   delay =
715     get_transmit_delay ((GNUNET_NO == peer_entry->previous_round) ? -1 : 0);
716   peer_entry->transmit_task =
717     GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
718   return GNUNET_OK;
719 }
720
721
722 /**
723  * Update our flood message to be sent (and our timestamps).
724  *
725  * @param cls unused
726  */
727 static void
728 update_flood_message (void *cls)
729 {
730   struct GNUNET_TIME_Relative offset;
731
732   (void) cls;
733   flood_task = NULL;
734   offset = GNUNET_TIME_absolute_get_remaining (next_timestamp);
735   if (0 != offset.rel_value_us)
736   {
737     /* somehow run early, delay more */
738     flood_task =
739       GNUNET_SCHEDULER_add_delayed (offset, &update_flood_message, NULL);
740     return;
741   }
742   estimate_index = (estimate_index + 1) % HISTORY_SIZE;
743   if (estimate_count < HISTORY_SIZE)
744     estimate_count++;
745   current_timestamp = next_timestamp;
746   next_timestamp =
747     GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
748   if ((current_timestamp.abs_value_us ==
749        GNUNET_TIME_absolute_ntoh (next_message.timestamp).abs_value_us) &&
750       (get_matching_bits (current_timestamp, &my_identity) <
751        ntohl (next_message.matching_bits)))
752   {
753     /* we received a message for this round way early, use it! */
754     size_estimate_messages[estimate_index] = next_message;
755     size_estimate_messages[estimate_index].hop_count =
756       htonl (1 + ntohl (next_message.hop_count));
757   }
758   else
759     setup_flood_message (estimate_index, current_timestamp);
760   next_message.matching_bits = htonl (0);  /* reset for 'next' round */
761   hop_count_max = 0;
762   for (unsigned int i = 0; i < HISTORY_SIZE; i++)
763     hop_count_max =
764       GNUNET_MAX (ntohl (size_estimate_messages[i].hop_count), hop_count_max);
765   GNUNET_CONTAINER_multipeermap_iterate (peers, &schedule_current_round, NULL);
766   flood_task =
767     GNUNET_SCHEDULER_add_at (next_timestamp, &update_flood_message, NULL);
768 }
769
770
771 /**
772  * Count the leading zeroes in hash.
773  *
774  * @param hash to count leading zeros in
775  * @return the number of leading zero bits.
776  */
777 static unsigned int
778 count_leading_zeroes (const struct GNUNET_HashCode *hash)
779 {
780   unsigned int hash_count;
781
782   hash_count = 0;
783   while (0 == GNUNET_CRYPTO_hash_get_bit_ltr (hash, hash_count))
784     hash_count++;
785   return hash_count;
786 }
787
788
789 /**
790  * Check whether the given public key and integer are a valid proof of
791  * work.
792  *
793  * @param pkey the public key
794  * @param val the integer
795  * @return #GNUNET_YES if valid, #GNUNET_NO if not
796  */
797 static int
798 check_proof_of_work (const struct GNUNET_CRYPTO_EddsaPublicKey *pkey,
799                      uint64_t val)
800 {
801   char buf[sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
802            + sizeof(val)] GNUNET_ALIGN;
803   struct GNUNET_HashCode result;
804
805   GNUNET_memcpy (buf, &val, sizeof(val));
806   GNUNET_memcpy (&buf[sizeof(val)],
807                  pkey,
808                  sizeof(struct GNUNET_CRYPTO_EddsaPublicKey));
809   GNUNET_CRYPTO_pow_hash ("gnunet-nse-proof",
810                           buf,
811                           sizeof(buf),
812                           &result);
813   return (count_leading_zeroes (&result) >= nse_work_required) ? GNUNET_YES
814          : GNUNET_NO;
815 }
816
817
818 /**
819  * Write our current proof to disk.
820  */
821 static void
822 write_proof ()
823 {
824   char *proof;
825
826   if (GNUNET_OK !=
827       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
828     return;
829   if (sizeof(my_proof) != GNUNET_DISK_fn_write (proof,
830                                                 &my_proof,
831                                                 sizeof(my_proof),
832                                                 GNUNET_DISK_PERM_USER_READ
833                                                 | GNUNET_DISK_PERM_USER_WRITE))
834     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", proof);
835   GNUNET_free (proof);
836 }
837
838
839 /**
840  * Find our proof of work.
841  *
842  * @param cls closure (unused)
843  */
844 static void
845 find_proof (void *cls)
846 {
847 #define ROUND_SIZE 10
848   uint64_t counter;
849   char buf[sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
850            + sizeof(uint64_t)] GNUNET_ALIGN;
851   struct GNUNET_HashCode result;
852   unsigned int i;
853
854   (void) cls;
855   proof_task = NULL;
856   GNUNET_memcpy (&buf[sizeof(uint64_t)],
857                  &my_identity,
858                  sizeof(struct GNUNET_PeerIdentity));
859   i = 0;
860   counter = my_proof;
861   while ((counter != UINT64_MAX) && (i < ROUND_SIZE))
862   {
863     GNUNET_memcpy (buf, &counter, sizeof(uint64_t));
864     GNUNET_CRYPTO_pow_hash ("gnunet-nse-proof",
865                             buf,
866                             sizeof(buf),
867                             &result);
868     if (nse_work_required <= count_leading_zeroes (&result))
869     {
870       my_proof = counter;
871       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
872                   "Proof of work found: %llu!\n",
873                   (unsigned long long) GNUNET_ntohll (counter));
874       write_proof ();
875       setup_flood_message (estimate_index, current_timestamp);
876       return;
877     }
878     counter++;
879     i++;
880   }
881   if (my_proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE))
882   {
883     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
884                 "Testing proofs currently at %llu\n",
885                 (unsigned long long) counter);
886     /* remember progress every 100 rounds */
887     my_proof = counter;
888     write_proof ();
889   }
890   else
891   {
892     my_proof = counter;
893   }
894   proof_task =
895     GNUNET_SCHEDULER_add_delayed_with_priority (proof_find_delay,
896                                                 GNUNET_SCHEDULER_PRIORITY_IDLE,
897                                                 &find_proof,
898                                                 NULL);
899 }
900
901
902 /**
903  * An incoming flood message has been received which claims
904  * to have more bits matching than any we know in this time
905  * period.  Verify the signature and/or proof of work.
906  *
907  * @param incoming_flood the message to verify
908  * @return #GNUNET_YES if the message is verified
909  *         #GNUNET_NO if the key/signature don't verify
910  */
911 static int
912 verify_message_crypto (const struct GNUNET_NSE_FloodMessage *incoming_flood)
913 {
914   if (GNUNET_YES != check_proof_of_work (&incoming_flood->origin.public_key,
915                                          incoming_flood->proof_of_work))
916   {
917     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
918                 "Proof of work invalid: %llu!\n",
919                 (unsigned long long) GNUNET_ntohll (
920                   incoming_flood->proof_of_work));
921     GNUNET_break_op (0);
922     return GNUNET_NO;
923   }
924   if ((nse_work_required > 0) &&
925       (GNUNET_OK !=
926        GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_NSE_SEND,
927                                     &incoming_flood->purpose,
928                                     &incoming_flood->signature,
929                                     &incoming_flood->origin.public_key)))
930   {
931     GNUNET_break_op (0);
932     return GNUNET_NO;
933   }
934   return GNUNET_YES;
935 }
936
937
938 /**
939  * Update transmissions for the given peer for the current round based
940  * on updated proximity information.
941  *
942  * @param cls peer entry to exclude from updates
943  * @param key hash of peer identity
944  * @param value the `struct NSEPeerEntry *` of a peer to transmit to
945  * @return #GNUNET_OK (continue to iterate)
946  */
947 static int
948 update_flood_times (void *cls,
949                     const struct GNUNET_PeerIdentity *key,
950                     void *value)
951 {
952   struct NSEPeerEntry *exclude = cls;
953   struct NSEPeerEntry *peer_entry = value;
954   struct GNUNET_TIME_Relative delay;
955
956   (void) key;
957   if (peer_entry == exclude)
958     return GNUNET_OK; /* trigger of the update */
959   if (GNUNET_NO == peer_entry->previous_round)
960   {
961     /* still stuck in previous round, no point to update, check that
962      * we are active here though... */
963     if (NULL == peer_entry->transmit_task)
964     {
965       GNUNET_break (0);
966     }
967     return GNUNET_OK;
968   }
969   if (NULL != peer_entry->transmit_task)
970   {
971     GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
972     peer_entry->transmit_task = NULL;
973   }
974   delay = get_transmit_delay (0);
975   peer_entry->transmit_task =
976     GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
977   return GNUNET_OK;
978 }
979
980
981 /**
982  * Core handler for size estimate flooding messages.
983  *
984  * @param cls peer this message is from
985  * @param incoming_flood received message
986  */
987 static void
988 handle_p2p_estimate (void *cls,
989                      const struct GNUNET_NSE_FloodMessage *incoming_flood)
990 {
991   struct NSEPeerEntry *peer_entry = cls;
992   struct GNUNET_TIME_Absolute ts;
993   uint32_t matching_bits;
994   unsigned int idx;
995
996 #if ENABLE_NSE_HISTOGRAM
997   {
998     uint64_t t;
999
1000     t = GNUNET_TIME_absolute_get ().abs_value_us;
1001     if (NULL != lh)
1002       GNUNET_TESTBED_LOGGER_write (lh, &t, sizeof(uint64_t));
1003     if (NULL != histogram)
1004       GNUNET_BIO_write_int64 (histogram, "histogram-time", t);
1005   }
1006 #endif
1007   GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO);
1008   matching_bits = ntohl (incoming_flood->matching_bits);
1009 #if DEBUG_NSE
1010   {
1011     char origin[5];
1012     char pred[5];
1013     struct GNUNET_PeerIdentity os;
1014
1015     GNUNET_snprintf (origin,
1016                      sizeof(origin),
1017                      "%s",
1018                      GNUNET_i2s (&incoming_flood->origin));
1019     GNUNET_snprintf (pred, sizeof(pred), "%s", GNUNET_i2s (peer_entry->id));
1020     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1021                 "Flood at %s from `%s' via `%s' at `%s' with bits %u\n",
1022                 GNUNET_STRINGS_absolute_time_to_string (
1023                   GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp)),
1024                 origin,
1025                 pred,
1026                 GNUNET_i2s (&my_identity),
1027                 (unsigned int) matching_bits);
1028   }
1029 #endif
1030
1031 #if ENABLE_NSE_HISTOGRAM
1032   peer_entry->received_messages++;
1033   if ((peer_entry->transmitted_messages > 0) &&
1034       (peer_entry->last_transmitted_size >= matching_bits) )
1035     GNUNET_STATISTICS_update (stats, "# cross messages", 1, GNUNET_NO);
1036 #endif
1037
1038   ts = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp);
1039   if (ts.abs_value_us == current_timestamp.abs_value_us)
1040     idx = estimate_index;
1041   else if (ts.abs_value_us ==
1042            current_timestamp.abs_value_us - gnunet_nse_interval.rel_value_us)
1043     idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1044   else if (ts.abs_value_us == next_timestamp.abs_value_us)
1045   {
1046     if (matching_bits <= ntohl (next_message.matching_bits))
1047       return;   /* ignore, simply too early/late */
1048     if (GNUNET_YES != verify_message_crypto (incoming_flood))
1049     {
1050       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1051                   "Peer %s is likely ill-configured!\n",
1052                   GNUNET_i2s (peer_entry->id));
1053       GNUNET_break_op (0);
1054       return;
1055     }
1056     next_message = *incoming_flood;
1057     return;
1058   }
1059   else
1060   {
1061     GNUNET_STATISTICS_update (stats,
1062                               "# flood messages discarded (clock skew too large)",
1063                               1,
1064                               GNUNET_NO);
1065     return;
1066   }
1067   if (0 == (GNUNET_memcmp (peer_entry->id, &my_identity)))
1068   {
1069     /* send to self, update our own estimate IF this also comes from us! */
1070     if (0 == GNUNET_memcmp (&incoming_flood->origin, &my_identity))
1071       update_network_size_estimate ();
1072     return;
1073   }
1074   if (matching_bits == ntohl (size_estimate_messages[idx].matching_bits))
1075   {
1076     /* Cancel transmission in the other direction, as this peer clearly has
1077        up-to-date information already. Even if we didn't talk to this peer in
1078        the previous round, we should no longer send it stale information as it
1079        told us about the current round! */
1080     peer_entry->previous_round = GNUNET_YES;
1081     if (idx != estimate_index)
1082     {
1083       /* do not transmit information for the previous round to this peer
1084          anymore (but allow current round) */
1085       return;
1086     }
1087     /* got up-to-date information for current round, cancel transmission to
1088      * this peer altogether */
1089     if (NULL != peer_entry->transmit_task)
1090     {
1091       GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1092       peer_entry->transmit_task = NULL;
1093     }
1094     return;
1095   }
1096   if (matching_bits < ntohl (size_estimate_messages[idx].matching_bits))
1097   {
1098     if ((idx < estimate_index) && (peer_entry->previous_round == GNUNET_YES))
1099     {
1100       peer_entry->previous_round = GNUNET_NO;
1101     }
1102     /* push back our result now, that peer is spreading bad information... */
1103     if (NULL != peer_entry->transmit_task)
1104       GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1105     peer_entry->transmit_task =
1106       GNUNET_SCHEDULER_add_now (&transmit_task_cb, peer_entry);
1107     /* Not closer than our most recent message, no need to do work here */
1108     GNUNET_STATISTICS_update (stats,
1109                               "# flood messages ignored (had closer already)",
1110                               1,
1111                               GNUNET_NO);
1112     return;
1113   }
1114   if (GNUNET_YES != verify_message_crypto (incoming_flood))
1115   {
1116     GNUNET_break_op (0);
1117     return;
1118   }
1119   GNUNET_assert (matching_bits >
1120                  ntohl (size_estimate_messages[idx].matching_bits));
1121   /* Cancel transmission in the other direction, as this peer clearly has
1122    * up-to-date information already.
1123    */
1124   peer_entry->previous_round = GNUNET_YES;
1125   if (idx == estimate_index)
1126   {
1127     /* cancel any activity for current round */
1128     if (NULL != peer_entry->transmit_task)
1129     {
1130       GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1131       peer_entry->transmit_task = NULL;
1132     }
1133   }
1134   size_estimate_messages[idx] = *incoming_flood;
1135   size_estimate_messages[idx].hop_count =
1136     htonl (ntohl (incoming_flood->hop_count) + 1);
1137   hop_count_max =
1138     GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1, hop_count_max);
1139   GNUNET_STATISTICS_set (stats,
1140                          "# estimated network diameter",
1141                          hop_count_max,
1142                          GNUNET_NO);
1143
1144   /* have a new, better size estimate, inform clients */
1145   update_network_size_estimate ();
1146
1147   /* flood to rest */
1148   GNUNET_CONTAINER_multipeermap_iterate (peers,
1149                                          &update_flood_times,
1150                                          peer_entry);
1151 }
1152
1153
1154 /**
1155  * Method called whenever a peer connects. Sets up the PeerEntry and
1156  * schedules the initial size info transmission to this peer.
1157  *
1158  * @param cls closure
1159  * @param peer peer identity this notification is about
1160  */
1161 static void *
1162 handle_core_connect (void *cls,
1163                      const struct GNUNET_PeerIdentity *peer,
1164                      struct GNUNET_MQ_Handle *mq)
1165 {
1166   struct NSEPeerEntry *peer_entry;
1167
1168   (void) cls;
1169   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1170               "Peer `%s' connected to us\n",
1171               GNUNET_i2s (peer));
1172   /* set our default transmission options */
1173   GNUNET_MQ_set_options (mq, NSE_PRIORITY);
1174   /* create our peer entry for this peer */
1175   peer_entry = GNUNET_new (struct NSEPeerEntry);
1176   peer_entry->id = peer;
1177   peer_entry->mq = mq;
1178   GNUNET_assert (GNUNET_OK ==
1179                  GNUNET_CONTAINER_multipeermap_put (
1180                    peers,
1181                    peer_entry->id,
1182                    peer_entry,
1183                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1184   peer_entry->transmit_task =
1185     GNUNET_SCHEDULER_add_delayed (get_transmit_delay (-1),
1186                                   &transmit_task_cb,
1187                                   peer_entry);
1188   GNUNET_STATISTICS_update (stats, "# peers connected", 1, GNUNET_NO);
1189   return peer_entry;
1190 }
1191
1192
1193 /**
1194  * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
1195  * any pending transmission requests to that peer.
1196  *
1197  * @param cls closure
1198  * @param peer peer identity this notification is about
1199  * @parma internal_cls the `struct NSEPeerEntry` for the @a peer
1200  */
1201 static void
1202 handle_core_disconnect (void *cls,
1203                         const struct GNUNET_PeerIdentity *peer,
1204                         void *internal_cls)
1205 {
1206   struct NSEPeerEntry *pos = internal_cls;
1207
1208   (void) cls;
1209   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1210               "Peer `%s' disconnected from us\n",
1211               GNUNET_i2s (peer));
1212   GNUNET_assert (GNUNET_YES ==
1213                  GNUNET_CONTAINER_multipeermap_remove (peers, peer, pos));
1214   if (NULL != pos->transmit_task)
1215   {
1216     GNUNET_SCHEDULER_cancel (pos->transmit_task);
1217     pos->transmit_task = NULL;
1218   }
1219   GNUNET_free (pos);
1220   GNUNET_STATISTICS_update (stats, "# peers connected", -1, GNUNET_NO);
1221 }
1222
1223
1224 #if ENABLE_NSE_HISTOGRAM
1225 /**
1226  * Functions of this type are called to notify a successful transmission of the
1227  * message to the logger service
1228  *
1229  * @param cls NULL
1230  * @param size the amount of data sent (ignored)
1231  */
1232 static void
1233 flush_comp_cb (void *cls, size_t size)
1234 {
1235   (void) cls;
1236   (void) size;
1237   GNUNET_TESTBED_LOGGER_disconnect (lh);
1238   lh = NULL;
1239 }
1240
1241
1242 #endif
1243
1244
1245 /**
1246  * Task run during shutdown.
1247  *
1248  * @param cls unused
1249  */
1250 static void
1251 shutdown_task (void *cls)
1252 {
1253   (void) cls;
1254   if (NULL != flood_task)
1255   {
1256     GNUNET_SCHEDULER_cancel (flood_task);
1257     flood_task = NULL;
1258   }
1259   if (NULL != proof_task)
1260   {
1261     GNUNET_SCHEDULER_cancel (proof_task);
1262     proof_task = NULL;
1263     write_proof ();  /* remember progress */
1264   }
1265   if (NULL != nc)
1266   {
1267     GNUNET_notification_context_destroy (nc);
1268     nc = NULL;
1269   }
1270   if (NULL != core_api)
1271   {
1272     GNUNET_CORE_disconnect (core_api);
1273     core_api = NULL;
1274   }
1275   if (NULL != stats)
1276   {
1277     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1278     stats = NULL;
1279   }
1280   if (NULL != peers)
1281   {
1282     GNUNET_CONTAINER_multipeermap_destroy (peers);
1283     peers = NULL;
1284   }
1285   if (NULL != my_private_key)
1286   {
1287     GNUNET_free (my_private_key);
1288     my_private_key = NULL;
1289   }
1290 #if ENABLE_NSE_HISTOGRAM
1291   if (NULL != logger_test)
1292   {
1293     GNUNET_CLIENT_service_test_cancel (logger_test);
1294     logger_test = NULL;
1295   }
1296   if (NULL != lh)
1297   {
1298     GNUNET_TESTBED_LOGGER_flush (lh, &flush_comp_cb, NULL);
1299   }
1300   if (NULL != histogram)
1301   {
1302     GNUNET_BIO_write_close (histogram, NULL);
1303     histogram = NULL;
1304   }
1305 #endif
1306 }
1307
1308
1309 /**
1310  * Called on core init/fail.
1311  *
1312  * @param cls service closure
1313  * @param identity the public identity of this peer
1314  */
1315 static void
1316 core_init (void *cls, const struct GNUNET_PeerIdentity *identity)
1317 {
1318   struct GNUNET_TIME_Absolute now;
1319   struct GNUNET_TIME_Absolute prev_time;
1320
1321   (void) cls;
1322   if (NULL == identity)
1323   {
1324     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection to core FAILED!\n");
1325     GNUNET_SCHEDULER_shutdown ();
1326     return;
1327   }
1328   GNUNET_assert (0 == GNUNET_memcmp (&my_identity, identity));
1329   now = GNUNET_TIME_absolute_get ();
1330   current_timestamp.abs_value_us =
1331     (now.abs_value_us / gnunet_nse_interval.rel_value_us)
1332     * gnunet_nse_interval.rel_value_us;
1333   next_timestamp =
1334     GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
1335   estimate_index = HISTORY_SIZE - 1;
1336   estimate_count = 0;
1337   if (GNUNET_YES == check_proof_of_work (&my_identity.public_key, my_proof))
1338   {
1339     int idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1340     prev_time.abs_value_us =
1341       current_timestamp.abs_value_us - gnunet_nse_interval.rel_value_us;
1342     setup_flood_message (idx, prev_time);
1343     setup_flood_message (estimate_index, current_timestamp);
1344     estimate_count++;
1345   }
1346   flood_task =
1347     GNUNET_SCHEDULER_add_at (next_timestamp, &update_flood_message, NULL);
1348 }
1349
1350
1351 #if ENABLE_NSE_HISTOGRAM
1352 /**
1353  * Function called with the status of the testbed logger service
1354  *
1355  * @param cls NULL
1356  * @param status #GNUNET_YES if the service is running,
1357  *               #GNUNET_NO if the service is not running
1358  *               #GNUNET_SYSERR if the configuration is invalid
1359  */
1360 static void
1361 status_cb (void *cls, int status)
1362 {
1363   (void) cls;
1364   logger_test = NULL;
1365   if (GNUNET_YES != status)
1366   {
1367     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed logger not running\n");
1368     return;
1369   }
1370   if (NULL == (lh = GNUNET_TESTBED_LOGGER_connect (cfg)))
1371   {
1372     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1373                 "Cannot connect to the testbed logger.  Exiting.\n");
1374     GNUNET_SCHEDULER_shutdown ();
1375   }
1376 }
1377
1378
1379 #endif
1380
1381
1382 /**
1383  * Handle network size estimate clients.
1384  *
1385  * @param cls closure
1386  * @param c configuration to use
1387  * @param service the initialized service
1388  */
1389 static void
1390 run (void *cls,
1391      const struct GNUNET_CONFIGURATION_Handle *c,
1392      struct GNUNET_SERVICE_Handle *service)
1393 {
1394   struct GNUNET_MQ_MessageHandler core_handlers[] =
1395   { GNUNET_MQ_hd_fixed_size (p2p_estimate,
1396                              GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD,
1397                              struct GNUNET_NSE_FloodMessage,
1398                              NULL),
1399     GNUNET_MQ_handler_end () };
1400   char *proof;
1401   struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
1402
1403   (void) cls;
1404   (void) service;
1405   cfg = c;
1406   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
1407                                                         "NSE",
1408                                                         "INTERVAL",
1409                                                         &gnunet_nse_interval))
1410   {
1411     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "INTERVAL");
1412     GNUNET_SCHEDULER_shutdown ();
1413     return;
1414   }
1415   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
1416                                                         "NSE",
1417                                                         "WORKDELAY",
1418                                                         &proof_find_delay))
1419   {
1420     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKDELAY");
1421     GNUNET_SCHEDULER_shutdown ();
1422     return;
1423   }
1424   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
1425                                                           "NSE",
1426                                                           "WORKBITS",
1427                                                           &nse_work_required))
1428   {
1429     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "WORKBITS");
1430     GNUNET_SCHEDULER_shutdown ();
1431     return;
1432   }
1433   if (nse_work_required >= sizeof(struct GNUNET_HashCode) * 8)
1434   {
1435     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1436                                "NSE",
1437                                "WORKBITS",
1438                                _ ("Value is too large.\n"));
1439     GNUNET_SCHEDULER_shutdown ();
1440     return;
1441   }
1442
1443 #if ENABLE_NSE_HISTOGRAM
1444   {
1445     char *histogram_dir;
1446     char *histogram_fn;
1447
1448     if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
1449                                                               "NSE",
1450                                                               "HISTOGRAM_DIR",
1451                                                               &histogram_dir))
1452     {
1453       GNUNET_assert (
1454         0 < GNUNET_asprintf (&histogram_fn, "%s/timestamps", histogram_dir));
1455       GNUNET_free (histogram_dir);
1456       histogram = GNUNET_BIO_write_open_file (histogram_fn);
1457       if (NULL == histogram)
1458         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1459                     "Unable to open histogram file `%s'\n",
1460                     histogram_fn);
1461       GNUNET_free (histogram_fn);
1462     }
1463     logger_test = GNUNET_CLIENT_service_test ("testbed-logger",
1464                                               cfg,
1465                                               GNUNET_TIME_UNIT_SECONDS,
1466                                               &status_cb,
1467                                               NULL);
1468   }
1469 #endif
1470
1471   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1472   pk = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
1473   GNUNET_assert (NULL != pk);
1474   my_private_key = pk;
1475   GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
1476   if (GNUNET_OK !=
1477       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
1478   {
1479     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "NSE", "PROOFFILE");
1480     GNUNET_free (my_private_key);
1481     my_private_key = NULL;
1482     GNUNET_SCHEDULER_shutdown ();
1483     return;
1484   }
1485   if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) ||
1486       (sizeof(my_proof) !=
1487        GNUNET_DISK_fn_read (proof, &my_proof, sizeof(my_proof))))
1488     my_proof = 0;
1489   GNUNET_free (proof);
1490   proof_task =
1491     GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1492                                         &find_proof,
1493                                         NULL);
1494
1495   peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
1496   nc = GNUNET_notification_context_create (1);
1497   /* Connect to core service and register core handlers */
1498   core_api =
1499     GNUNET_CORE_connect (cfg,  /* Main configuration */
1500                          NULL, /* Closure passed to functions */
1501                          &core_init, /* Call core_init once connected */
1502                          &handle_core_connect, /* Handle connects */
1503                          &handle_core_disconnect, /* Handle disconnects */
1504                          core_handlers); /* Register these handlers */
1505   if (NULL == core_api)
1506   {
1507     GNUNET_SCHEDULER_shutdown ();
1508     return;
1509   }
1510   stats = GNUNET_STATISTICS_create ("nse", cfg);
1511 }
1512
1513
1514 /**
1515  * Callback called when a client connects to the service.
1516  *
1517  * @param cls closure for the service
1518  * @param c the new client that connected to the service
1519  * @param mq the message queue used to send messages to the client
1520  * @return @a c
1521  */
1522 static void *
1523 client_connect_cb (void *cls,
1524                    struct GNUNET_SERVICE_Client *c,
1525                    struct GNUNET_MQ_Handle *mq)
1526 {
1527   (void) cls;
1528   (void) mq;
1529   return c;
1530 }
1531
1532
1533 /**
1534  * Callback called when a client disconnected from the service
1535  *
1536  * @param cls closure for the service
1537  * @param c the client that disconnected
1538  * @param internal_cls should be equal to @a c
1539  */
1540 static void
1541 client_disconnect_cb (void *cls,
1542                       struct GNUNET_SERVICE_Client *c,
1543                       void *internal_cls)
1544 {
1545   (void) cls;
1546   GNUNET_assert (c == internal_cls);
1547 }
1548
1549
1550 /**
1551  * Define "main" method using service macro.
1552  */
1553 GNUNET_SERVICE_MAIN ("nse",
1554                      GNUNET_SERVICE_OPTION_NONE,
1555                      &run,
1556                      &client_connect_cb,
1557                      &client_disconnect_cb,
1558                      NULL,
1559                      GNUNET_MQ_hd_fixed_size (start,
1560                                               GNUNET_MESSAGE_TYPE_NSE_START,
1561                                               struct GNUNET_MessageHeader,
1562                                               NULL),
1563                      GNUNET_MQ_handler_end ());
1564
1565
1566 #if defined(__linux__) && defined(__GLIBC__)
1567 #include <malloc.h>
1568
1569 /**
1570  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1571  */
1572 void __attribute__ ((constructor))
1573 GNUNET_ARM_memory_init ()
1574 {
1575   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1576   mallopt (M_TOP_PAD, 1 * 1024);
1577   malloc_trim (0);
1578 }
1579
1580
1581 #endif
1582
1583
1584 /* end of gnunet-service-nse.c */