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