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