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