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