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