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