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