-remove trailing whitespace
[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_EccSignature 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 *coreAPI;
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_EccPrivateKey *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 (coreAPI, 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_EccSignature));
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_ecc_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_EccPublicSignKey *pkey,
853                      uint64_t val)
854 {
855   char buf[sizeof (struct GNUNET_CRYPTO_EccPublicSignKey) +
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_EccPublicSignKey));
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_EccPublicSignKey) +
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, "Proof of work invalid: %llu!\n",
963                 (unsigned long long)
964                 GNUNET_ntohll (incoming_flood->proof_of_work));
965     GNUNET_break_op (0);
966     return GNUNET_NO;
967   }
968   if ((nse_work_required > 0) &&
969       (GNUNET_OK !=
970        GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND,
971                                  &incoming_flood->purpose,
972                                  &incoming_flood->signature,
973                                  &incoming_flood->origin.public_key)))
974   {
975     GNUNET_break_op (0);
976     return GNUNET_NO;
977   }
978   return GNUNET_YES;
979 }
980
981
982 /**
983  * Update transmissions for the given peer for the current round based
984  * on updated proximity information.
985  *
986  * @param cls peer entry to exclude from updates
987  * @param key hash of peer identity
988  * @param value the `struct NSEPeerEntry *` of a peer to transmit to
989  * @return #GNUNET_OK (continue to iterate)
990  */
991 static int
992 update_flood_times (void *cls,
993                     const struct GNUNET_PeerIdentity *key,
994                     void *value)
995 {
996   struct NSEPeerEntry *exclude = cls;
997   struct NSEPeerEntry *peer_entry = value;
998   struct GNUNET_TIME_Relative delay;
999
1000   if (NULL != peer_entry->th)
1001     return GNUNET_OK;           /* already active */
1002   if (peer_entry == exclude)
1003     return GNUNET_OK;           /* trigger of the update */
1004   if (peer_entry->previous_round == GNUNET_NO)
1005   {
1006     /* still stuck in previous round, no point to update, check that
1007      * we are active here though... */
1008     if ( (GNUNET_SCHEDULER_NO_TASK == peer_entry->transmit_task) &&
1009          (NULL == peer_entry->th) )
1010     {
1011         GNUNET_break (0);
1012     }
1013     return GNUNET_OK;
1014   }
1015   if (GNUNET_SCHEDULER_NO_TASK != peer_entry->transmit_task)
1016   {
1017     GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1018     peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1019   }
1020   delay = get_transmit_delay (0);
1021   peer_entry->transmit_task =
1022       GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
1023   return GNUNET_OK;
1024 }
1025
1026
1027 /**
1028  * Core handler for size estimate flooding messages.
1029  *
1030  * @param cls closure unused
1031  * @param message message
1032  * @param peer peer identity this message is from (ignored)
1033  */
1034 static int
1035 handle_p2p_size_estimate (void *cls,
1036                           const struct GNUNET_PeerIdentity *peer,
1037                           const struct GNUNET_MessageHeader *message)
1038 {
1039   const struct GNUNET_NSE_FloodMessage *incoming_flood;
1040   struct GNUNET_TIME_Absolute ts;
1041   struct NSEPeerEntry *peer_entry;
1042   uint32_t matching_bits;
1043   unsigned int idx;
1044
1045 #if ENABLE_NSE_HISTOGRAM
1046   {
1047     uint64_t t;
1048
1049     t = GNUNET_TIME_absolute_get().abs_value_us;
1050     GNUNET_TESTBED_LOGGER_write (lh, &t, sizeof (uint64_t));
1051   }
1052 #endif
1053   incoming_flood = (const struct GNUNET_NSE_FloodMessage *) message;
1054   GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO);
1055   matching_bits = ntohl (incoming_flood->matching_bits);
1056 #if DEBUG_NSE
1057   {
1058     char origin[5];
1059     char pred[5];
1060     struct GNUNET_PeerIdentity os;
1061
1062     GNUNET_snprintf (origin,
1063                      sizeof (origin),
1064                      "%4s",
1065                      GNUNET_i2s (&incoming_flood->origin));
1066     GNUNET_snprintf (pred,
1067                      sizeof (pred),
1068                      "%4s",
1069                      GNUNET_i2s (peer));
1070     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1071                 "Flood at %s from `%s' via `%s' at `%s' with bits %u\n",
1072                 GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp)),
1073                 origin, pred, GNUNET_i2s (&my_identity),
1074                 (unsigned int) matching_bits);
1075   }
1076 #endif
1077
1078   peer_entry = GNUNET_CONTAINER_multipeermap_get (peers, peer);
1079   if (NULL == peer_entry)
1080   {
1081     GNUNET_break (0);
1082     return GNUNET_OK;
1083   }
1084 #if ENABLE_NSE_HISTOGRAM
1085   peer_entry->received_messages++;
1086   if (peer_entry->transmitted_messages > 0 &&
1087       peer_entry->last_transmitted_size >= matching_bits)
1088     GNUNET_STATISTICS_update(stats, "# cross messages", 1, GNUNET_NO);
1089 #endif
1090
1091   ts = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp);
1092   if (ts.abs_value_us == current_timestamp.abs_value_us)
1093     idx = estimate_index;
1094   else if (ts.abs_value_us ==
1095            current_timestamp.abs_value_us - gnunet_nse_interval.rel_value_us)
1096     idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1097   else if (ts.abs_value_us == next_timestamp.abs_value_us)
1098   {
1099     if (matching_bits <= ntohl (next_message.matching_bits))
1100       return GNUNET_OK;         /* ignore, simply too early/late */
1101     if (GNUNET_YES != verify_message_crypto (incoming_flood))
1102     {
1103       GNUNET_break_op (0);
1104       return GNUNET_OK;
1105     }
1106     next_message = *incoming_flood;
1107     return GNUNET_OK;
1108   }
1109   else
1110   {
1111     GNUNET_STATISTICS_update (stats,
1112                               "# flood messages discarded (clock skew too large)",
1113                               1, GNUNET_NO);
1114     return GNUNET_OK;
1115   }
1116   if (0 == (memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity))))
1117   {
1118     /* send to self, update our own estimate IF this also comes from us! */
1119     if (0 ==
1120         memcmp (&incoming_flood->origin,
1121                 &my_identity, sizeof (my_identity)))
1122       update_network_size_estimate ();
1123     return GNUNET_OK;
1124   }
1125   if (matching_bits == ntohl (size_estimate_messages[idx].matching_bits))
1126   {
1127     /* Cancel transmission in the other direction, as this peer clearly has
1128        up-to-date information already. Even if we didn't talk to this peer in
1129        the previous round, we should no longer send it stale information as it
1130        told us about the current round! */
1131     peer_entry->previous_round = GNUNET_YES;
1132     if (idx != estimate_index)
1133     {
1134       /* do not transmit information for the previous round to this peer
1135          anymore (but allow current round) */
1136       return GNUNET_OK;
1137     }
1138     /* got up-to-date information for current round, cancel transmission to
1139      * this peer altogether */
1140     if (GNUNET_SCHEDULER_NO_TASK != peer_entry->transmit_task)
1141     {
1142       GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1143       peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1144     }
1145     if (NULL != peer_entry->th)
1146     {
1147       GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th);
1148       peer_entry->th = NULL;
1149     }
1150     return GNUNET_OK;
1151   }
1152   if (matching_bits < ntohl (size_estimate_messages[idx].matching_bits))
1153   {
1154     if ((idx < estimate_index) && (peer_entry->previous_round == GNUNET_YES)) {
1155       peer_entry->previous_round = GNUNET_NO;
1156     }
1157     /* push back our result now, that peer is spreading bad information... */
1158     if (NULL == peer_entry->th)
1159     {
1160       if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1161         GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1162       peer_entry->transmit_task =
1163           GNUNET_SCHEDULER_add_now (&transmit_task_cb, peer_entry);
1164     }
1165     /* Not closer than our most recent message, no need to do work here */
1166     GNUNET_STATISTICS_update (stats,
1167                               "# flood messages ignored (had closer already)",
1168                               1, GNUNET_NO);
1169     return GNUNET_OK;
1170   }
1171   if (GNUNET_YES != verify_message_crypto (incoming_flood))
1172   {
1173     GNUNET_break_op (0);
1174     return GNUNET_OK;
1175   }
1176   GNUNET_assert (matching_bits >
1177                  ntohl (size_estimate_messages[idx].matching_bits));
1178   /* Cancel transmission in the other direction, as this peer clearly has
1179    * up-to-date information already.
1180    */
1181   peer_entry->previous_round = GNUNET_YES;
1182   if (idx == estimate_index)
1183   {
1184       /* cancel any activity for current round */
1185       if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1186       {
1187         GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1188         peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1189       }
1190       if (peer_entry->th != NULL)
1191       {
1192         GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th);
1193         peer_entry->th = NULL;
1194       }
1195   }
1196   size_estimate_messages[idx] = *incoming_flood;
1197   size_estimate_messages[idx].hop_count =
1198       htonl (ntohl (incoming_flood->hop_count) + 1);
1199   hop_count_max =
1200       GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1, hop_count_max);
1201   GNUNET_STATISTICS_set (stats,
1202                          "# estimated network diameter",
1203                          hop_count_max, GNUNET_NO);
1204
1205   /* have a new, better size estimate, inform clients */
1206   update_network_size_estimate ();
1207
1208   /* flood to rest */
1209   GNUNET_CONTAINER_multipeermap_iterate (peers, &update_flood_times,
1210                                          peer_entry);
1211   return GNUNET_OK;
1212 }
1213
1214
1215
1216 /**
1217  * Method called whenever a peer connects. Sets up the PeerEntry and
1218  * schedules the initial size info transmission to this peer.
1219  *
1220  * @param cls closure
1221  * @param peer peer identity this notification is about
1222  */
1223 static void
1224 handle_core_connect (void *cls,
1225                      const struct GNUNET_PeerIdentity *peer)
1226 {
1227   struct NSEPeerEntry *peer_entry;
1228
1229   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected to us\n",
1230               GNUNET_i2s (peer));
1231   peer_entry = GNUNET_new (struct NSEPeerEntry);
1232   peer_entry->id = *peer;
1233   GNUNET_assert (GNUNET_OK ==
1234                  GNUNET_CONTAINER_multipeermap_put (peers, peer,
1235                                                     peer_entry,
1236                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1237   peer_entry->transmit_task =
1238       GNUNET_SCHEDULER_add_delayed (get_transmit_delay (-1), &transmit_task_cb,
1239                                     peer_entry);
1240   GNUNET_STATISTICS_update (stats, "# peers connected", 1, GNUNET_NO);
1241 }
1242
1243
1244 /**
1245  * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
1246  * any pending transmission requests to that peer.
1247  *
1248  * @param cls closure
1249  * @param peer peer identity this notification is about
1250  */
1251 static void
1252 handle_core_disconnect (void *cls,
1253                         const struct GNUNET_PeerIdentity *peer)
1254 {
1255   struct NSEPeerEntry *pos;
1256
1257   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1258               "Peer `%s' disconnected from us\n",
1259               GNUNET_i2s (peer));
1260   pos = GNUNET_CONTAINER_multipeermap_get (peers, peer);
1261   if (NULL == pos)
1262   {
1263     GNUNET_break (0);
1264     return;
1265   }
1266   GNUNET_assert (GNUNET_YES ==
1267                  GNUNET_CONTAINER_multipeermap_remove (peers, peer,
1268                                                        pos));
1269   if (pos->transmit_task != GNUNET_SCHEDULER_NO_TASK) {
1270     GNUNET_SCHEDULER_cancel (pos->transmit_task);
1271     pos->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1272   }
1273   if (NULL != pos->th)
1274   {
1275     GNUNET_CORE_notify_transmit_ready_cancel (pos->th);
1276     pos->th = NULL;
1277   }
1278   GNUNET_free (pos);
1279   GNUNET_STATISTICS_update (stats, "# peers connected", -1, GNUNET_NO);
1280 }
1281
1282
1283 #if ENABLE_NSE_HISTOGRAM
1284 /**
1285  * Functions of this type are called to notify a successful transmission of the
1286  * message to the logger service
1287  *
1288  * @param cls NULL
1289  * @param size the amount of data sent (ignored)
1290  */
1291 static void
1292 flush_comp_cb (void *cls,
1293                size_t size)
1294 {
1295   GNUNET_TESTBED_LOGGER_disconnect (lh);
1296   lh = NULL;
1297 }
1298 #endif
1299
1300
1301 /**
1302  * Task run during shutdown.
1303  *
1304  * @param cls unused
1305  * @param tc unused
1306  */
1307 static void
1308 shutdown_task (void *cls,
1309                const struct GNUNET_SCHEDULER_TaskContext *tc)
1310 {
1311   if (GNUNET_SCHEDULER_NO_TASK != flood_task)
1312   {
1313     GNUNET_SCHEDULER_cancel (flood_task);
1314     flood_task = GNUNET_SCHEDULER_NO_TASK;
1315   }
1316   if (GNUNET_SCHEDULER_NO_TASK != proof_task)
1317   {
1318     GNUNET_SCHEDULER_cancel (proof_task);
1319     proof_task = GNUNET_SCHEDULER_NO_TASK;
1320     write_proof ();             /* remember progress */
1321   }
1322   if (NULL != nc)
1323   {
1324     GNUNET_SERVER_notification_context_destroy (nc);
1325     nc = NULL;
1326   }
1327   if (NULL != coreAPI)
1328   {
1329     GNUNET_CORE_disconnect (coreAPI);
1330     coreAPI = NULL;
1331   }
1332   if (NULL != stats)
1333   {
1334     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1335     stats = NULL;
1336   }
1337   if (NULL != peers)
1338   {
1339     GNUNET_CONTAINER_multipeermap_destroy (peers);
1340     peers = NULL;
1341   }
1342   if (NULL != my_private_key)
1343   {
1344     GNUNET_free (my_private_key);
1345     my_private_key = NULL;
1346   }
1347 #if ENABLE_NSE_HISTOGRAM
1348   struct GNUNET_TIME_Relative timeout;
1349   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30);
1350   GNUNET_TESTBED_LOGGER_flush (lh, timeout, &flush_comp_cb, NULL);
1351 #endif
1352 }
1353
1354
1355 /**
1356  * Called on core init/fail.
1357  *
1358  * @param cls service closure
1359  * @param identity the public identity of this peer
1360  */
1361 static void
1362 core_init (void *cls,
1363            const struct GNUNET_PeerIdentity *identity)
1364 {
1365   struct GNUNET_TIME_Absolute now;
1366   struct GNUNET_TIME_Absolute prev_time;
1367
1368   if (NULL == identity)
1369   {
1370     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection to core FAILED!\n");
1371     GNUNET_SCHEDULER_shutdown ();
1372     return;
1373   }
1374   GNUNET_assert (0 ==
1375                  memcmp (&my_identity, identity,
1376                          sizeof (struct GNUNET_PeerIdentity)));
1377   now = GNUNET_TIME_absolute_get ();
1378   current_timestamp.abs_value_us =
1379       (now.abs_value_us / gnunet_nse_interval.rel_value_us) *
1380       gnunet_nse_interval.rel_value_us;
1381   next_timestamp =
1382       GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
1383   estimate_index = HISTORY_SIZE - 1;
1384   estimate_count = 0;
1385   if (GNUNET_YES == check_proof_of_work (&my_identity.public_key, my_proof))
1386   {
1387     int idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1388     prev_time.abs_value_us =
1389         current_timestamp.abs_value_us - gnunet_nse_interval.rel_value_us;
1390     setup_flood_message (idx, prev_time);
1391     setup_flood_message (estimate_index, current_timestamp);
1392     estimate_count++;
1393   }
1394   flood_task =
1395       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
1396                                     (next_timestamp), &update_flood_message,
1397                                     NULL);
1398 }
1399
1400
1401 /**
1402  * Handle network size estimate clients.
1403  *
1404  * @param cls closure
1405  * @param server the initialized server
1406  * @param c configuration to use
1407  */
1408 static void
1409 run (void *cls,
1410      struct GNUNET_SERVER_Handle *server,
1411      const struct GNUNET_CONFIGURATION_Handle *c)
1412 {
1413   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1414     {&handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START,
1415      sizeof (struct GNUNET_MessageHeader)},
1416     {NULL, NULL, 0, 0}
1417   };
1418   static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
1419     {&handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD,
1420      sizeof (struct GNUNET_NSE_FloodMessage)},
1421     {NULL, 0, 0}
1422   };
1423   char *proof;
1424   struct GNUNET_CRYPTO_EccPrivateKey *pk;
1425
1426   cfg = c;
1427   srv = server;
1428   if (GNUNET_OK !=
1429       GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "INTERVAL",
1430                                            &gnunet_nse_interval))
1431   {
1432     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1433                                "NSE", "INTERVAL");
1434     GNUNET_SCHEDULER_shutdown ();
1435     return;
1436   }
1437   if (GNUNET_OK !=
1438       GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "WORKDELAY",
1439                                            &proof_find_delay))
1440   {
1441     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1442                                "NSE", "WORKDELAY");
1443     GNUNET_SCHEDULER_shutdown ();
1444     return;
1445   }
1446   if (GNUNET_OK !=
1447       GNUNET_CONFIGURATION_get_value_number (cfg, "NSE", "WORKBITS",
1448                                              &nse_work_required))
1449   {
1450     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1451                                "NSE", "WORKBITS");
1452     GNUNET_SCHEDULER_shutdown ();
1453     return;
1454   }
1455   if (nse_work_required >= sizeof (struct GNUNET_HashCode) * 8)
1456   {
1457     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1458                                "NSE",
1459                                "WORKBITS",
1460                                _("Value is too large.\n"));
1461     GNUNET_SCHEDULER_shutdown ();
1462     return;
1463   }
1464
1465 #if ENABLE_NSE_HISTOGRAM
1466   if (NULL == (lh = GNUNET_TESTBED_LOGGER_connect (cfg)))
1467   {
1468     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1469                 "Cannot connect to the testbed logger.  Exiting.\n");
1470     GNUNET_SCHEDULER_shutdown ();
1471     return;
1472   }
1473 #endif
1474
1475   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1476                                 NULL);
1477   pk = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg);
1478   GNUNET_assert (NULL != pk);
1479   my_private_key = pk;
1480   GNUNET_CRYPTO_ecc_key_get_public_for_signature (my_private_key,
1481                                                   &my_identity.public_key);
1482   if (GNUNET_OK !=
1483       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
1484   {
1485     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1486                 _
1487                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1488     GNUNET_free (my_private_key);
1489     my_private_key = NULL;
1490     GNUNET_SCHEDULER_shutdown ();
1491     return;
1492   }
1493   if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) ||
1494       (sizeof (my_proof) !=
1495        GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof))))
1496     my_proof = 0;
1497   GNUNET_free (proof);
1498   proof_task =
1499       GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1500                                           &find_proof, NULL);
1501
1502   peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
1503   GNUNET_SERVER_add_handlers (srv, handlers);
1504   nc = GNUNET_SERVER_notification_context_create (srv, 1);
1505   /* Connect to core service and register core handlers */
1506   coreAPI = GNUNET_CORE_connect (cfg,   /* Main configuration */
1507                                  NULL,       /* Closure passed to functions */
1508                                  &core_init,    /* Call core_init once connected */
1509                                  &handle_core_connect,  /* Handle connects */
1510                                  &handle_core_disconnect,       /* Handle disconnects */
1511                                  NULL,  /* Don't want notified about all incoming messages */
1512                                  GNUNET_NO,     /* For header only inbound notification */
1513                                  NULL,  /* Don't want notified about all outbound messages */
1514                                  GNUNET_NO,     /* For header only outbound notification */
1515                                  core_handlers);        /* Register these handlers */
1516   if (NULL == coreAPI)
1517   {
1518     GNUNET_SCHEDULER_shutdown ();
1519     return;
1520   }
1521   stats = GNUNET_STATISTICS_create ("nse", cfg);
1522 }
1523
1524
1525 /**
1526  * The main function for the network size estimation service.
1527  *
1528  * @param argc number of arguments from the command line
1529  * @param argv command line arguments
1530  * @return 0 ok, 1 on error
1531  */
1532 int
1533 main (int argc,
1534       char *const *argv)
1535 {
1536   return (GNUNET_OK ==
1537           GNUNET_SERVICE_run (argc, argv, "nse", GNUNET_SERVICE_OPTION_NONE,
1538                               &run, NULL)) ? 0 : 1;
1539 }
1540
1541
1542 #ifdef LINUX
1543 #include <malloc.h>
1544
1545 /**
1546  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1547  */
1548 void __attribute__ ((constructor))
1549 GNUNET_ARM_memory_init ()
1550 {
1551   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1552   mallopt (M_TOP_PAD, 1 * 1024);
1553   malloc_trim (0);
1554 }
1555 #endif
1556
1557
1558
1559 /* end of gnunet-service-nse.c */