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