dns hijacker code review
[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_with_priority (proof_find_delay,
915                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
916                                                   &find_proof, NULL);
917 }
918
919
920 /**
921  * An incoming flood message has been received which claims
922  * to have more bits matching than any we know in this time
923  * period.  Verify the signature and/or proof of work.
924  *
925  * @param incoming_flood the message to verify
926  *
927  * @return GNUNET_YES if the message is verified
928  *         GNUNET_NO if the key/signature don't verify
929  */
930 static int
931 verify_message_crypto (const struct GNUNET_NSE_FloodMessage *incoming_flood)
932 {
933   if (GNUNET_YES !=
934       check_proof_of_work (&incoming_flood->pkey,
935                            incoming_flood->proof_of_work))
936   {
937     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Proof of work invalid: %llu!\n"),
938                 (unsigned long long)
939                 GNUNET_ntohll (incoming_flood->proof_of_work));
940     GNUNET_break_op (0);
941     return GNUNET_NO;
942   }
943   if ((nse_work_required > 0) &&
944       (GNUNET_OK !=
945        GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND,
946                                  &incoming_flood->purpose,
947                                  &incoming_flood->signature,
948                                  &incoming_flood->pkey)))
949   {
950     GNUNET_break_op (0);
951     return GNUNET_NO;
952   }
953   return GNUNET_YES;
954 }
955
956
957 /**
958  * Update transmissions for the given peer for the current round based
959  * on updated proximity information.
960  *
961  * @param cls peer entry to exclude from updates
962  * @param key hash of peer identity
963  * @param value the 'struct NSEPeerEntry'
964  * @return GNUNET_OK (continue to iterate)
965  */
966 static int
967 update_flood_times (void *cls, const GNUNET_HashCode * key, void *value)
968 {
969   struct NSEPeerEntry *exclude = cls;
970   struct NSEPeerEntry *peer_entry = value;
971   struct GNUNET_TIME_Relative delay;
972
973   if (peer_entry->th != NULL)
974     return GNUNET_OK;           /* already active */
975   if (peer_entry == exclude)
976     return GNUNET_OK;           /* trigger of the update */
977   if (peer_entry->previous_round == GNUNET_NO)
978   {
979     /* still stuck in previous round, no point to update, check that
980      * we are active here though... */
981     GNUNET_break (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK);
982     return GNUNET_OK;
983   }
984   if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
985   {
986     GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
987     peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
988   }
989   delay = get_transmit_delay (0);
990   peer_entry->transmit_task =
991       GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
992   return GNUNET_OK;
993 }
994
995
996 /**
997  * Core handler for size estimate flooding messages.
998  *
999  * @param cls closure unused
1000  * @param message message
1001  * @param peer peer identity this message is from (ignored)
1002  * @param atsi performance data (ignored)
1003  * @param atsi_count number of records in 'atsi'
1004  */
1005 static int
1006 handle_p2p_size_estimate (void *cls, const struct GNUNET_PeerIdentity *peer,
1007                           const struct GNUNET_MessageHeader *message,
1008                           const struct GNUNET_ATS_Information *atsi,
1009                           unsigned int atsi_count)
1010 {
1011   const struct GNUNET_NSE_FloodMessage *incoming_flood;
1012   struct GNUNET_TIME_Absolute ts;
1013   struct NSEPeerEntry *peer_entry;
1014   uint32_t matching_bits;
1015   unsigned int idx;
1016
1017 #if ENABLE_HISTOGRAM
1018   if (NULL != wh)
1019     GNUNET_BIO_write_int64 (wh, GNUNET_TIME_absolute_get ().abs_value);
1020 #endif
1021   incoming_flood = (const struct GNUNET_NSE_FloodMessage *) message;
1022   GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO);
1023   matching_bits = ntohl (incoming_flood->matching_bits);
1024 #if DEBUG_NSE
1025   {
1026     char origin[5];
1027     char pred[5];
1028     struct GNUNET_PeerIdentity os;
1029
1030     GNUNET_CRYPTO_hash (&incoming_flood->pkey,
1031                         sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1032                         &os.hashPubKey);
1033     GNUNET_snprintf (origin, sizeof (origin), "%s", GNUNET_i2s (&os));
1034     GNUNET_snprintf (pred, sizeof (pred), "%s", GNUNET_i2s (peer));
1035     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1036                 "Flood at %llu from `%s' via `%s' at `%s' with bits %u\n",
1037                 (unsigned long long)
1038                 GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value,
1039                 origin, pred, GNUNET_i2s (&my_identity),
1040                 (unsigned int) matching_bits);
1041   }
1042 #endif
1043
1044   peer_entry = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
1045   if (NULL == peer_entry)
1046   {
1047     GNUNET_break (0);
1048     return GNUNET_OK;
1049   }
1050 #if ENABLE_HISTOGRAM
1051   peer_entry->received_messages++;
1052   if (peer_entry->transmitted_messages > 0 && 
1053       peer_entry->last_transmitted_size >= matching_bits)
1054     GNUNET_STATISTICS_update(stats, "# cross messages", 1, GNUNET_NO);
1055 #endif
1056
1057   ts = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp);
1058
1059   if (ts.abs_value == current_timestamp.abs_value)
1060     idx = estimate_index;
1061   else if (ts.abs_value ==
1062            current_timestamp.abs_value - gnunet_nse_interval.rel_value)
1063     idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1064   else if (ts.abs_value ==
1065            next_timestamp.abs_value - gnunet_nse_interval.rel_value)
1066   {
1067     if (matching_bits <= ntohl (next_message.matching_bits))
1068       return GNUNET_OK;         /* ignore, simply too early/late */
1069     if (GNUNET_YES != verify_message_crypto (incoming_flood))
1070     {
1071       GNUNET_break_op (0);
1072       return GNUNET_OK;
1073     }
1074     next_message = *incoming_flood;
1075     return GNUNET_OK;
1076   }
1077   else
1078   {
1079     GNUNET_STATISTICS_update (stats,
1080                               "# flood messages discarded (clock skew too large)",
1081                               1, GNUNET_NO);
1082     return GNUNET_OK;
1083   }
1084   if (0 == (memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity))))
1085   {
1086     /* send to self, update our own estimate IF this also comes from us! */
1087     if (0 ==
1088         memcmp (&incoming_flood->pkey, &my_public_key, sizeof (my_public_key)))
1089       update_network_size_estimate ();
1090     return GNUNET_OK;
1091   }
1092   if (matching_bits == ntohl (size_estimate_messages[idx].matching_bits))
1093   {
1094     /* Cancel transmission in the other direction, as this peer clearly has
1095        up-to-date information already. Even if we didn't talk to this peer in
1096        the previous round, we should no longer send it stale information as it
1097        told us about the current round! */
1098     peer_entry->previous_round = GNUNET_YES;
1099     if (idx != estimate_index)
1100     {
1101       /* do not transmit information for the previous round to this peer 
1102          anymore (but allow current round) */
1103       return GNUNET_OK;
1104     }
1105     /* got up-to-date information for current round, cancel transmission to
1106      * this peer altogether */
1107     if (GNUNET_SCHEDULER_NO_TASK != peer_entry->transmit_task)
1108     {
1109       GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1110       peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1111     }
1112     if (peer_entry->th != NULL)
1113     {
1114       GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th);
1115       peer_entry->th = NULL;
1116     }
1117     return GNUNET_OK;
1118   }
1119   if (matching_bits < ntohl (size_estimate_messages[idx].matching_bits))
1120   {
1121     if ((idx < estimate_index) && (peer_entry->previous_round == GNUNET_YES))
1122       peer_entry->previous_round = GNUNET_NO;
1123     /* push back our result now, that peer is spreading bad information... */
1124     if (NULL == peer_entry->th)
1125     {
1126       if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1127         GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1128       peer_entry->transmit_task =
1129           GNUNET_SCHEDULER_add_now (&transmit_task_cb, peer_entry);
1130     }
1131     /* Not closer than our most recent message, no need to do work here */
1132     GNUNET_STATISTICS_update (stats,
1133                               "# flood messages ignored (had closer already)",
1134                               1, GNUNET_NO);
1135     return GNUNET_OK;
1136   }
1137   if (GNUNET_YES != verify_message_crypto (incoming_flood))
1138   {
1139     GNUNET_break_op (0);
1140     return GNUNET_OK;
1141   }
1142   GNUNET_assert (matching_bits >
1143                  ntohl (size_estimate_messages[idx].matching_bits));
1144   /* cancel transmission from us to this peer for this round */
1145   if (idx == estimate_index)
1146   {
1147       /* cancel any activity for current round */
1148       if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1149       {
1150         GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1151         peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1152       }
1153       if (peer_entry->th != NULL)
1154       {
1155         GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th);
1156         peer_entry->th = NULL;
1157       }
1158   }
1159   else
1160   {
1161     /* cancel previous round only */
1162     peer_entry->previous_round = GNUNET_YES;
1163   }
1164   size_estimate_messages[idx] = *incoming_flood;
1165   size_estimate_messages[idx].hop_count =
1166       htonl (ntohl (incoming_flood->hop_count) + 1);
1167   hop_count_max =
1168       GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1, hop_count_max);
1169   GNUNET_STATISTICS_set (stats,
1170                          "# estimated network diameter",
1171                          hop_count_max, GNUNET_NO);
1172
1173   /* have a new, better size estimate, inform clients */
1174   update_network_size_estimate ();
1175
1176   /* flood to rest */
1177   GNUNET_CONTAINER_multihashmap_iterate (peers, &update_flood_times,
1178                                          peer_entry);
1179   return GNUNET_OK;
1180 }
1181
1182
1183
1184 /**
1185  * Method called whenever a peer connects.
1186  *
1187  * @param cls closure
1188  * @param peer peer identity this notification is about
1189  * @param atsi performance data
1190  * @param atsi_count number of records in 'atsi'
1191  */
1192 static void
1193 handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
1194                      const struct GNUNET_ATS_Information *atsi,
1195                      unsigned int atsi_count)
1196 {
1197   struct NSEPeerEntry *peer_entry;
1198
1199 #if DEBUG_NSE
1200   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected to us\n",
1201               GNUNET_i2s (peer));
1202 #endif
1203   peer_entry = GNUNET_malloc (sizeof (struct NSEPeerEntry));
1204   peer_entry->id = *peer;
1205   GNUNET_assert (GNUNET_OK ==
1206                  GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey,
1207                                                     peer_entry,
1208                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1209   peer_entry->transmit_task =
1210       GNUNET_SCHEDULER_add_delayed (get_transmit_delay (-1), &transmit_task_cb,
1211                                     peer_entry);
1212   GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO);
1213 }
1214
1215
1216 /**
1217  * Method called whenever a peer disconnects.
1218  *
1219  * @param cls closure
1220  * @param peer peer identity this notification is about
1221  */
1222 static void
1223 handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
1224 {
1225   struct NSEPeerEntry *pos;
1226
1227 #if DEBUG_NSE
1228   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' disconnected from us\n",
1229               GNUNET_i2s (peer));
1230 #endif
1231   pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
1232   if (NULL == pos)
1233   {
1234     GNUNET_break (0);
1235     return;
1236   }
1237   GNUNET_assert (GNUNET_YES ==
1238                  GNUNET_CONTAINER_multihashmap_remove (peers, &peer->hashPubKey,
1239                                                        pos));
1240   if (pos->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1241     GNUNET_SCHEDULER_cancel (pos->transmit_task);
1242   if (pos->th != NULL)
1243   {
1244     GNUNET_CORE_notify_transmit_ready_cancel (pos->th);
1245     pos->th = NULL;
1246   }
1247   GNUNET_free (pos);
1248   GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO);
1249 }
1250
1251
1252 /**
1253  * Task run during shutdown.
1254  *
1255  * @param cls unused
1256  * @param tc unused
1257  */
1258 static void
1259 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1260 {
1261   if (flood_task != GNUNET_SCHEDULER_NO_TASK)
1262   {
1263     GNUNET_SCHEDULER_cancel (flood_task);
1264     flood_task = GNUNET_SCHEDULER_NO_TASK;
1265   }
1266   if (proof_task != GNUNET_SCHEDULER_NO_TASK)
1267   {
1268     GNUNET_SCHEDULER_cancel (proof_task);
1269     proof_task = GNUNET_SCHEDULER_NO_TASK;
1270     write_proof ();             /* remember progress */
1271   }
1272   if (nc != NULL)
1273   {
1274     GNUNET_SERVER_notification_context_destroy (nc);
1275     nc = NULL;
1276   }
1277   if (coreAPI != NULL)
1278   {
1279     GNUNET_CORE_disconnect (coreAPI);
1280     coreAPI = NULL;
1281   }
1282   if (stats != NULL)
1283   {
1284     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1285     stats = NULL;
1286   }
1287   if (peers != NULL)
1288   {
1289     GNUNET_CONTAINER_multihashmap_destroy (peers);
1290     peers = NULL;
1291   }
1292   if (my_private_key != NULL)
1293   {
1294     GNUNET_CRYPTO_rsa_key_free (my_private_key);
1295     my_private_key = NULL;
1296   }
1297 #if ENABLE_HISTOGRAM
1298   if (wh != NULL)
1299   {
1300     GNUNET_BIO_write_close (wh);
1301     wh = NULL;
1302   }
1303 #endif
1304 }
1305
1306
1307 /**
1308  * Called on core init/fail.
1309  *
1310  * @param cls service closure
1311  * @param server handle to the server for this service
1312  * @param identity the public identity of this peer
1313  */
1314 static void
1315 core_init (void *cls, struct GNUNET_CORE_Handle *server,
1316            const struct GNUNET_PeerIdentity *identity)
1317 {
1318   struct GNUNET_TIME_Absolute now;
1319   struct GNUNET_TIME_Absolute prev_time;
1320
1321   if (server == NULL)
1322   {
1323 #if DEBUG_NSE
1324     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to core FAILED!\n");
1325 #endif
1326     GNUNET_SCHEDULER_shutdown ();
1327     return;
1328   }
1329   GNUNET_assert (0 ==
1330                  memcmp (&my_identity, identity,
1331                          sizeof (struct GNUNET_PeerIdentity)));
1332   now = GNUNET_TIME_absolute_get ();
1333   current_timestamp.abs_value =
1334       (now.abs_value / gnunet_nse_interval.rel_value) *
1335       gnunet_nse_interval.rel_value;
1336   next_timestamp =
1337       GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
1338   estimate_index = HISTORY_SIZE - 1;
1339   estimate_count = 0;
1340   if (GNUNET_YES == check_proof_of_work (&my_public_key, my_proof))
1341   {
1342     prev_time.abs_value =
1343         current_timestamp.abs_value - gnunet_nse_interval.rel_value;
1344     setup_flood_message (estimate_index, prev_time);
1345     estimate_count++;
1346   }
1347   flood_task =
1348       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
1349                                     (next_timestamp), &update_flood_message,
1350                                     NULL);
1351 }
1352
1353
1354 /**
1355  * Handle network size estimate clients.
1356  *
1357  * @param cls closure
1358  * @param server the initialized server
1359  * @param c configuration to use
1360  */
1361 static void
1362 run (void *cls, struct GNUNET_SERVER_Handle *server,
1363      const struct GNUNET_CONFIGURATION_Handle *c)
1364 {
1365   char *keyfile;
1366   char *proof;
1367
1368   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1369     {&handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START,
1370      sizeof (struct GNUNET_MessageHeader)},
1371     {NULL, NULL, 0, 0}
1372   };
1373   static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
1374     {&handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD,
1375      sizeof (struct GNUNET_NSE_FloodMessage)},
1376     {NULL, 0, 0}
1377   };
1378   cfg = c;
1379
1380   if ((GNUNET_OK !=
1381        GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "INTERVAL",
1382                                             &gnunet_nse_interval)) ||
1383       (GNUNET_OK !=
1384        GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "WORKDELAY",
1385                                             &proof_find_delay)) ||
1386       (GNUNET_OK !=
1387        GNUNET_CONFIGURATION_get_value_number (cfg, "NSE", "WORKBITS",
1388                                               &nse_work_required)))
1389   {
1390     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1391                 _
1392                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1393     GNUNET_SCHEDULER_shutdown ();
1394     return;
1395   }
1396   if (nse_work_required >= sizeof (GNUNET_HashCode) * 8)
1397   {
1398     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1399                 _("Invalid work requirement for NSE service. Exiting.\n"));
1400     GNUNET_SCHEDULER_shutdown ();
1401     return;
1402   }
1403
1404
1405   if (GNUNET_OK !=
1406       GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY",
1407                                                &keyfile))
1408   {
1409     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1410                 _
1411                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1412     GNUNET_SCHEDULER_shutdown ();
1413     return;
1414   }
1415   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1416   GNUNET_free (keyfile);
1417   if (my_private_key == NULL)
1418   {
1419     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1420                 _("NSE service could not access hostkey.  Exiting.\n"));
1421     GNUNET_SCHEDULER_shutdown ();
1422     return;
1423   }
1424   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
1425   GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
1426                       &my_identity.hashPubKey);
1427   if (GNUNET_OK !=
1428       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
1429   {
1430     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1431                 _
1432                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1433     if (my_private_key != NULL)
1434     {
1435       GNUNET_CRYPTO_rsa_key_free (my_private_key);
1436       my_private_key = NULL;
1437     }
1438     GNUNET_SCHEDULER_shutdown ();
1439     return;
1440   }
1441   if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) ||
1442       (sizeof (my_proof) !=
1443        GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof))))
1444     my_proof = 0;
1445   GNUNET_free (proof);
1446   proof_task =
1447       GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1448                                           &find_proof, NULL);
1449
1450   peers = GNUNET_CONTAINER_multihashmap_create (128);
1451   GNUNET_SERVER_add_handlers (server, handlers);
1452   nc = GNUNET_SERVER_notification_context_create (server, 1);
1453   /* Connect to core service and register core handlers */
1454   coreAPI = GNUNET_CORE_connect (cfg,   /* Main configuration */
1455                                  1, NULL,       /* Closure passed to functions */
1456                                  &core_init,    /* Call core_init once connected */
1457                                  &handle_core_connect,  /* Handle connects */
1458                                  &handle_core_disconnect,       /* Handle disconnects */
1459                                  NULL,  /* Don't want notified about all incoming messages */
1460                                  GNUNET_NO,     /* For header only inbound notification */
1461                                  NULL,  /* Don't want notified about all outbound messages */
1462                                  GNUNET_NO,     /* For header only outbound notification */
1463                                  core_handlers);        /* Register these handlers */
1464   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1465                                 NULL);
1466 #if ENABLE_HISTOGRAM
1467   if (GNUNET_OK ==
1468       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "HISTOGRAM", &proof))
1469   {
1470     wh = GNUNET_BIO_write_open (proof);
1471     GNUNET_free (proof);
1472   }
1473 #endif
1474   if (coreAPI == NULL)
1475   {
1476     GNUNET_SCHEDULER_shutdown ();
1477     return;
1478   }
1479   stats = GNUNET_STATISTICS_create ("nse", cfg);
1480 }
1481
1482
1483 /**
1484  * The main function for the statistics service.
1485  *
1486  * @param argc number of arguments from the command line
1487  * @param argv command line arguments
1488  * @return 0 ok, 1 on error
1489  */
1490 int
1491 main (int argc, char *const *argv)
1492 {
1493   return (GNUNET_OK ==
1494           GNUNET_SERVICE_run (argc, argv, "nse", GNUNET_SERVICE_OPTION_NONE,
1495                               &run, NULL)) ? 0 : 1;
1496 }
1497
1498 /* end of gnunet-service-nse.c */