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