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