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