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