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