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