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