- Don't crash on bogus data from client
[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   double se = mean - 0.332747;
389   nsize = log2 (GNUNET_CONTAINER_multihashmap_size (peers) + 1);
390   if (em->size_estimate < nsize)
391     se = nsize;
392   em->size_estimate = GNUNET_hton_double (se);
393   em->std_deviation = GNUNET_hton_double (std_dev);
394   GNUNET_STATISTICS_set (stats, "# nodes in the network (estimate)",
395                          (uint64_t) pow (2, mean - 1.0 / 3.0), GNUNET_NO);
396 }
397
398
399 /**
400  * Handler for START message from client, triggers an
401  * immediate current network estimate notification.
402  * Also, we remember the client for updates upon future
403  * estimate measurements.
404  *
405  * @param cls unused
406  * @param client who sent the message
407  * @param message the message received
408  */
409 static void
410 handle_start_message (void *cls, struct GNUNET_SERVER_Client *client,
411                       const struct GNUNET_MessageHeader *message)
412 {
413   struct GNUNET_NSE_ClientMessage em;
414
415 #if DEBUG_NSE
416   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received START message from client\n");
417 #endif
418   GNUNET_SERVER_notification_context_add (nc, client);
419   setup_estimate_message (&em);
420   GNUNET_SERVER_notification_context_unicast (nc, client, &em.header,
421                                               GNUNET_YES);
422   GNUNET_SERVER_receive_done (client, GNUNET_OK);
423 }
424
425
426 /**
427  * How long should we delay a message to go the given number of
428  * matching bits?
429  *
430  * @param matching_bits number of matching bits to consider
431  */
432 static double
433 get_matching_bits_delay (uint32_t matching_bits)
434 {
435   /* Calculated as: S + f/2 - (f / pi) * (atan(x - p')) */
436   // S is next_timestamp (ignored in return value)
437   // f is frequency (gnunet_nse_interval)
438   // x is matching_bits
439   // p' is current_size_estimate
440   return ((double) gnunet_nse_interval.rel_value / (double) 2.0) -
441       ((gnunet_nse_interval.rel_value / M_PI) *
442        atan (matching_bits - current_size_estimate));
443 }
444
445
446 /**
447  * What delay randomization should we apply for a given number of matching bits?
448  *
449  * @param matching_bits number of matching bits
450  * @return random delay to apply
451  */
452 static struct GNUNET_TIME_Relative
453 get_delay_randomization (uint32_t matching_bits)
454 {
455 #if USE_RANDOM_DELAYS
456   struct GNUNET_TIME_Relative ret;
457   uint32_t i;
458   double d;
459
460   d = get_matching_bits_delay (matching_bits);
461   i = (uint32_t) (d / (double) (hop_count_max + 1));
462 #if DEBUG_NSE
463   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
464               "Randomizing flood using latencies up to %u ms\n",
465               (unsigned int) i);
466 #endif
467   ret.rel_value = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, i + 1);
468   return ret;
469 #else
470   return GNUNET_TIME_UNIT_ZERO;
471 #endif
472 }
473
474
475 /**
476  * Get the number of matching bits that the given timestamp has to the given peer ID.
477  *
478  * @param timestamp time to generate key
479  * @param id peer identity to compare with
480  * @return number of matching bits
481  */
482 static uint32_t
483 get_matching_bits (struct GNUNET_TIME_Absolute timestamp,
484                    const struct GNUNET_PeerIdentity *id)
485 {
486   GNUNET_HashCode timestamp_hash;
487
488   GNUNET_CRYPTO_hash (&timestamp.abs_value, sizeof (timestamp.abs_value),
489                       &timestamp_hash);
490   return GNUNET_CRYPTO_hash_matching_bits (&timestamp_hash, &id->hashPubKey);
491 }
492
493
494 /**
495  * Get the transmission delay that should be applied for a
496  * particular round.
497  *
498  * @param round_offset -1 for the previous round (random delay between 0 and 50ms)
499  *                      0 for the current round (based on our proximity to time key)
500  * @return delay that should be applied
501  */
502 static struct GNUNET_TIME_Relative
503 get_transmit_delay (int round_offset)
504 {
505   struct GNUNET_TIME_Relative ret;
506   struct GNUNET_TIME_Absolute tgt;
507   double dist_delay;
508   uint32_t matching_bits;
509
510   switch (round_offset)
511   {
512   case -1:
513     /* previous round is randomized between 0 and 50 ms */
514 #if USE_RANDOM_DELAYS
515     ret.rel_value = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, 50);
516 #else
517     ret = GNUNET_TIME_UNIT_ZERO;
518 #endif
519 #if DEBUG_NSE
520     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
521                 "Transmitting previous round behind schedule in %llu ms\n",
522                 (unsigned long long) ret.rel_value);
523 #endif
524     return ret;
525   case 0:
526     /* current round is based on best-known matching_bits */
527     matching_bits =
528         ntohl (size_estimate_messages[estimate_index].matching_bits);
529     dist_delay = get_matching_bits_delay (matching_bits);
530     dist_delay += get_delay_randomization (matching_bits).rel_value;
531     ret.rel_value = (uint64_t) dist_delay;
532 #if DEBUG_NSE
533     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
534                 "For round %llu, delay for %u matching bits is %llu ms\n",
535                 (unsigned long long) current_timestamp.abs_value,
536                 (unsigned int) matching_bits,
537                 (unsigned long long) ret.rel_value);
538 #endif
539     /* now consider round start time and add delay to it */
540     tgt = GNUNET_TIME_absolute_add (current_timestamp, ret);
541     return GNUNET_TIME_absolute_get_remaining (tgt);
542   }
543   GNUNET_break (0);
544   return GNUNET_TIME_UNIT_FOREVER_REL;
545 }
546
547
548 /**
549  * Task that triggers a NSE P2P transmission.
550  *
551  * @param cls the 'struct NSEPeerEntry'
552  * @param tc scheduler context
553  */
554 static void
555 transmit_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
556
557
558 /**
559  * Called when core is ready to send a message we asked for
560  * out to the destination.
561  *
562  * @param cls closure (NULL)
563  * @param size number of bytes available in buf
564  * @param buf where the callee should write the message
565  * @return number of bytes written to buf
566  */
567 static size_t
568 transmit_ready (void *cls, size_t size, void *buf)
569 {
570   struct NSEPeerEntry *peer_entry = cls;
571   unsigned int idx;
572
573   peer_entry->th = NULL;
574   if (buf == NULL)
575   {
576     /* client disconnected */
577     return 0;
578   }
579   GNUNET_assert (size >= sizeof (struct GNUNET_NSE_FloodMessage));
580   idx = estimate_index;
581   if (peer_entry->previous_round == GNUNET_NO)
582   {
583     idx = (idx + HISTORY_SIZE - 1) % HISTORY_SIZE;
584     peer_entry->previous_round = GNUNET_YES;
585     peer_entry->transmit_task =
586         GNUNET_SCHEDULER_add_delayed (get_transmit_delay (0), &transmit_task_cb,
587                                       peer_entry);
588   }
589   if ((ntohl (size_estimate_messages[idx].hop_count) == 0) &&
590       (GNUNET_SCHEDULER_NO_TASK != proof_task))
591   {
592     GNUNET_STATISTICS_update (stats,
593                               "# flood messages not generated (no proof yet)",
594                               1, GNUNET_NO);
595     return 0;
596   }
597   if (ntohs (size_estimate_messages[idx].header.size) == 0)
598   {
599     GNUNET_STATISTICS_update (stats,
600                               "# flood messages not generated (lack of history)",
601                               1, GNUNET_NO);
602     return 0;
603   }
604 #if DEBUG_NSE
605   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606               "In round %llu, sending to `%s' estimate with %u bits\n",
607               (unsigned long long)
608               GNUNET_TIME_absolute_ntoh (size_estimate_messages[idx].
609                                          timestamp).abs_value,
610               GNUNET_i2s (&peer_entry->id),
611               (unsigned int) ntohl (size_estimate_messages[idx].matching_bits));
612 #endif
613   if (ntohl (size_estimate_messages[idx].hop_count) == 0)
614     GNUNET_STATISTICS_update (stats, "# flood messages started", 1, GNUNET_NO);
615   GNUNET_STATISTICS_update (stats, "# flood messages transmitted", 1,
616                             GNUNET_NO);
617 #if ENABLE_HISTOGRAM
618   peer_entry->transmitted_messages++;
619   peer_entry->last_transmitted_size = 
620       ntohl(size_estimate_messages[idx].matching_bits);
621 #endif
622   memcpy (buf, &size_estimate_messages[idx],
623           sizeof (struct GNUNET_NSE_FloodMessage));
624   return sizeof (struct GNUNET_NSE_FloodMessage);
625 }
626
627
628 /**
629  * Task that triggers a NSE P2P transmission.
630  *
631  * @param cls the 'struct NSEPeerEntry'
632  * @param tc scheduler context
633  */
634 static void
635 transmit_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
636 {
637   struct NSEPeerEntry *peer_entry = cls;
638
639   peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
640   GNUNET_assert (NULL == peer_entry->th);
641   peer_entry->th =
642       GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_NO, NSE_PRIORITY,
643                                          GNUNET_TIME_UNIT_FOREVER_REL,
644                                          &peer_entry->id,
645                                          sizeof (struct
646                                                  GNUNET_NSE_FloodMessage),
647                                          &transmit_ready, peer_entry);
648 }
649
650
651 /**
652  * We've sent on our flood message or one that we received which was
653  * validated and closer than ours.  Update the global list of recent
654  * messages and the average.  Also re-broadcast the message to any
655  * clients.
656  */
657 static void
658 update_network_size_estimate ()
659 {
660   struct GNUNET_NSE_ClientMessage em;
661
662   setup_estimate_message (&em);
663   GNUNET_SERVER_notification_context_broadcast (nc, &em.header, GNUNET_YES);
664 }
665
666
667 /**
668  * Setup a flood message in our history array at the given
669  * slot offset for the given timestamp.
670  *
671  * @param slot index to use
672  * @param ts timestamp to use
673  */
674 static void
675 setup_flood_message (unsigned int slot, struct GNUNET_TIME_Absolute ts)
676 {
677   struct GNUNET_NSE_FloodMessage *fm;
678   uint32_t matching_bits;
679
680   matching_bits = get_matching_bits (ts, &my_identity);
681   fm = &size_estimate_messages[slot];
682   fm->header.size = htons (sizeof (struct GNUNET_NSE_FloodMessage));
683   fm->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD);
684   fm->hop_count = htonl (0);
685   fm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND);
686   fm->purpose.size =
687       htonl (sizeof (struct GNUNET_NSE_FloodMessage) -
688              sizeof (struct GNUNET_MessageHeader) - sizeof (uint32_t) -
689              sizeof (struct GNUNET_CRYPTO_RsaSignature));
690   fm->matching_bits = htonl (matching_bits);
691   fm->timestamp = GNUNET_TIME_absolute_hton (ts);
692   fm->pkey = my_public_key;
693   fm->proof_of_work = my_proof;
694   if (nse_work_required > 0)
695     GNUNET_assert (GNUNET_OK ==
696                    GNUNET_CRYPTO_rsa_sign (my_private_key, &fm->purpose,
697                                            &fm->signature));
698   else
699     memset (&fm->signature, 0, sizeof (fm->signature));
700 }
701
702
703 /**
704  * Schedule transmission for the given peer for the current round based
705  * on what we know about the desired delay.
706  *
707  * @param cls unused
708  * @param key hash of peer identity
709  * @param value the 'struct NSEPeerEntry'
710  * @return GNUNET_OK (continue to iterate)
711  */
712 static int
713 schedule_current_round (void *cls, const GNUNET_HashCode * key, void *value)
714 {
715   struct NSEPeerEntry *peer_entry = value;
716   struct GNUNET_TIME_Relative delay;
717
718   if (peer_entry->th != NULL)
719   {
720     peer_entry->previous_round = GNUNET_NO;
721     return GNUNET_OK;
722   }
723   if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
724   {
725     GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
726     peer_entry->previous_round = GNUNET_NO;
727   }
728 #if ENABLE_HISTOGRAM
729   if (peer_entry->received_messages > 1)
730     GNUNET_STATISTICS_update(stats, "# extra messages",
731                              peer_entry->received_messages - 1, GNUNET_NO);
732   peer_entry->transmitted_messages = 0;
733   peer_entry->last_transmitted_size = 0;
734   peer_entry->received_messages = 0;
735 #endif
736   delay =
737       get_transmit_delay ((peer_entry->previous_round == GNUNET_NO) ? -1 : 0);
738   peer_entry->transmit_task =
739       GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
740   return GNUNET_OK;
741 }
742
743
744 /**
745  * Update our flood message to be sent (and our timestamps).
746  *
747  * @param cls unused
748  * @param tc context for this message
749  */
750 static void
751 update_flood_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
752 {
753   struct GNUNET_TIME_Relative offset;
754   unsigned int i;
755
756   flood_task = GNUNET_SCHEDULER_NO_TASK;
757   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
758     return;
759   offset = GNUNET_TIME_absolute_get_remaining (next_timestamp);
760   if (0 != offset.rel_value)
761   {
762     /* somehow run early, delay more */
763     flood_task =
764         GNUNET_SCHEDULER_add_delayed (offset, &update_flood_message, NULL);
765     return;
766   }
767   current_timestamp = next_timestamp;
768   next_timestamp =
769       GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
770   estimate_index = (estimate_index + 1) % HISTORY_SIZE;
771   if (estimate_count < HISTORY_SIZE)
772     estimate_count++;
773   if (next_timestamp.abs_value ==
774       GNUNET_TIME_absolute_ntoh (next_message.timestamp).abs_value)
775   {
776     /* we received a message for this round way early, use it! */
777     size_estimate_messages[estimate_index] = next_message;
778     size_estimate_messages[estimate_index].hop_count =
779         htonl (1 + ntohl (next_message.hop_count));
780   }
781   else
782     setup_flood_message (estimate_index, current_timestamp);
783   next_message.matching_bits = htonl (0);       /* reset for 'next' round */
784   hop_count_max = 0;
785   for (i = 0; i < HISTORY_SIZE; i++)
786     hop_count_max =
787         GNUNET_MAX (ntohl (size_estimate_messages[i].hop_count), hop_count_max);
788   GNUNET_CONTAINER_multihashmap_iterate (peers, &schedule_current_round, NULL);
789   flood_task =
790       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
791                                     (next_timestamp), &update_flood_message,
792                                     NULL);
793 }
794
795
796 /**
797  * Count the leading zeroes in hash.
798  *
799  * @param hash
800  * @return the number of leading zero bits.
801  */
802 static unsigned int
803 count_leading_zeroes (const GNUNET_HashCode * hash)
804 {
805   unsigned int hash_count;
806
807   hash_count = 0;
808   while ((0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count)))
809     hash_count++;
810   return hash_count;
811 }
812
813
814 /**
815  * Check whether the given public key
816  * and integer are a valid proof of work.
817  *
818  * @param pkey the public key
819  * @param val the integer
820  *
821  * @return GNUNET_YES if valid, GNUNET_NO if not
822  */
823 static int
824 check_proof_of_work (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey,
825                      uint64_t val)
826 {
827   char buf[sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
828            sizeof (val)];
829   GNUNET_HashCode result;
830
831   memcpy (buf, &val, sizeof (val));
832   memcpy (&buf[sizeof (val)], pkey,
833           sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
834   GNUNET_CRYPTO_hash (buf, sizeof (buf), &result);
835   return (count_leading_zeroes (&result) >=
836           nse_work_required) ? GNUNET_YES : GNUNET_NO;
837 }
838
839
840 /**
841  * Write our current proof to disk.
842  */
843 static void
844 write_proof ()
845 {
846   char *proof;
847
848   if (GNUNET_OK !=
849       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
850     return;
851   if (sizeof (my_proof) !=
852       GNUNET_DISK_fn_write (proof, &my_proof, sizeof (my_proof),
853                             GNUNET_DISK_PERM_USER_READ |
854                             GNUNET_DISK_PERM_USER_WRITE))
855     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", proof);
856   GNUNET_free (proof);
857
858 }
859
860
861 /**
862  * Find our proof of work.
863  *
864  * @param cls closure (unused)
865  * @param tc task context
866  */
867 static void
868 find_proof (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
869 {
870 #define ROUND_SIZE 10
871   uint64_t counter;
872   char buf[sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
873            sizeof (uint64_t)];
874   GNUNET_HashCode result;
875   unsigned int i;
876
877   proof_task = GNUNET_SCHEDULER_NO_TASK;
878   memcpy (&buf[sizeof (uint64_t)], &my_public_key,
879           sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
880   i = 0;
881   counter = my_proof;
882   while ((counter != UINT64_MAX) && (i < ROUND_SIZE))
883   {
884     memcpy (buf, &counter, sizeof (uint64_t));
885     GNUNET_CRYPTO_hash (buf, sizeof (buf), &result);
886     if (nse_work_required <= count_leading_zeroes (&result))
887     {
888       my_proof = counter;
889 #if DEBUG_NSE
890       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Proof of work found: %llu!\n",
891                   (unsigned long long) GNUNET_ntohll (counter));
892 #endif
893       write_proof ();
894       setup_flood_message (estimate_index, current_timestamp);
895       return;
896     }
897     counter++;
898     i++;
899   }
900   if (my_proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE))
901   {
902 #if DEBUG_NSE
903     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing proofs currently at %llu\n",
904                 (unsigned long long) counter);
905 #endif
906     /* remember progress every 100 rounds */
907     my_proof = counter;
908     write_proof ();
909   }
910   else
911   {
912     my_proof = counter;
913   }
914   proof_task =
915       GNUNET_SCHEDULER_add_delayed_with_priority (proof_find_delay,
916                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
917                                                   &find_proof, NULL);
918 }
919
920
921 /**
922  * An incoming flood message has been received which claims
923  * to have more bits matching than any we know in this time
924  * period.  Verify the signature and/or proof of work.
925  *
926  * @param incoming_flood the message to verify
927  *
928  * @return GNUNET_YES if the message is verified
929  *         GNUNET_NO if the key/signature don't verify
930  */
931 static int
932 verify_message_crypto (const struct GNUNET_NSE_FloodMessage *incoming_flood)
933 {
934   if (GNUNET_YES !=
935       check_proof_of_work (&incoming_flood->pkey,
936                            incoming_flood->proof_of_work))
937   {
938     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Proof of work invalid: %llu!\n"),
939                 (unsigned long long)
940                 GNUNET_ntohll (incoming_flood->proof_of_work));
941     GNUNET_break_op (0);
942     return GNUNET_NO;
943   }
944   if ((nse_work_required > 0) &&
945       (GNUNET_OK !=
946        GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND,
947                                  &incoming_flood->purpose,
948                                  &incoming_flood->signature,
949                                  &incoming_flood->pkey)))
950   {
951     GNUNET_break_op (0);
952     return GNUNET_NO;
953   }
954   return GNUNET_YES;
955 }
956
957
958 /**
959  * Update transmissions for the given peer for the current round based
960  * on updated proximity information.
961  *
962  * @param cls peer entry to exclude from updates
963  * @param key hash of peer identity
964  * @param value the 'struct NSEPeerEntry'
965  * @return GNUNET_OK (continue to iterate)
966  */
967 static int
968 update_flood_times (void *cls, const GNUNET_HashCode * key, void *value)
969 {
970   struct NSEPeerEntry *exclude = cls;
971   struct NSEPeerEntry *peer_entry = value;
972   struct GNUNET_TIME_Relative delay;
973
974   if (peer_entry->th != NULL)
975     return GNUNET_OK;           /* already active */
976   if (peer_entry == exclude)
977     return GNUNET_OK;           /* trigger of the update */
978   if (peer_entry->previous_round == GNUNET_NO)
979   {
980     /* still stuck in previous round, no point to update, check that
981      * we are active here though... */
982     GNUNET_break (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK);
983     return GNUNET_OK;
984   }
985   if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
986   {
987     GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
988     peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
989   }
990   delay = get_transmit_delay (0);
991   peer_entry->transmit_task =
992       GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
993   return GNUNET_OK;
994 }
995
996
997 /**
998  * Core handler for size estimate flooding messages.
999  *
1000  * @param cls closure unused
1001  * @param message message
1002  * @param peer peer identity this message is from (ignored)
1003  * @param atsi performance data (ignored)
1004  * @param atsi_count number of records in 'atsi'
1005  */
1006 static int
1007 handle_p2p_size_estimate (void *cls, const struct GNUNET_PeerIdentity *peer,
1008                           const struct GNUNET_MessageHeader *message,
1009                           const struct GNUNET_ATS_Information *atsi,
1010                           unsigned int atsi_count)
1011 {
1012   const struct GNUNET_NSE_FloodMessage *incoming_flood;
1013   struct GNUNET_TIME_Absolute ts;
1014   struct NSEPeerEntry *peer_entry;
1015   uint32_t matching_bits;
1016   unsigned int idx;
1017
1018 #if ENABLE_HISTOGRAM
1019   if (NULL != wh)
1020     GNUNET_BIO_write_int64 (wh, GNUNET_TIME_absolute_get ().abs_value);
1021 #endif
1022   incoming_flood = (const struct GNUNET_NSE_FloodMessage *) message;
1023   GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO);
1024   matching_bits = ntohl (incoming_flood->matching_bits);
1025 #if DEBUG_NSE
1026   {
1027     char origin[5];
1028     char pred[5];
1029     struct GNUNET_PeerIdentity os;
1030
1031     GNUNET_CRYPTO_hash (&incoming_flood->pkey,
1032                         sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1033                         &os.hashPubKey);
1034     GNUNET_snprintf (origin, sizeof (origin), "%s", GNUNET_i2s (&os));
1035     GNUNET_snprintf (pred, sizeof (pred), "%s", GNUNET_i2s (peer));
1036     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1037                 "Flood at %llu from `%s' via `%s' at `%s' with bits %u\n",
1038                 (unsigned long long)
1039                 GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value,
1040                 origin, pred, GNUNET_i2s (&my_identity),
1041                 (unsigned int) matching_bits);
1042   }
1043 #endif
1044
1045   peer_entry = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
1046   if (NULL == peer_entry)
1047   {
1048     GNUNET_break (0);
1049     return GNUNET_OK;
1050   }
1051 #if ENABLE_HISTOGRAM
1052   peer_entry->received_messages++;
1053   if (peer_entry->transmitted_messages > 0 && 
1054       peer_entry->last_transmitted_size >= matching_bits)
1055     GNUNET_STATISTICS_update(stats, "# cross messages", 1, GNUNET_NO);
1056 #endif
1057
1058   ts = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp);
1059
1060   if (ts.abs_value == current_timestamp.abs_value)
1061     idx = estimate_index;
1062   else if (ts.abs_value ==
1063            current_timestamp.abs_value - gnunet_nse_interval.rel_value)
1064     idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1065   else if (ts.abs_value ==
1066            next_timestamp.abs_value - gnunet_nse_interval.rel_value)
1067   {
1068     if (matching_bits <= ntohl (next_message.matching_bits))
1069       return GNUNET_OK;         /* ignore, simply too early/late */
1070     if (GNUNET_YES != verify_message_crypto (incoming_flood))
1071     {
1072       GNUNET_break_op (0);
1073       return GNUNET_OK;
1074     }
1075     next_message = *incoming_flood;
1076     return GNUNET_OK;
1077   }
1078   else
1079   {
1080     GNUNET_STATISTICS_update (stats,
1081                               "# flood messages discarded (clock skew too large)",
1082                               1, GNUNET_NO);
1083     return GNUNET_OK;
1084   }
1085   if (0 == (memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity))))
1086   {
1087     /* send to self, update our own estimate IF this also comes from us! */
1088     if (0 ==
1089         memcmp (&incoming_flood->pkey, &my_public_key, sizeof (my_public_key)))
1090       update_network_size_estimate ();
1091     return GNUNET_OK;
1092   }
1093   if (matching_bits == ntohl (size_estimate_messages[idx].matching_bits))
1094   {
1095     /* Cancel transmission in the other direction, as this peer clearly has
1096        up-to-date information already. Even if we didn't talk to this peer in
1097        the previous round, we should no longer send it stale information as it
1098        told us about the current round! */
1099     peer_entry->previous_round = GNUNET_YES;
1100     if (idx != estimate_index)
1101     {
1102       /* do not transmit information for the previous round to this peer 
1103          anymore (but allow current round) */
1104       return GNUNET_OK;
1105     }
1106     /* got up-to-date information for current round, cancel transmission to
1107      * this peer altogether */
1108     if (GNUNET_SCHEDULER_NO_TASK != peer_entry->transmit_task)
1109     {
1110       GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1111       peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1112     }
1113     if (peer_entry->th != NULL)
1114     {
1115       GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th);
1116       peer_entry->th = NULL;
1117     }
1118     return GNUNET_OK;
1119   }
1120   if (matching_bits < ntohl (size_estimate_messages[idx].matching_bits))
1121   {
1122     if ((idx < estimate_index) && (peer_entry->previous_round == GNUNET_YES))
1123       peer_entry->previous_round = GNUNET_NO;
1124     /* push back our result now, that peer is spreading bad information... */
1125     if (NULL == peer_entry->th)
1126     {
1127       if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1128         GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1129       peer_entry->transmit_task =
1130           GNUNET_SCHEDULER_add_now (&transmit_task_cb, peer_entry);
1131     }
1132     /* Not closer than our most recent message, no need to do work here */
1133     GNUNET_STATISTICS_update (stats,
1134                               "# flood messages ignored (had closer already)",
1135                               1, GNUNET_NO);
1136     return GNUNET_OK;
1137   }
1138   if (GNUNET_YES != verify_message_crypto (incoming_flood))
1139   {
1140     GNUNET_break_op (0);
1141     return GNUNET_OK;
1142   }
1143   GNUNET_assert (matching_bits >
1144                  ntohl (size_estimate_messages[idx].matching_bits));
1145   /* cancel transmission from us to this peer for this round */
1146   if (idx == estimate_index)
1147   {
1148       /* cancel any activity for current round */
1149       if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1150       {
1151         GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1152         peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1153       }
1154       if (peer_entry->th != NULL)
1155       {
1156         GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th);
1157         peer_entry->th = NULL;
1158       }
1159   }
1160   else
1161   {
1162     /* cancel previous round only */
1163     peer_entry->previous_round = GNUNET_YES;
1164   }
1165   size_estimate_messages[idx] = *incoming_flood;
1166   size_estimate_messages[idx].hop_count =
1167       htonl (ntohl (incoming_flood->hop_count) + 1);
1168   hop_count_max =
1169       GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1, hop_count_max);
1170   GNUNET_STATISTICS_set (stats,
1171                          "# estimated network diameter",
1172                          hop_count_max, GNUNET_NO);
1173
1174   /* have a new, better size estimate, inform clients */
1175   update_network_size_estimate ();
1176
1177   /* flood to rest */
1178   GNUNET_CONTAINER_multihashmap_iterate (peers, &update_flood_times,
1179                                          peer_entry);
1180   return GNUNET_OK;
1181 }
1182
1183
1184
1185 /**
1186  * Method called whenever a peer connects.
1187  *
1188  * @param cls closure
1189  * @param peer peer identity this notification is about
1190  * @param atsi performance data
1191  * @param atsi_count number of records in 'atsi'
1192  */
1193 static void
1194 handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
1195                      const struct GNUNET_ATS_Information *atsi,
1196                      unsigned int atsi_count)
1197 {
1198   struct NSEPeerEntry *peer_entry;
1199
1200 #if DEBUG_NSE
1201   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected to us\n",
1202               GNUNET_i2s (peer));
1203 #endif
1204   peer_entry = GNUNET_malloc (sizeof (struct NSEPeerEntry));
1205   peer_entry->id = *peer;
1206   GNUNET_assert (GNUNET_OK ==
1207                  GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey,
1208                                                     peer_entry,
1209                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1210   peer_entry->transmit_task =
1211       GNUNET_SCHEDULER_add_delayed (get_transmit_delay (-1), &transmit_task_cb,
1212                                     peer_entry);
1213   GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO);
1214 }
1215
1216
1217 /**
1218  * Method called whenever a peer disconnects.
1219  *
1220  * @param cls closure
1221  * @param peer peer identity this notification is about
1222  */
1223 static void
1224 handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
1225 {
1226   struct NSEPeerEntry *pos;
1227
1228 #if DEBUG_NSE
1229   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' disconnected from us\n",
1230               GNUNET_i2s (peer));
1231 #endif
1232   pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
1233   if (NULL == pos)
1234   {
1235     GNUNET_break (0);
1236     return;
1237   }
1238   GNUNET_assert (GNUNET_YES ==
1239                  GNUNET_CONTAINER_multihashmap_remove (peers, &peer->hashPubKey,
1240                                                        pos));
1241   if (pos->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1242     GNUNET_SCHEDULER_cancel (pos->transmit_task);
1243   if (pos->th != NULL)
1244   {
1245     GNUNET_CORE_notify_transmit_ready_cancel (pos->th);
1246     pos->th = NULL;
1247   }
1248   GNUNET_free (pos);
1249   GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO);
1250 }
1251
1252
1253 /**
1254  * Task run during shutdown.
1255  *
1256  * @param cls unused
1257  * @param tc unused
1258  */
1259 static void
1260 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1261 {
1262   if (flood_task != GNUNET_SCHEDULER_NO_TASK)
1263   {
1264     GNUNET_SCHEDULER_cancel (flood_task);
1265     flood_task = GNUNET_SCHEDULER_NO_TASK;
1266   }
1267   if (proof_task != GNUNET_SCHEDULER_NO_TASK)
1268   {
1269     GNUNET_SCHEDULER_cancel (proof_task);
1270     proof_task = GNUNET_SCHEDULER_NO_TASK;
1271     write_proof ();             /* remember progress */
1272   }
1273   if (nc != NULL)
1274   {
1275     GNUNET_SERVER_notification_context_destroy (nc);
1276     nc = NULL;
1277   }
1278   if (coreAPI != NULL)
1279   {
1280     GNUNET_CORE_disconnect (coreAPI);
1281     coreAPI = NULL;
1282   }
1283   if (stats != NULL)
1284   {
1285     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1286     stats = NULL;
1287   }
1288   if (peers != NULL)
1289   {
1290     GNUNET_CONTAINER_multihashmap_destroy (peers);
1291     peers = NULL;
1292   }
1293   if (my_private_key != NULL)
1294   {
1295     GNUNET_CRYPTO_rsa_key_free (my_private_key);
1296     my_private_key = NULL;
1297   }
1298 #if ENABLE_HISTOGRAM
1299   if (wh != NULL)
1300   {
1301     GNUNET_BIO_write_close (wh);
1302     wh = NULL;
1303   }
1304 #endif
1305 }
1306
1307
1308 /**
1309  * Called on core init/fail.
1310  *
1311  * @param cls service closure
1312  * @param server handle to the server for this service
1313  * @param identity the public identity of this peer
1314  */
1315 static void
1316 core_init (void *cls, struct GNUNET_CORE_Handle *server,
1317            const struct GNUNET_PeerIdentity *identity)
1318 {
1319   struct GNUNET_TIME_Absolute now;
1320   struct GNUNET_TIME_Absolute prev_time;
1321
1322   if (server == NULL)
1323   {
1324 #if DEBUG_NSE
1325     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to core FAILED!\n");
1326 #endif
1327     GNUNET_SCHEDULER_shutdown ();
1328     return;
1329   }
1330   GNUNET_assert (0 ==
1331                  memcmp (&my_identity, identity,
1332                          sizeof (struct GNUNET_PeerIdentity)));
1333   now = GNUNET_TIME_absolute_get ();
1334   current_timestamp.abs_value =
1335       (now.abs_value / gnunet_nse_interval.rel_value) *
1336       gnunet_nse_interval.rel_value;
1337   next_timestamp =
1338       GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
1339   estimate_index = HISTORY_SIZE - 1;
1340   estimate_count = 0;
1341   if (GNUNET_YES == check_proof_of_work (&my_public_key, my_proof))
1342   {
1343     prev_time.abs_value =
1344         current_timestamp.abs_value - gnunet_nse_interval.rel_value;
1345     setup_flood_message (estimate_index, prev_time);
1346     estimate_count++;
1347   }
1348   flood_task =
1349       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
1350                                     (next_timestamp), &update_flood_message,
1351                                     NULL);
1352 }
1353
1354
1355 /**
1356  * Handle network size estimate clients.
1357  *
1358  * @param cls closure
1359  * @param server the initialized server
1360  * @param c configuration to use
1361  */
1362 static void
1363 run (void *cls, struct GNUNET_SERVER_Handle *server,
1364      const struct GNUNET_CONFIGURATION_Handle *c)
1365 {
1366   char *keyfile;
1367   char *proof;
1368
1369   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1370     {&handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START,
1371      sizeof (struct GNUNET_MessageHeader)},
1372     {NULL, NULL, 0, 0}
1373   };
1374   static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
1375     {&handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD,
1376      sizeof (struct GNUNET_NSE_FloodMessage)},
1377     {NULL, 0, 0}
1378   };
1379   cfg = c;
1380
1381   if ((GNUNET_OK !=
1382        GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "INTERVAL",
1383                                             &gnunet_nse_interval)) ||
1384       (GNUNET_OK !=
1385        GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "WORKDELAY",
1386                                             &proof_find_delay)) ||
1387       (GNUNET_OK !=
1388        GNUNET_CONFIGURATION_get_value_number (cfg, "NSE", "WORKBITS",
1389                                               &nse_work_required)))
1390   {
1391     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1392                 _
1393                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1394     GNUNET_SCHEDULER_shutdown ();
1395     return;
1396   }
1397   if (nse_work_required >= sizeof (GNUNET_HashCode) * 8)
1398   {
1399     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1400                 _("Invalid work requirement for NSE service. Exiting.\n"));
1401     GNUNET_SCHEDULER_shutdown ();
1402     return;
1403   }
1404
1405
1406   if (GNUNET_OK !=
1407       GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY",
1408                                                &keyfile))
1409   {
1410     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1411                 _
1412                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1413     GNUNET_SCHEDULER_shutdown ();
1414     return;
1415   }
1416   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1417   GNUNET_free (keyfile);
1418   if (my_private_key == NULL)
1419   {
1420     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1421                 _("NSE service could not access hostkey.  Exiting.\n"));
1422     GNUNET_SCHEDULER_shutdown ();
1423     return;
1424   }
1425   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
1426   GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
1427                       &my_identity.hashPubKey);
1428   if (GNUNET_OK !=
1429       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
1430   {
1431     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1432                 _
1433                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1434     if (my_private_key != NULL)
1435     {
1436       GNUNET_CRYPTO_rsa_key_free (my_private_key);
1437       my_private_key = NULL;
1438     }
1439     GNUNET_SCHEDULER_shutdown ();
1440     return;
1441   }
1442   if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) ||
1443       (sizeof (my_proof) !=
1444        GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof))))
1445     my_proof = 0;
1446   GNUNET_free (proof);
1447   proof_task =
1448       GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1449                                           &find_proof, NULL);
1450
1451   peers = GNUNET_CONTAINER_multihashmap_create (128);
1452   GNUNET_SERVER_add_handlers (server, handlers);
1453   nc = GNUNET_SERVER_notification_context_create (server, 1);
1454   /* Connect to core service and register core handlers */
1455   coreAPI = GNUNET_CORE_connect (cfg,   /* Main configuration */
1456                                  1, NULL,       /* Closure passed to functions */
1457                                  &core_init,    /* Call core_init once connected */
1458                                  &handle_core_connect,  /* Handle connects */
1459                                  &handle_core_disconnect,       /* Handle disconnects */
1460                                  NULL,  /* Don't want notified about all incoming messages */
1461                                  GNUNET_NO,     /* For header only inbound notification */
1462                                  NULL,  /* Don't want notified about all outbound messages */
1463                                  GNUNET_NO,     /* For header only outbound notification */
1464                                  core_handlers);        /* Register these handlers */
1465   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1466                                 NULL);
1467 #if ENABLE_HISTOGRAM
1468   if (GNUNET_OK ==
1469       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "HISTOGRAM", &proof))
1470   {
1471     wh = GNUNET_BIO_write_open (proof);
1472     GNUNET_free (proof);
1473   }
1474 #endif
1475   if (coreAPI == NULL)
1476   {
1477     GNUNET_SCHEDULER_shutdown ();
1478     return;
1479   }
1480   stats = GNUNET_STATISTICS_create ("nse", cfg);
1481 }
1482
1483
1484 /**
1485  * The main function for the statistics service.
1486  *
1487  * @param argc number of arguments from the command line
1488  * @param argv command line arguments
1489  * @return 0 ok, 1 on error
1490  */
1491 int
1492 main (int argc, char *const *argv)
1493 {
1494   return (GNUNET_OK ==
1495           GNUNET_SERVICE_run (argc, argv, "nse", GNUNET_SERVICE_OPTION_NONE,
1496                               &run, NULL)) ? 0 : 1;
1497 }
1498
1499 /* end of gnunet-service-nse.c */