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