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