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