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