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