-removing 2nd argument from GNUNET_CLIENT_disconnect as it was virtually always GNUNE...
[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 #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 (NULL == buf)
573   {
574     /* client disconnected */
575     return 0;
576   }
577   GNUNET_assert (size >= sizeof (struct GNUNET_NSE_FloodMessage));
578   idx = estimate_index;
579   if (GNUNET_NO == peer_entry->previous_round)
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
639   GNUNET_assert (NULL == peer_entry->th);
640   peer_entry->th =
641       GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_NO, NSE_PRIORITY,
642                                          GNUNET_TIME_UNIT_FOREVER_REL,
643                                          &peer_entry->id,
644                                          sizeof (struct
645                                                  GNUNET_NSE_FloodMessage),
646                                          &transmit_ready, peer_entry);
647 }
648
649
650 /**
651  * We've sent on our flood message or one that we received which was
652  * validated and closer than ours.  Update the global list of recent
653  * messages and the average.  Also re-broadcast the message to any
654  * clients.
655  */
656 static void
657 update_network_size_estimate ()
658 {
659   struct GNUNET_NSE_ClientMessage em;
660
661   setup_estimate_message (&em);
662   GNUNET_SERVER_notification_context_broadcast (nc, &em.header, GNUNET_YES);
663 }
664
665
666 /**
667  * Setup a flood message in our history array at the given
668  * slot offset for the given timestamp.
669  *
670  * @param slot index to use
671  * @param ts timestamp to use
672  */
673 static void
674 setup_flood_message (unsigned int slot, struct GNUNET_TIME_Absolute ts)
675 {
676   struct GNUNET_NSE_FloodMessage *fm;
677   uint32_t matching_bits;
678
679   matching_bits = get_matching_bits (ts, &my_identity);
680   fm = &size_estimate_messages[slot];
681   fm->header.size = htons (sizeof (struct GNUNET_NSE_FloodMessage));
682   fm->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD);
683   fm->hop_count = htonl (0);
684   fm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND);
685   fm->purpose.size =
686       htonl (sizeof (struct GNUNET_NSE_FloodMessage) -
687              sizeof (struct GNUNET_MessageHeader) - sizeof (uint32_t) -
688              sizeof (struct GNUNET_CRYPTO_RsaSignature));
689   fm->matching_bits = htonl (matching_bits);
690   fm->timestamp = GNUNET_TIME_absolute_hton (ts);
691   fm->pkey = my_public_key;
692   fm->proof_of_work = my_proof;
693   if (nse_work_required > 0)
694     GNUNET_assert (GNUNET_OK ==
695                    GNUNET_CRYPTO_rsa_sign (my_private_key, &fm->purpose,
696                                            &fm->signature));
697   else
698     memset (&fm->signature, 0, sizeof (fm->signature));
699 }
700
701
702 /**
703  * Schedule transmission for the given peer for the current round based
704  * on what we know about the desired delay.
705  *
706  * @param cls unused
707  * @param key hash of peer identity
708  * @param value the 'struct NSEPeerEntry'
709  * @return GNUNET_OK (continue to iterate)
710  */
711 static int
712 schedule_current_round (void *cls, const GNUNET_HashCode * key, void *value)
713 {
714   struct NSEPeerEntry *peer_entry = value;
715   struct GNUNET_TIME_Relative delay;
716
717   if (NULL != peer_entry->th)
718   {
719     peer_entry->previous_round = GNUNET_NO;
720     return GNUNET_OK;
721   }
722   if (GNUNET_SCHEDULER_NO_TASK != peer_entry->transmit_task)
723   {
724     GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
725     peer_entry->previous_round = GNUNET_NO;
726   }
727 #if ENABLE_HISTOGRAM
728   if (peer_entry->received_messages > 1)
729     GNUNET_STATISTICS_update(stats, "# extra messages",
730                              peer_entry->received_messages - 1, GNUNET_NO);
731   peer_entry->transmitted_messages = 0;
732   peer_entry->last_transmitted_size = 0;
733   peer_entry->received_messages = 0;
734 #endif
735   delay =
736       get_transmit_delay ((peer_entry->previous_round == GNUNET_NO) ? -1 : 0);
737   peer_entry->transmit_task =
738       GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
739   return GNUNET_OK;
740 }
741
742
743 /**
744  * Update our flood message to be sent (and our timestamps).
745  *
746  * @param cls unused
747  * @param tc context for this message
748  */
749 static void
750 update_flood_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
751 {
752   struct GNUNET_TIME_Relative offset;
753   unsigned int i;
754
755   flood_task = GNUNET_SCHEDULER_NO_TASK;
756   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
757     return;
758   offset = GNUNET_TIME_absolute_get_remaining (next_timestamp);
759   if (0 != offset.rel_value)
760   {
761     /* somehow run early, delay more */
762     flood_task =
763         GNUNET_SCHEDULER_add_delayed (offset, &update_flood_message, NULL);
764     return;
765   }
766   estimate_index = (estimate_index + 1) % HISTORY_SIZE;
767   if (estimate_count < HISTORY_SIZE)
768     estimate_count++;
769   current_timestamp = next_timestamp;
770   next_timestamp =
771       GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
772   if ((current_timestamp.abs_value ==
773       GNUNET_TIME_absolute_ntoh (next_message.timestamp).abs_value) &&
774       (get_matching_bits (current_timestamp, &my_identity) <
775       ntohl(next_message.matching_bits)))
776   {
777     /* we received a message for this round way early, use it! */
778     size_estimate_messages[estimate_index] = next_message;
779     size_estimate_messages[estimate_index].hop_count =
780         htonl (1 + ntohl (next_message.hop_count));
781   }
782   else
783     setup_flood_message (estimate_index, current_timestamp);
784   next_message.matching_bits = htonl (0);       /* reset for 'next' round */
785   hop_count_max = 0;
786   for (i = 0; i < HISTORY_SIZE; i++)
787     hop_count_max =
788         GNUNET_MAX (ntohl (size_estimate_messages[i].hop_count), hop_count_max);
789   GNUNET_CONTAINER_multihashmap_iterate (peers, &schedule_current_round, NULL);
790   flood_task =
791       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
792                                     (next_timestamp), &update_flood_message,
793                                     NULL);
794 }
795
796
797 /**
798  * Count the leading zeroes in hash.
799  *
800  * @param hash
801  * @return the number of leading zero bits.
802  */
803 static unsigned int
804 count_leading_zeroes (const GNUNET_HashCode * hash)
805 {
806   unsigned int hash_count;
807
808   hash_count = 0;
809   while ((0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count)))
810     hash_count++;
811   return hash_count;
812 }
813
814
815 /**
816  * Check whether the given public key
817  * and integer are a valid proof of work.
818  *
819  * @param pkey the public key
820  * @param val the integer
821  *
822  * @return GNUNET_YES if valid, GNUNET_NO if not
823  */
824 static int
825 check_proof_of_work (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey,
826                      uint64_t val)
827 {
828   char buf[sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
829            sizeof (val)];
830   GNUNET_HashCode result;
831
832   memcpy (buf, &val, sizeof (val));
833   memcpy (&buf[sizeof (val)], pkey,
834           sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
835   GNUNET_CRYPTO_hash (buf, sizeof (buf), &result);
836   return (count_leading_zeroes (&result) >=
837           nse_work_required) ? GNUNET_YES : GNUNET_NO;
838 }
839
840
841 /**
842  * Write our current proof to disk.
843  */
844 static void
845 write_proof ()
846 {
847   char *proof;
848
849   if (GNUNET_OK !=
850       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
851     return;
852   if (sizeof (my_proof) !=
853       GNUNET_DISK_fn_write (proof, &my_proof, sizeof (my_proof),
854                             GNUNET_DISK_PERM_USER_READ |
855                             GNUNET_DISK_PERM_USER_WRITE))
856     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", proof);
857   GNUNET_free (proof);
858
859 }
860
861
862 /**
863  * Find our proof of work.
864  *
865  * @param cls closure (unused)
866  * @param tc task context
867  */
868 static void
869 find_proof (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
870 {
871 #define ROUND_SIZE 10
872   uint64_t counter;
873   char buf[sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
874            sizeof (uint64_t)];
875   GNUNET_HashCode result;
876   unsigned int i;
877
878   proof_task = GNUNET_SCHEDULER_NO_TASK;
879   memcpy (&buf[sizeof (uint64_t)], &my_public_key,
880           sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
881   i = 0;
882   counter = my_proof;
883   while ((counter != UINT64_MAX) && (i < ROUND_SIZE))
884   {
885     memcpy (buf, &counter, sizeof (uint64_t));
886     GNUNET_CRYPTO_hash (buf, sizeof (buf), &result);
887     if (nse_work_required <= count_leading_zeroes (&result))
888     {
889       my_proof = counter;
890 #if DEBUG_NSE
891       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Proof of work found: %llu!\n",
892                   (unsigned long long) GNUNET_ntohll (counter));
893 #endif
894       write_proof ();
895       setup_flood_message (estimate_index, current_timestamp);
896       return;
897     }
898     counter++;
899     i++;
900   }
901   if (my_proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE))
902   {
903 #if DEBUG_NSE
904     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing proofs currently at %llu\n",
905                 (unsigned long long) counter);
906 #endif
907     /* remember progress every 100 rounds */
908     my_proof = counter;
909     write_proof ();
910   }
911   else
912   {
913     my_proof = counter;
914   }
915   proof_task =
916       GNUNET_SCHEDULER_add_delayed_with_priority (proof_find_delay,
917                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
918                                                   &find_proof, NULL);
919 }
920
921
922 /**
923  * An incoming flood message has been received which claims
924  * to have more bits matching than any we know in this time
925  * period.  Verify the signature and/or proof of work.
926  *
927  * @param incoming_flood the message to verify
928  *
929  * @return GNUNET_YES if the message is verified
930  *         GNUNET_NO if the key/signature don't verify
931  */
932 static int
933 verify_message_crypto (const struct GNUNET_NSE_FloodMessage *incoming_flood)
934 {
935   if (GNUNET_YES !=
936       check_proof_of_work (&incoming_flood->pkey,
937                            incoming_flood->proof_of_work))
938   {
939     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Proof of work invalid: %llu!\n"),
940                 (unsigned long long)
941                 GNUNET_ntohll (incoming_flood->proof_of_work));
942     GNUNET_break_op (0);
943     return GNUNET_NO;
944   }
945   if ((nse_work_required > 0) &&
946       (GNUNET_OK !=
947        GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND,
948                                  &incoming_flood->purpose,
949                                  &incoming_flood->signature,
950                                  &incoming_flood->pkey)))
951   {
952     GNUNET_break_op (0);
953     return GNUNET_NO;
954   }
955   return GNUNET_YES;
956 }
957
958
959 /**
960  * Update transmissions for the given peer for the current round based
961  * on updated proximity information.
962  *
963  * @param cls peer entry to exclude from updates
964  * @param key hash of peer identity
965  * @param value the 'struct NSEPeerEntry'
966  * @return GNUNET_OK (continue to iterate)
967  */
968 static int
969 update_flood_times (void *cls, const GNUNET_HashCode * key, void *value)
970 {
971   struct NSEPeerEntry *exclude = cls;
972   struct NSEPeerEntry *peer_entry = value;
973   struct GNUNET_TIME_Relative delay;
974
975   if (peer_entry->th != NULL)
976     return GNUNET_OK;           /* already active */
977   if (peer_entry == exclude)
978     return GNUNET_OK;           /* trigger of the update */
979   if (peer_entry->previous_round == GNUNET_NO)
980   {
981     /* still stuck in previous round, no point to update, check that
982      * we are active here though... */
983     if (GNUNET_SCHEDULER_NO_TASK == peer_entry->transmit_task &&
984                   NULL == peer_entry->th)
985     {
986         GNUNET_break (0);
987     }
988     return GNUNET_OK;
989   }
990   if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
991   {
992     GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
993     peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
994   }
995   delay = get_transmit_delay (0);
996   peer_entry->transmit_task =
997       GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
998   return GNUNET_OK;
999 }
1000
1001
1002 /**
1003  * Core handler for size estimate flooding messages.
1004  *
1005  * @param cls closure unused
1006  * @param message message
1007  * @param peer peer identity this message is from (ignored)
1008  * @param atsi performance data (ignored)
1009  * @param atsi_count number of records in 'atsi'
1010  */
1011 static int
1012 handle_p2p_size_estimate (void *cls, const struct GNUNET_PeerIdentity *peer,
1013                           const struct GNUNET_MessageHeader *message,
1014                           const struct GNUNET_ATS_Information *atsi,
1015                           unsigned int atsi_count)
1016 {
1017   const struct GNUNET_NSE_FloodMessage *incoming_flood;
1018   struct GNUNET_TIME_Absolute ts;
1019   struct NSEPeerEntry *peer_entry;
1020   uint32_t matching_bits;
1021   unsigned int idx;
1022
1023 #if ENABLE_HISTOGRAM
1024   if (NULL != wh)
1025     GNUNET_BIO_write_int64 (wh, GNUNET_TIME_absolute_get ().abs_value);
1026 #endif
1027   incoming_flood = (const struct GNUNET_NSE_FloodMessage *) message;
1028   GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO);
1029   matching_bits = ntohl (incoming_flood->matching_bits);
1030 #if DEBUG_NSE
1031   {
1032     char origin[5];
1033     char pred[5];
1034     struct GNUNET_PeerIdentity os;
1035
1036     GNUNET_CRYPTO_hash (&incoming_flood->pkey,
1037                         sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1038                         &os.hashPubKey);
1039     GNUNET_snprintf (origin, sizeof (origin), "%s", GNUNET_i2s (&os));
1040     GNUNET_snprintf (pred, sizeof (pred), "%s", GNUNET_i2s (peer));
1041     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1042                 "Flood at %llu from `%s' via `%s' at `%s' with bits %u\n",
1043                 (unsigned long long)
1044                 GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value,
1045                 origin, pred, GNUNET_i2s (&my_identity),
1046                 (unsigned int) matching_bits);
1047   }
1048 #endif
1049
1050   peer_entry = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
1051   if (NULL == peer_entry)
1052   {
1053     GNUNET_break (0);
1054     return GNUNET_OK;
1055   }
1056 #if ENABLE_HISTOGRAM
1057   peer_entry->received_messages++;
1058   if (peer_entry->transmitted_messages > 0 && 
1059       peer_entry->last_transmitted_size >= matching_bits)
1060     GNUNET_STATISTICS_update(stats, "# cross messages", 1, GNUNET_NO);
1061 #endif
1062
1063   ts = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp);
1064   if (ts.abs_value == current_timestamp.abs_value)
1065     idx = estimate_index;
1066   else if (ts.abs_value ==
1067            current_timestamp.abs_value - gnunet_nse_interval.rel_value)
1068     idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1069   else if (ts.abs_value == next_timestamp.abs_value)
1070   {
1071     if (matching_bits <= ntohl (next_message.matching_bits))
1072       return GNUNET_OK;         /* ignore, simply too early/late */
1073     if (GNUNET_YES != verify_message_crypto (incoming_flood))
1074     {
1075       GNUNET_break_op (0);
1076       return GNUNET_OK;
1077     }
1078     next_message = *incoming_flood;
1079     return GNUNET_OK;
1080   }
1081   else
1082   {
1083     GNUNET_STATISTICS_update (stats,
1084                               "# flood messages discarded (clock skew too large)",
1085                               1, GNUNET_NO);
1086     return GNUNET_OK;
1087   }
1088   if (0 == (memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity))))
1089   {
1090     /* send to self, update our own estimate IF this also comes from us! */
1091     if (0 ==
1092         memcmp (&incoming_flood->pkey, &my_public_key, sizeof (my_public_key)))
1093       update_network_size_estimate ();
1094     return GNUNET_OK;
1095   }
1096   if (matching_bits == ntohl (size_estimate_messages[idx].matching_bits))
1097   {
1098     /* Cancel transmission in the other direction, as this peer clearly has
1099        up-to-date information already. Even if we didn't talk to this peer in
1100        the previous round, we should no longer send it stale information as it
1101        told us about the current round! */
1102     peer_entry->previous_round = GNUNET_YES;
1103     if (idx != estimate_index)
1104     {
1105       /* do not transmit information for the previous round to this peer 
1106          anymore (but allow current round) */
1107       return GNUNET_OK;
1108     }
1109     /* got up-to-date information for current round, cancel transmission to
1110      * this peer altogether */
1111     if (GNUNET_SCHEDULER_NO_TASK != peer_entry->transmit_task)
1112     {
1113       GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1114       peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1115     }
1116     if (peer_entry->th != NULL)
1117     {
1118       GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th);
1119       peer_entry->th = NULL;
1120     }
1121     return GNUNET_OK;
1122   }
1123   if (matching_bits < ntohl (size_estimate_messages[idx].matching_bits))
1124   {
1125     if ((idx < estimate_index) && (peer_entry->previous_round == GNUNET_YES)) {
1126       peer_entry->previous_round = GNUNET_NO;
1127     }
1128     /* push back our result now, that peer is spreading bad information... */
1129     if (NULL == peer_entry->th)
1130     {
1131       if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1132         GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1133       peer_entry->transmit_task =
1134           GNUNET_SCHEDULER_add_now (&transmit_task_cb, peer_entry);
1135     }
1136     /* Not closer than our most recent message, no need to do work here */
1137     GNUNET_STATISTICS_update (stats,
1138                               "# flood messages ignored (had closer already)",
1139                               1, GNUNET_NO);
1140     return GNUNET_OK;
1141   }
1142   if (GNUNET_YES != verify_message_crypto (incoming_flood))
1143   {
1144     GNUNET_break_op (0);
1145     return GNUNET_OK;
1146   }
1147   GNUNET_assert (matching_bits >
1148                  ntohl (size_estimate_messages[idx].matching_bits));
1149   /* cancel transmission from us to this peer for this round */
1150   if (idx == estimate_index)
1151   {
1152       /* Cancel transmission in the other direction, as this peer clearly has
1153        up-to-date information already. Even if we didn't talk to this peer in
1154        the previous round, we should no longer send it stale information as it
1155        told us about the current round! */
1156       peer_entry->previous_round = GNUNET_YES;
1157       /* cancel any activity for current round */
1158       if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1159       {
1160         GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1161         peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1162       }
1163       if (peer_entry->th != NULL)
1164       {
1165         GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th);
1166         peer_entry->th = NULL;
1167       }
1168   }
1169   else
1170   {
1171     /* cancel previous round only */
1172     peer_entry->previous_round = GNUNET_YES;
1173   }
1174   size_estimate_messages[idx] = *incoming_flood;
1175   size_estimate_messages[idx].hop_count =
1176       htonl (ntohl (incoming_flood->hop_count) + 1);
1177   hop_count_max =
1178       GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1, hop_count_max);
1179   GNUNET_STATISTICS_set (stats,
1180                          "# estimated network diameter",
1181                          hop_count_max, GNUNET_NO);
1182
1183   /* have a new, better size estimate, inform clients */
1184   update_network_size_estimate ();
1185
1186   /* flood to rest */
1187   GNUNET_CONTAINER_multihashmap_iterate (peers, &update_flood_times,
1188                                          peer_entry);
1189   return GNUNET_OK;
1190 }
1191
1192
1193
1194 /**
1195  * Method called whenever a peer connects. Sets up the PeerEntry and
1196  * schedules the initial size info transmission to this peer.
1197  *
1198  * @param cls closure
1199  * @param peer peer identity this notification is about
1200  * @param atsi performance data
1201  * @param atsi_count number of records in 'atsi'
1202  */
1203 static void
1204 handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
1205                      const struct GNUNET_ATS_Information *atsi,
1206                      unsigned int atsi_count)
1207 {
1208   struct NSEPeerEntry *peer_entry;
1209
1210 #if DEBUG_NSE
1211   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected to us\n",
1212               GNUNET_i2s (peer));
1213 #endif
1214   peer_entry = GNUNET_malloc (sizeof (struct NSEPeerEntry));
1215   peer_entry->id = *peer;
1216   GNUNET_assert (GNUNET_OK ==
1217                  GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey,
1218                                                     peer_entry,
1219                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1220   peer_entry->transmit_task =
1221       GNUNET_SCHEDULER_add_delayed (get_transmit_delay (-1), &transmit_task_cb,
1222                                     peer_entry);
1223   GNUNET_STATISTICS_update (stats, "# peers", 1, GNUNET_NO);
1224 }
1225
1226
1227 /**
1228  * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
1229  * any pending transmission requests to that peer.
1230  *
1231  * @param cls closure
1232  * @param peer peer identity this notification is about
1233  */
1234 static void
1235 handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
1236 {
1237   struct NSEPeerEntry *pos;
1238
1239 #if DEBUG_NSE
1240   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' disconnected from us\n",
1241               GNUNET_i2s (peer));
1242 #endif
1243   pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
1244   if (NULL == pos)
1245   {
1246     GNUNET_break (0);
1247     return;
1248   }
1249   GNUNET_assert (GNUNET_YES ==
1250                  GNUNET_CONTAINER_multihashmap_remove (peers, &peer->hashPubKey,
1251                                                        pos));
1252   if (pos->transmit_task != GNUNET_SCHEDULER_NO_TASK) {
1253     GNUNET_SCHEDULER_cancel (pos->transmit_task);
1254     pos->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1255   }
1256   if (pos->th != NULL)
1257   {
1258     GNUNET_CORE_notify_transmit_ready_cancel (pos->th);
1259     pos->th = NULL;
1260   }
1261   GNUNET_free (pos);
1262   GNUNET_STATISTICS_update (stats, "# peers", -1, GNUNET_NO);
1263 }
1264
1265
1266 /**
1267  * Task run during shutdown.
1268  *
1269  * @param cls unused
1270  * @param tc unused
1271  */
1272 static void
1273 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1274 {
1275   if (flood_task != GNUNET_SCHEDULER_NO_TASK)
1276   {
1277     GNUNET_SCHEDULER_cancel (flood_task);
1278     flood_task = GNUNET_SCHEDULER_NO_TASK;
1279   }
1280   if (proof_task != GNUNET_SCHEDULER_NO_TASK)
1281   {
1282     GNUNET_SCHEDULER_cancel (proof_task);
1283     proof_task = GNUNET_SCHEDULER_NO_TASK;
1284     write_proof ();             /* remember progress */
1285   }
1286   if (nc != NULL)
1287   {
1288     GNUNET_SERVER_notification_context_destroy (nc);
1289     nc = NULL;
1290   }
1291   if (coreAPI != NULL)
1292   {
1293     GNUNET_CORE_disconnect (coreAPI);
1294     coreAPI = NULL;
1295   }
1296   if (stats != NULL)
1297   {
1298     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1299     stats = NULL;
1300   }
1301   if (peers != NULL)
1302   {
1303     GNUNET_CONTAINER_multihashmap_destroy (peers);
1304     peers = NULL;
1305   }
1306   if (my_private_key != NULL)
1307   {
1308     GNUNET_CRYPTO_rsa_key_free (my_private_key);
1309     my_private_key = NULL;
1310   }
1311 #if ENABLE_HISTOGRAM
1312   if (wh != NULL)
1313   {
1314     GNUNET_BIO_write_close (wh);
1315     wh = NULL;
1316   }
1317 #endif
1318 }
1319
1320
1321 /**
1322  * Called on core init/fail.
1323  *
1324  * @param cls service closure
1325  * @param server handle to the server for this service
1326  * @param identity the public identity of this peer
1327  */
1328 static void
1329 core_init (void *cls, struct GNUNET_CORE_Handle *server,
1330            const struct GNUNET_PeerIdentity *identity)
1331 {
1332   struct GNUNET_TIME_Absolute now;
1333   struct GNUNET_TIME_Absolute prev_time;
1334
1335   if (NULL == server)
1336   {
1337     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection to core FAILED!\n");
1338     GNUNET_SCHEDULER_shutdown ();
1339     return;
1340   }
1341   GNUNET_assert (0 ==
1342                  memcmp (&my_identity, identity,
1343                          sizeof (struct GNUNET_PeerIdentity)));
1344   now = GNUNET_TIME_absolute_get ();
1345   current_timestamp.abs_value =
1346       (now.abs_value / gnunet_nse_interval.rel_value) *
1347       gnunet_nse_interval.rel_value;
1348   next_timestamp =
1349       GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
1350   estimate_index = HISTORY_SIZE - 1;
1351   estimate_count = 0;
1352   if (GNUNET_YES == check_proof_of_work (&my_public_key, my_proof))
1353   {
1354     int idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1355     prev_time.abs_value =
1356         current_timestamp.abs_value - gnunet_nse_interval.rel_value;
1357     setup_flood_message (idx, prev_time);
1358     setup_flood_message (estimate_index, current_timestamp);
1359     estimate_count++;
1360   }
1361   flood_task =
1362       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
1363                                     (next_timestamp), &update_flood_message,
1364                                     NULL);
1365 }
1366
1367
1368 /**
1369  * Handle network size estimate clients.
1370  *
1371  * @param cls closure
1372  * @param server the initialized server
1373  * @param c configuration to use
1374  */
1375 static void
1376 run (void *cls, struct GNUNET_SERVER_Handle *server,
1377      const struct GNUNET_CONFIGURATION_Handle *c)
1378 {
1379   char *keyfile;
1380   char *proof;
1381
1382   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1383     {&handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START,
1384      sizeof (struct GNUNET_MessageHeader)},
1385     {NULL, NULL, 0, 0}
1386   };
1387   static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
1388     {&handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD,
1389      sizeof (struct GNUNET_NSE_FloodMessage)},
1390     {NULL, 0, 0}
1391   };
1392   cfg = c;
1393
1394   if ((GNUNET_OK !=
1395        GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "INTERVAL",
1396                                             &gnunet_nse_interval)) ||
1397       (GNUNET_OK !=
1398        GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "WORKDELAY",
1399                                             &proof_find_delay)) ||
1400       (GNUNET_OK !=
1401        GNUNET_CONFIGURATION_get_value_number (cfg, "NSE", "WORKBITS",
1402                                               &nse_work_required)))
1403   {
1404     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1405                 _
1406                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1407     GNUNET_SCHEDULER_shutdown ();
1408     return;
1409   }
1410   if (nse_work_required >= sizeof (GNUNET_HashCode) * 8)
1411   {
1412     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1413                 _("Invalid work requirement for NSE service. Exiting.\n"));
1414     GNUNET_SCHEDULER_shutdown ();
1415     return;
1416   }
1417
1418
1419   if (GNUNET_OK !=
1420       GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY",
1421                                                &keyfile))
1422   {
1423     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1424                 _
1425                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1426     GNUNET_SCHEDULER_shutdown ();
1427     return;
1428   }
1429   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1430   GNUNET_free (keyfile);
1431   if (my_private_key == NULL)
1432   {
1433     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1434                 _("NSE service could not access hostkey.  Exiting.\n"));
1435     GNUNET_SCHEDULER_shutdown ();
1436     return;
1437   }
1438   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
1439   GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
1440                       &my_identity.hashPubKey);
1441   if (GNUNET_OK !=
1442       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
1443   {
1444     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1445                 _
1446                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1447     if (my_private_key != NULL)
1448     {
1449       GNUNET_CRYPTO_rsa_key_free (my_private_key);
1450       my_private_key = NULL;
1451     }
1452     GNUNET_SCHEDULER_shutdown ();
1453     return;
1454   }
1455   if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) ||
1456       (sizeof (my_proof) !=
1457        GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof))))
1458     my_proof = 0;
1459   GNUNET_free (proof);
1460   proof_task =
1461       GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1462                                           &find_proof, NULL);
1463
1464   peers = GNUNET_CONTAINER_multihashmap_create (128);
1465   GNUNET_SERVER_add_handlers (server, handlers);
1466   nc = GNUNET_SERVER_notification_context_create (server, 1);
1467   /* Connect to core service and register core handlers */
1468   coreAPI = GNUNET_CORE_connect (cfg,   /* Main configuration */
1469                                  1, NULL,       /* Closure passed to functions */
1470                                  &core_init,    /* Call core_init once connected */
1471                                  &handle_core_connect,  /* Handle connects */
1472                                  &handle_core_disconnect,       /* Handle disconnects */
1473                                  NULL,  /* Don't want notified about all incoming messages */
1474                                  GNUNET_NO,     /* For header only inbound notification */
1475                                  NULL,  /* Don't want notified about all outbound messages */
1476                                  GNUNET_NO,     /* For header only outbound notification */
1477                                  core_handlers);        /* Register these handlers */
1478   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1479                                 NULL);
1480 #if ENABLE_HISTOGRAM
1481   if (GNUNET_OK ==
1482       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "HISTOGRAM", &proof))
1483   {
1484     wh = GNUNET_BIO_write_open (proof);
1485     GNUNET_free (proof);
1486   }
1487 #endif
1488   if (coreAPI == NULL)
1489   {
1490     GNUNET_SCHEDULER_shutdown ();
1491     return;
1492   }
1493   stats = GNUNET_STATISTICS_create ("nse", cfg);
1494 }
1495
1496
1497 /**
1498  * The main function for the statistics service.
1499  *
1500  * @param argc number of arguments from the command line
1501  * @param argv command line arguments
1502  * @return 0 ok, 1 on error
1503  */
1504 int
1505 main (int argc, char *const *argv)
1506 {
1507   return (GNUNET_OK ==
1508           GNUNET_SERVICE_run (argc, argv, "nse", GNUNET_SERVICE_OPTION_NONE,
1509                               &run, NULL)) ? 0 : 1;
1510 }
1511
1512 /* end of gnunet-service-nse.c */