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