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