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