- Fix contidion for next round
[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   em->size_estimate = GNUNET_hton_double (GNUNET_MAX (se, nsize));
391   em->std_deviation = GNUNET_hton_double (std_dev);
392   GNUNET_STATISTICS_set (stats, "# nodes in the network (estimate)",
393                          (uint64_t) pow (2, mean - 1.0 / 3.0), GNUNET_NO);
394 }
395
396
397 /**
398  * Handler for START message from client, triggers an
399  * immediate current network estimate notification.
400  * Also, we remember the client for updates upon future
401  * estimate measurements.
402  *
403  * @param cls unused
404  * @param client who sent the message
405  * @param message the message received
406  */
407 static void
408 handle_start_message (void *cls, struct GNUNET_SERVER_Client *client,
409                       const struct GNUNET_MessageHeader *message)
410 {
411   struct GNUNET_NSE_ClientMessage em;
412
413 #if DEBUG_NSE
414   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received START message from client\n");
415 #endif
416   GNUNET_SERVER_notification_context_add (nc, client);
417   setup_estimate_message (&em);
418   GNUNET_SERVER_notification_context_unicast (nc, client, &em.header,
419                                               GNUNET_YES);
420   GNUNET_SERVER_receive_done (client, GNUNET_OK);
421 }
422
423
424 /**
425  * How long should we delay a message to go the given number of
426  * matching bits?
427  *
428  * @param matching_bits number of matching bits to consider
429  */
430 static double
431 get_matching_bits_delay (uint32_t matching_bits)
432 {
433   /* Calculated as: S + f/2 - (f / pi) * (atan(x - p')) */
434   // S is next_timestamp (ignored in return value)
435   // f is frequency (gnunet_nse_interval)
436   // x is matching_bits
437   // p' is current_size_estimate
438   return ((double) gnunet_nse_interval.rel_value / (double) 2.0) -
439       ((gnunet_nse_interval.rel_value / M_PI) *
440        atan (matching_bits - current_size_estimate));
441 }
442
443
444 /**
445  * What delay randomization should we apply for a given number of matching bits?
446  *
447  * @param matching_bits number of matching bits
448  * @return random delay to apply
449  */
450 static struct GNUNET_TIME_Relative
451 get_delay_randomization (uint32_t matching_bits)
452 {
453 #if USE_RANDOM_DELAYS
454   struct GNUNET_TIME_Relative ret;
455   uint32_t i;
456   double d;
457
458   d = get_matching_bits_delay (matching_bits);
459   i = (uint32_t) (d / (double) (hop_count_max + 1));
460 #if DEBUG_NSE
461   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
462               "Randomizing flood using latencies up to %u ms\n",
463               (unsigned int) i);
464 #endif
465   ret.rel_value = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, i + 1);
466   return ret;
467 #else
468   return GNUNET_TIME_UNIT_ZERO;
469 #endif
470 }
471
472
473 /**
474  * Get the number of matching bits that the given timestamp has to the given peer ID.
475  *
476  * @param timestamp time to generate key
477  * @param id peer identity to compare with
478  * @return number of matching bits
479  */
480 static uint32_t
481 get_matching_bits (struct GNUNET_TIME_Absolute timestamp,
482                    const struct GNUNET_PeerIdentity *id)
483 {
484   GNUNET_HashCode timestamp_hash;
485
486   GNUNET_CRYPTO_hash (&timestamp.abs_value, sizeof (timestamp.abs_value),
487                       &timestamp_hash);
488   return GNUNET_CRYPTO_hash_matching_bits (&timestamp_hash, &id->hashPubKey);
489 }
490
491
492 /**
493  * Get the transmission delay that should be applied for a
494  * particular round.
495  *
496  * @param round_offset -1 for the previous round (random delay between 0 and 50ms)
497  *                      0 for the current round (based on our proximity to time key)
498  * @return delay that should be applied
499  */
500 static struct GNUNET_TIME_Relative
501 get_transmit_delay (int round_offset)
502 {
503   struct GNUNET_TIME_Relative ret;
504   struct GNUNET_TIME_Absolute tgt;
505   double dist_delay;
506   uint32_t matching_bits;
507
508   switch (round_offset)
509   {
510   case -1:
511     /* previous round is randomized between 0 and 50 ms */
512 #if USE_RANDOM_DELAYS
513     ret.rel_value = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, 50);
514 #else
515     ret = GNUNET_TIME_UNIT_ZERO;
516 #endif
517 #if DEBUG_NSE
518     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
519                 "Transmitting previous round behind schedule in %llu ms\n",
520                 (unsigned long long) ret.rel_value);
521 #endif
522     return ret;
523   case 0:
524     /* current round is based on best-known matching_bits */
525     matching_bits =
526         ntohl (size_estimate_messages[estimate_index].matching_bits);
527     dist_delay = get_matching_bits_delay (matching_bits);
528     dist_delay += get_delay_randomization (matching_bits).rel_value;
529     ret.rel_value = (uint64_t) dist_delay;
530 #if DEBUG_NSE
531     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
532                 "For round %llu, delay for %u matching bits is %llu ms\n",
533                 (unsigned long long) current_timestamp.abs_value,
534                 (unsigned int) matching_bits,
535                 (unsigned long long) ret.rel_value);
536 #endif
537     /* now consider round start time and add delay to it */
538     tgt = GNUNET_TIME_absolute_add (current_timestamp, ret);
539     return GNUNET_TIME_absolute_get_remaining (tgt);
540   }
541   GNUNET_break (0);
542   return GNUNET_TIME_UNIT_FOREVER_REL;
543 }
544
545
546 /**
547  * Task that triggers a NSE P2P transmission.
548  *
549  * @param cls the 'struct NSEPeerEntry'
550  * @param tc scheduler context
551  */
552 static void
553 transmit_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
554
555
556 /**
557  * Called when core is ready to send a message we asked for
558  * out to the destination.
559  *
560  * @param cls closure (NULL)
561  * @param size number of bytes available in buf
562  * @param buf where the callee should write the message
563  * @return number of bytes written to buf
564  */
565 static size_t
566 transmit_ready (void *cls, size_t size, void *buf)
567 {
568   struct NSEPeerEntry *peer_entry = cls;
569   unsigned int idx;
570
571   peer_entry->th = NULL;
572   if (buf == NULL)
573   {
574     /* client disconnected */
575     return 0;
576   }
577   GNUNET_assert (size >= sizeof (struct GNUNET_NSE_FloodMessage));
578   idx = estimate_index;
579   if (peer_entry->previous_round == GNUNET_NO)
580   {
581     idx = (idx + HISTORY_SIZE - 1) % HISTORY_SIZE;
582     peer_entry->previous_round = GNUNET_YES;
583     peer_entry->transmit_task =
584         GNUNET_SCHEDULER_add_delayed (get_transmit_delay (0), &transmit_task_cb,
585                                       peer_entry);
586   }
587   if ((ntohl (size_estimate_messages[idx].hop_count) == 0) &&
588       (GNUNET_SCHEDULER_NO_TASK != proof_task))
589   {
590     GNUNET_STATISTICS_update (stats,
591                               "# flood messages not generated (no proof yet)",
592                               1, GNUNET_NO);
593     return 0;
594   }
595   if (ntohs (size_estimate_messages[idx].header.size) == 0)
596   {
597     GNUNET_STATISTICS_update (stats,
598                               "# flood messages not generated (lack of history)",
599                               1, GNUNET_NO);
600     return 0;
601   }
602 #if DEBUG_NSE
603   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
604               "In round %llu, sending to `%s' estimate with %u bits\n",
605               (unsigned long long)
606               GNUNET_TIME_absolute_ntoh (size_estimate_messages[idx].
607                                          timestamp).abs_value,
608               GNUNET_i2s (&peer_entry->id),
609               (unsigned int) ntohl (size_estimate_messages[idx].matching_bits));
610 #endif
611   if (ntohl (size_estimate_messages[idx].hop_count) == 0)
612     GNUNET_STATISTICS_update (stats, "# flood messages started", 1, GNUNET_NO);
613   GNUNET_STATISTICS_update (stats, "# flood messages transmitted", 1,
614                             GNUNET_NO);
615 #if ENABLE_HISTOGRAM
616   peer_entry->transmitted_messages++;
617   peer_entry->last_transmitted_size = 
618       ntohl(size_estimate_messages[idx].matching_bits);
619 #endif
620   memcpy (buf, &size_estimate_messages[idx],
621           sizeof (struct GNUNET_NSE_FloodMessage));
622   return sizeof (struct GNUNET_NSE_FloodMessage);
623 }
624
625
626 /**
627  * Task that triggers a NSE P2P transmission.
628  *
629  * @param cls the 'struct NSEPeerEntry'
630  * @param tc scheduler context
631  */
632 static void
633 transmit_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
634 {
635   struct NSEPeerEntry *peer_entry = cls;
636
637   peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
638   GNUNET_assert (NULL == peer_entry->th);
639   peer_entry->th =
640       GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_NO, NSE_PRIORITY,
641                                          GNUNET_TIME_UNIT_FOREVER_REL,
642                                          &peer_entry->id,
643                                          sizeof (struct
644                                                  GNUNET_NSE_FloodMessage),
645                                          &transmit_ready, peer_entry);
646 }
647
648
649 /**
650  * We've sent on our flood message or one that we received which was
651  * validated and closer than ours.  Update the global list of recent
652  * messages and the average.  Also re-broadcast the message to any
653  * clients.
654  */
655 static void
656 update_network_size_estimate ()
657 {
658   struct GNUNET_NSE_ClientMessage em;
659
660   setup_estimate_message (&em);
661   GNUNET_SERVER_notification_context_broadcast (nc, &em.header, GNUNET_YES);
662 }
663
664
665 /**
666  * Setup a flood message in our history array at the given
667  * slot offset for the given timestamp.
668  *
669  * @param slot index to use
670  * @param ts timestamp to use
671  */
672 static void
673 setup_flood_message (unsigned int slot, struct GNUNET_TIME_Absolute ts)
674 {
675   struct GNUNET_NSE_FloodMessage *fm;
676   uint32_t matching_bits;
677
678   matching_bits = get_matching_bits (ts, &my_identity);
679   fm = &size_estimate_messages[slot];
680   fm->header.size = htons (sizeof (struct GNUNET_NSE_FloodMessage));
681   fm->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD);
682   fm->hop_count = htonl (0);
683   fm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND);
684   fm->purpose.size =
685       htonl (sizeof (struct GNUNET_NSE_FloodMessage) -
686              sizeof (struct GNUNET_MessageHeader) - sizeof (uint32_t) -
687              sizeof (struct GNUNET_CRYPTO_RsaSignature));
688   fm->matching_bits = htonl (matching_bits);
689   fm->timestamp = GNUNET_TIME_absolute_hton (ts);
690   fm->pkey = my_public_key;
691   fm->proof_of_work = my_proof;
692   if (nse_work_required > 0)
693     GNUNET_assert (GNUNET_OK ==
694                    GNUNET_CRYPTO_rsa_sign (my_private_key, &fm->purpose,
695                                            &fm->signature));
696   else
697     memset (&fm->signature, 0, sizeof (fm->signature));
698 }
699
700
701 /**
702  * Schedule transmission for the given peer for the current round based
703  * on what we know about the desired delay.
704  *
705  * @param cls unused
706  * @param key hash of peer identity
707  * @param value the 'struct NSEPeerEntry'
708  * @return GNUNET_OK (continue to iterate)
709  */
710 static int
711 schedule_current_round (void *cls, const GNUNET_HashCode * key, void *value)
712 {
713   struct NSEPeerEntry *peer_entry = value;
714   struct GNUNET_TIME_Relative delay;
715
716   if (peer_entry->th != NULL)
717   {
718     peer_entry->previous_round = GNUNET_NO;
719     return GNUNET_OK;
720   }
721   if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
722   {
723     GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
724     peer_entry->previous_round = GNUNET_NO;
725   }
726 #if ENABLE_HISTOGRAM
727   if (peer_entry->received_messages > 1)
728     GNUNET_STATISTICS_update(stats, "# extra messages",
729                              peer_entry->received_messages - 1, GNUNET_NO);
730   peer_entry->transmitted_messages = 0;
731   peer_entry->last_transmitted_size = 0;
732   peer_entry->received_messages = 0;
733 #endif
734   delay =
735       get_transmit_delay ((peer_entry->previous_round == GNUNET_NO) ? -1 : 0);
736   peer_entry->transmit_task =
737       GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
738   return GNUNET_OK;
739 }
740
741
742 /**
743  * Update our flood message to be sent (and our timestamps).
744  *
745  * @param cls unused
746  * @param tc context for this message
747  */
748 static void
749 update_flood_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
750 {
751   struct GNUNET_TIME_Relative offset;
752   unsigned int i;
753
754   flood_task = GNUNET_SCHEDULER_NO_TASK;
755   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
756     return;
757   offset = GNUNET_TIME_absolute_get_remaining (next_timestamp);
758   if (0 != offset.rel_value)
759   {
760     /* somehow run early, delay more */
761     flood_task =
762         GNUNET_SCHEDULER_add_delayed (offset, &update_flood_message, NULL);
763     return;
764   }
765   estimate_index = (estimate_index + 1) % HISTORY_SIZE;
766   if (estimate_count < HISTORY_SIZE)
767     estimate_count++;
768   current_timestamp = next_timestamp;
769   next_timestamp =
770       GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
771   if ((current_timestamp.abs_value ==
772       GNUNET_TIME_absolute_ntoh (next_message.timestamp).abs_value) &&
773       (get_matching_bits (current_timestamp, &my_identity) <
774       ntohl(next_message.matching_bits)))
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   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 == next_timestamp.abs_value)
1065   {
1066     if (matching_bits <= ntohl (next_message.matching_bits))
1067       return GNUNET_OK;         /* ignore, simply too early/late */
1068     if (GNUNET_YES != verify_message_crypto (incoming_flood))
1069     {
1070       GNUNET_break_op (0);
1071       return GNUNET_OK;
1072     }
1073     next_message = *incoming_flood;
1074     return GNUNET_OK;
1075   }
1076   else
1077   {
1078     GNUNET_STATISTICS_update (stats,
1079                               "# flood messages discarded (clock skew too large)",
1080                               1, GNUNET_NO);
1081     return GNUNET_OK;
1082   }
1083   if (0 == (memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity))))
1084   {
1085     /* send to self, update our own estimate IF this also comes from us! */
1086     if (0 ==
1087         memcmp (&incoming_flood->pkey, &my_public_key, sizeof (my_public_key)))
1088       update_network_size_estimate ();
1089     return GNUNET_OK;
1090   }
1091   if (matching_bits == ntohl (size_estimate_messages[idx].matching_bits))
1092   {
1093     /* Cancel transmission in the other direction, as this peer clearly has
1094        up-to-date information already. Even if we didn't talk to this peer in
1095        the previous round, we should no longer send it stale information as it
1096        told us about the current round! */
1097     peer_entry->previous_round = GNUNET_YES;
1098     if (idx != estimate_index)
1099     {
1100       /* do not transmit information for the previous round to this peer 
1101          anymore (but allow current round) */
1102       return GNUNET_OK;
1103     }
1104     /* got up-to-date information for current round, cancel transmission to
1105      * this peer altogether */
1106     if (GNUNET_SCHEDULER_NO_TASK != peer_entry->transmit_task)
1107     {
1108       GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1109       peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1110     }
1111     if (peer_entry->th != NULL)
1112     {
1113       GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th);
1114       peer_entry->th = NULL;
1115     }
1116     return GNUNET_OK;
1117   }
1118   if (matching_bits < ntohl (size_estimate_messages[idx].matching_bits))
1119   {
1120     if ((idx < estimate_index) && (peer_entry->previous_round == GNUNET_YES))
1121       peer_entry->previous_round = GNUNET_NO;
1122     /* push back our result now, that peer is spreading bad information... */
1123     if (NULL == peer_entry->th)
1124     {
1125       if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1126         GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1127       peer_entry->transmit_task =
1128           GNUNET_SCHEDULER_add_now (&transmit_task_cb, peer_entry);
1129     }
1130     /* Not closer than our most recent message, no need to do work here */
1131     GNUNET_STATISTICS_update (stats,
1132                               "# flood messages ignored (had closer already)",
1133                               1, GNUNET_NO);
1134     return GNUNET_OK;
1135   }
1136   if (GNUNET_YES != verify_message_crypto (incoming_flood))
1137   {
1138     GNUNET_break_op (0);
1139     return GNUNET_OK;
1140   }
1141   GNUNET_assert (matching_bits >
1142                  ntohl (size_estimate_messages[idx].matching_bits));
1143   /* cancel transmission from us to this peer for this round */
1144   if (idx == estimate_index)
1145   {
1146       /* cancel any activity for current round */
1147       if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1148       {
1149         GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1150         peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1151       }
1152       if (peer_entry->th != NULL)
1153       {
1154         GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th);
1155         peer_entry->th = NULL;
1156       }
1157   }
1158   else
1159   {
1160     /* cancel previous round only */
1161     peer_entry->previous_round = GNUNET_YES;
1162   }
1163   size_estimate_messages[idx] = *incoming_flood;
1164   size_estimate_messages[idx].hop_count =
1165       htonl (ntohl (incoming_flood->hop_count) + 1);
1166   hop_count_max =
1167       GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1, hop_count_max);
1168   GNUNET_STATISTICS_set (stats,
1169                          "# estimated network diameter",
1170                          hop_count_max, GNUNET_NO);
1171
1172   /* have a new, better size estimate, inform clients */
1173   update_network_size_estimate ();
1174
1175   /* flood to rest */
1176   GNUNET_CONTAINER_multihashmap_iterate (peers, &update_flood_times,
1177                                          peer_entry);
1178   return GNUNET_OK;
1179 }
1180
1181
1182
1183 /**
1184  * Method called whenever a peer connects.
1185  *
1186  * @param cls closure
1187  * @param peer peer identity this notification is about
1188  * @param atsi performance data
1189  * @param atsi_count number of records in 'atsi'
1190  */
1191 static void
1192 handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
1193                      const struct GNUNET_ATS_Information *atsi,
1194                      unsigned int atsi_count)
1195 {
1196   struct NSEPeerEntry *peer_entry;
1197
1198 #if DEBUG_NSE
1199   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected to us\n",
1200               GNUNET_i2s (peer));
1201 #endif
1202   peer_entry = GNUNET_malloc (sizeof (struct NSEPeerEntry));
1203   peer_entry->id = *peer;
1204   GNUNET_assert (GNUNET_OK ==
1205                  GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey,
1206                                                     peer_entry,
1207                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1208   peer_entry->transmit_task =
1209       GNUNET_SCHEDULER_add_delayed (get_transmit_delay (-1), &transmit_task_cb,
1210                                     peer_entry);
1211   GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO);
1212 }
1213
1214
1215 /**
1216  * Method called whenever a peer disconnects.
1217  *
1218  * @param cls closure
1219  * @param peer peer identity this notification is about
1220  */
1221 static void
1222 handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
1223 {
1224   struct NSEPeerEntry *pos;
1225
1226 #if DEBUG_NSE
1227   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' disconnected from us\n",
1228               GNUNET_i2s (peer));
1229 #endif
1230   pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
1231   if (NULL == pos)
1232   {
1233     GNUNET_break (0);
1234     return;
1235   }
1236   GNUNET_assert (GNUNET_YES ==
1237                  GNUNET_CONTAINER_multihashmap_remove (peers, &peer->hashPubKey,
1238                                                        pos));
1239   if (pos->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1240     GNUNET_SCHEDULER_cancel (pos->transmit_task);
1241   if (pos->th != NULL)
1242   {
1243     GNUNET_CORE_notify_transmit_ready_cancel (pos->th);
1244     pos->th = NULL;
1245   }
1246   GNUNET_free (pos);
1247   GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO);
1248 }
1249
1250
1251 /**
1252  * Task run during shutdown.
1253  *
1254  * @param cls unused
1255  * @param tc unused
1256  */
1257 static void
1258 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1259 {
1260   if (flood_task != GNUNET_SCHEDULER_NO_TASK)
1261   {
1262     GNUNET_SCHEDULER_cancel (flood_task);
1263     flood_task = GNUNET_SCHEDULER_NO_TASK;
1264   }
1265   if (proof_task != GNUNET_SCHEDULER_NO_TASK)
1266   {
1267     GNUNET_SCHEDULER_cancel (proof_task);
1268     proof_task = GNUNET_SCHEDULER_NO_TASK;
1269     write_proof ();             /* remember progress */
1270   }
1271   if (nc != NULL)
1272   {
1273     GNUNET_SERVER_notification_context_destroy (nc);
1274     nc = NULL;
1275   }
1276   if (coreAPI != NULL)
1277   {
1278     GNUNET_CORE_disconnect (coreAPI);
1279     coreAPI = NULL;
1280   }
1281   if (stats != NULL)
1282   {
1283     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1284     stats = NULL;
1285   }
1286   if (peers != NULL)
1287   {
1288     GNUNET_CONTAINER_multihashmap_destroy (peers);
1289     peers = NULL;
1290   }
1291   if (my_private_key != NULL)
1292   {
1293     GNUNET_CRYPTO_rsa_key_free (my_private_key);
1294     my_private_key = NULL;
1295   }
1296 #if ENABLE_HISTOGRAM
1297   if (wh != NULL)
1298   {
1299     GNUNET_BIO_write_close (wh);
1300     wh = NULL;
1301   }
1302 #endif
1303 }
1304
1305
1306 /**
1307  * Called on core init/fail.
1308  *
1309  * @param cls service closure
1310  * @param server handle to the server for this service
1311  * @param identity the public identity of this peer
1312  */
1313 static void
1314 core_init (void *cls, struct GNUNET_CORE_Handle *server,
1315            const struct GNUNET_PeerIdentity *identity)
1316 {
1317   struct GNUNET_TIME_Absolute now;
1318   struct GNUNET_TIME_Absolute prev_time;
1319
1320   if (server == NULL)
1321   {
1322     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection to core FAILED!\n");
1323     GNUNET_SCHEDULER_shutdown ();
1324     return;
1325   }
1326   GNUNET_assert (0 ==
1327                  memcmp (&my_identity, identity,
1328                          sizeof (struct GNUNET_PeerIdentity)));
1329   now = GNUNET_TIME_absolute_get ();
1330   current_timestamp.abs_value =
1331       (now.abs_value / gnunet_nse_interval.rel_value) *
1332       gnunet_nse_interval.rel_value;
1333   next_timestamp =
1334       GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
1335   estimate_index = HISTORY_SIZE - 1;
1336   estimate_count = 0;
1337   if (GNUNET_YES == check_proof_of_work (&my_public_key, my_proof))
1338   {
1339     prev_time.abs_value =
1340         current_timestamp.abs_value - gnunet_nse_interval.rel_value;
1341     setup_flood_message (estimate_index, prev_time);
1342     estimate_count++;
1343   }
1344   flood_task =
1345       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
1346                                     (next_timestamp), &update_flood_message,
1347                                     NULL);
1348 }
1349
1350
1351 /**
1352  * Handle network size estimate clients.
1353  *
1354  * @param cls closure
1355  * @param server the initialized server
1356  * @param c configuration to use
1357  */
1358 static void
1359 run (void *cls, struct GNUNET_SERVER_Handle *server,
1360      const struct GNUNET_CONFIGURATION_Handle *c)
1361 {
1362   char *keyfile;
1363   char *proof;
1364
1365   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1366     {&handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START,
1367      sizeof (struct GNUNET_MessageHeader)},
1368     {NULL, NULL, 0, 0}
1369   };
1370   static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
1371     {&handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD,
1372      sizeof (struct GNUNET_NSE_FloodMessage)},
1373     {NULL, 0, 0}
1374   };
1375   cfg = c;
1376
1377   if ((GNUNET_OK !=
1378        GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "INTERVAL",
1379                                             &gnunet_nse_interval)) ||
1380       (GNUNET_OK !=
1381        GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "WORKDELAY",
1382                                             &proof_find_delay)) ||
1383       (GNUNET_OK !=
1384        GNUNET_CONFIGURATION_get_value_number (cfg, "NSE", "WORKBITS",
1385                                               &nse_work_required)))
1386   {
1387     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1388                 _
1389                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1390     GNUNET_SCHEDULER_shutdown ();
1391     return;
1392   }
1393   if (nse_work_required >= sizeof (GNUNET_HashCode) * 8)
1394   {
1395     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1396                 _("Invalid work requirement for NSE service. Exiting.\n"));
1397     GNUNET_SCHEDULER_shutdown ();
1398     return;
1399   }
1400
1401
1402   if (GNUNET_OK !=
1403       GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY",
1404                                                &keyfile))
1405   {
1406     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1407                 _
1408                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1409     GNUNET_SCHEDULER_shutdown ();
1410     return;
1411   }
1412   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1413   GNUNET_free (keyfile);
1414   if (my_private_key == NULL)
1415   {
1416     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1417                 _("NSE service could not access hostkey.  Exiting.\n"));
1418     GNUNET_SCHEDULER_shutdown ();
1419     return;
1420   }
1421   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
1422   GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
1423                       &my_identity.hashPubKey);
1424   if (GNUNET_OK !=
1425       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
1426   {
1427     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1428                 _
1429                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1430     if (my_private_key != NULL)
1431     {
1432       GNUNET_CRYPTO_rsa_key_free (my_private_key);
1433       my_private_key = NULL;
1434     }
1435     GNUNET_SCHEDULER_shutdown ();
1436     return;
1437   }
1438   if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) ||
1439       (sizeof (my_proof) !=
1440        GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof))))
1441     my_proof = 0;
1442   GNUNET_free (proof);
1443   proof_task =
1444       GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1445                                           &find_proof, NULL);
1446
1447   peers = GNUNET_CONTAINER_multihashmap_create (128);
1448   GNUNET_SERVER_add_handlers (server, handlers);
1449   nc = GNUNET_SERVER_notification_context_create (server, 1);
1450   /* Connect to core service and register core handlers */
1451   coreAPI = GNUNET_CORE_connect (cfg,   /* Main configuration */
1452                                  1, NULL,       /* Closure passed to functions */
1453                                  &core_init,    /* Call core_init once connected */
1454                                  &handle_core_connect,  /* Handle connects */
1455                                  &handle_core_disconnect,       /* Handle disconnects */
1456                                  NULL,  /* Don't want notified about all incoming messages */
1457                                  GNUNET_NO,     /* For header only inbound notification */
1458                                  NULL,  /* Don't want notified about all outbound messages */
1459                                  GNUNET_NO,     /* For header only outbound notification */
1460                                  core_handlers);        /* Register these handlers */
1461   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1462                                 NULL);
1463 #if ENABLE_HISTOGRAM
1464   if (GNUNET_OK ==
1465       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "HISTOGRAM", &proof))
1466   {
1467     wh = GNUNET_BIO_write_open (proof);
1468     GNUNET_free (proof);
1469   }
1470 #endif
1471   if (coreAPI == NULL)
1472   {
1473     GNUNET_SCHEDULER_shutdown ();
1474     return;
1475   }
1476   stats = GNUNET_STATISTICS_create ("nse", cfg);
1477 }
1478
1479
1480 /**
1481  * The main function for the statistics service.
1482  *
1483  * @param argc number of arguments from the command line
1484  * @param argv command line arguments
1485  * @return 0 ok, 1 on error
1486  */
1487 int
1488 main (int argc, char *const *argv)
1489 {
1490   return (GNUNET_OK ==
1491           GNUNET_SERVICE_run (argc, argv, "nse", GNUNET_SERVICE_OPTION_NONE,
1492                               &run, NULL)) ? 0 : 1;
1493 }
1494
1495 /* end of gnunet-service-nse.c */