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