-consistently use struct GNUNET_HashCode
[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   struct 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 struct 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 struct 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   struct 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   struct 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 struct 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 in the other direction, as this peer clearly has
1136    * up-to-date information already.
1137    */
1138   peer_entry->previous_round = GNUNET_YES;
1139   if (idx == estimate_index)
1140   {
1141       /* cancel any activity for current round */
1142       if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK)
1143       {
1144         GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1145         peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1146       }
1147       if (peer_entry->th != NULL)
1148       {
1149         GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th);
1150         peer_entry->th = NULL;
1151       }
1152   }
1153   size_estimate_messages[idx] = *incoming_flood;
1154   size_estimate_messages[idx].hop_count =
1155       htonl (ntohl (incoming_flood->hop_count) + 1);
1156   hop_count_max =
1157       GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1, hop_count_max);
1158   GNUNET_STATISTICS_set (stats,
1159                          "# estimated network diameter",
1160                          hop_count_max, GNUNET_NO);
1161
1162   /* have a new, better size estimate, inform clients */
1163   update_network_size_estimate ();
1164
1165   /* flood to rest */
1166   GNUNET_CONTAINER_multihashmap_iterate (peers, &update_flood_times,
1167                                          peer_entry);
1168   return GNUNET_OK;
1169 }
1170
1171
1172
1173 /**
1174  * Method called whenever a peer connects. Sets up the PeerEntry and
1175  * schedules the initial size info transmission to this peer.
1176  *
1177  * @param cls closure
1178  * @param peer peer identity this notification is about
1179  * @param atsi performance data
1180  * @param atsi_count number of records in 'atsi'
1181  */
1182 static void
1183 handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
1184                      const struct GNUNET_ATS_Information *atsi,
1185                      unsigned int atsi_count)
1186 {
1187   struct NSEPeerEntry *peer_entry;
1188
1189   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected to us\n",
1190               GNUNET_i2s (peer));
1191   peer_entry = GNUNET_malloc (sizeof (struct NSEPeerEntry));
1192   peer_entry->id = *peer;
1193   GNUNET_assert (GNUNET_OK ==
1194                  GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey,
1195                                                     peer_entry,
1196                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1197   peer_entry->transmit_task =
1198       GNUNET_SCHEDULER_add_delayed (get_transmit_delay (-1), &transmit_task_cb,
1199                                     peer_entry);
1200   GNUNET_STATISTICS_update (stats, "# peers connected", 1, GNUNET_NO);
1201 }
1202
1203
1204 /**
1205  * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
1206  * any pending transmission requests to that peer.
1207  *
1208  * @param cls closure
1209  * @param peer peer identity this notification is about
1210  */
1211 static void
1212 handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
1213 {
1214   struct NSEPeerEntry *pos;
1215
1216   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' disconnected from us\n",
1217               GNUNET_i2s (peer));
1218   pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
1219   if (NULL == pos)
1220   {
1221     GNUNET_break (0);
1222     return;
1223   }
1224   GNUNET_assert (GNUNET_YES ==
1225                  GNUNET_CONTAINER_multihashmap_remove (peers, &peer->hashPubKey,
1226                                                        pos));
1227   if (pos->transmit_task != GNUNET_SCHEDULER_NO_TASK) {
1228     GNUNET_SCHEDULER_cancel (pos->transmit_task);
1229     pos->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1230   }
1231   if (pos->th != NULL)
1232   {
1233     GNUNET_CORE_notify_transmit_ready_cancel (pos->th);
1234     pos->th = NULL;
1235   }
1236   GNUNET_free (pos);
1237   GNUNET_STATISTICS_update (stats, "# peers connected", -1, GNUNET_NO);
1238 }
1239
1240
1241 /**
1242  * Task run during shutdown.
1243  *
1244  * @param cls unused
1245  * @param tc unused
1246  */
1247 static void
1248 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1249 {
1250   if (flood_task != GNUNET_SCHEDULER_NO_TASK)
1251   {
1252     GNUNET_SCHEDULER_cancel (flood_task);
1253     flood_task = GNUNET_SCHEDULER_NO_TASK;
1254   }
1255   if (proof_task != GNUNET_SCHEDULER_NO_TASK)
1256   {
1257     GNUNET_SCHEDULER_cancel (proof_task);
1258     proof_task = GNUNET_SCHEDULER_NO_TASK;
1259     write_proof ();             /* remember progress */
1260   }
1261   if (nc != NULL)
1262   {
1263     GNUNET_SERVER_notification_context_destroy (nc);
1264     nc = NULL;
1265   }
1266   if (coreAPI != NULL)
1267   {
1268     GNUNET_CORE_disconnect (coreAPI);
1269     coreAPI = NULL;
1270   }
1271   if (stats != NULL)
1272   {
1273     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1274     stats = NULL;
1275   }
1276   if (peers != NULL)
1277   {
1278     GNUNET_CONTAINER_multihashmap_destroy (peers);
1279     peers = NULL;
1280   }
1281   if (my_private_key != NULL)
1282   {
1283     GNUNET_CRYPTO_rsa_key_free (my_private_key);
1284     my_private_key = NULL;
1285   }
1286 #if ENABLE_HISTOGRAM
1287   if (wh != NULL)
1288   {
1289     GNUNET_break (GNUNET_OK == GNUNET_BIO_write_close (wh));
1290     wh = NULL;
1291   }
1292 #endif
1293 }
1294
1295
1296 /**
1297  * Called on core init/fail.
1298  *
1299  * @param cls service closure
1300  * @param server handle to the server for this service
1301  * @param identity the public identity of this peer
1302  */
1303 static void
1304 core_init (void *cls, struct GNUNET_CORE_Handle *server,
1305            const struct GNUNET_PeerIdentity *identity)
1306 {
1307   struct GNUNET_TIME_Absolute now;
1308   struct GNUNET_TIME_Absolute prev_time;
1309
1310   if (NULL == server)
1311   {
1312     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection to core FAILED!\n");
1313     GNUNET_SCHEDULER_shutdown ();
1314     return;
1315   }
1316   GNUNET_assert (0 ==
1317                  memcmp (&my_identity, identity,
1318                          sizeof (struct GNUNET_PeerIdentity)));
1319   now = GNUNET_TIME_absolute_get ();
1320   current_timestamp.abs_value =
1321       (now.abs_value / gnunet_nse_interval.rel_value) *
1322       gnunet_nse_interval.rel_value;
1323   next_timestamp =
1324       GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
1325   estimate_index = HISTORY_SIZE - 1;
1326   estimate_count = 0;
1327   if (GNUNET_YES == check_proof_of_work (&my_public_key, my_proof))
1328   {
1329     int idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1330     prev_time.abs_value =
1331         current_timestamp.abs_value - gnunet_nse_interval.rel_value;
1332     setup_flood_message (idx, prev_time);
1333     setup_flood_message (estimate_index, current_timestamp);
1334     estimate_count++;
1335   }
1336   flood_task =
1337       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
1338                                     (next_timestamp), &update_flood_message,
1339                                     NULL);
1340 }
1341
1342
1343 /**
1344  * Handle network size estimate clients.
1345  *
1346  * @param cls closure
1347  * @param server the initialized server
1348  * @param c configuration to use
1349  */
1350 static void
1351 run (void *cls, struct GNUNET_SERVER_Handle *server,
1352      const struct GNUNET_CONFIGURATION_Handle *c)
1353 {
1354   char *keyfile;
1355   char *proof;
1356
1357   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1358     {&handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START,
1359      sizeof (struct GNUNET_MessageHeader)},
1360     {NULL, NULL, 0, 0}
1361   };
1362   static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
1363     {&handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD,
1364      sizeof (struct GNUNET_NSE_FloodMessage)},
1365     {NULL, 0, 0}
1366   };
1367   cfg = c;
1368
1369   if ((GNUNET_OK !=
1370        GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "INTERVAL",
1371                                             &gnunet_nse_interval)) ||
1372       (GNUNET_OK !=
1373        GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "WORKDELAY",
1374                                             &proof_find_delay)) ||
1375       (GNUNET_OK !=
1376        GNUNET_CONFIGURATION_get_value_number (cfg, "NSE", "WORKBITS",
1377                                               &nse_work_required)))
1378   {
1379     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1380                 _
1381                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1382     GNUNET_SCHEDULER_shutdown ();
1383     return;
1384   }
1385   if (nse_work_required >= sizeof (struct GNUNET_HashCode) * 8)
1386   {
1387     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1388                 _("Invalid work requirement for NSE service. Exiting.\n"));
1389     GNUNET_SCHEDULER_shutdown ();
1390     return;
1391   }
1392
1393
1394   if (GNUNET_OK !=
1395       GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY",
1396                                                &keyfile))
1397   {
1398     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1399                 _
1400                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1401     GNUNET_SCHEDULER_shutdown ();
1402     return;
1403   }
1404   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1405   GNUNET_free (keyfile);
1406   if (my_private_key == NULL)
1407   {
1408     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1409                 _("NSE service could not access hostkey.  Exiting.\n"));
1410     GNUNET_SCHEDULER_shutdown ();
1411     return;
1412   }
1413   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
1414   GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
1415                       &my_identity.hashPubKey);
1416   if (GNUNET_OK !=
1417       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
1418   {
1419     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1420                 _
1421                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1422     if (my_private_key != NULL)
1423     {
1424       GNUNET_CRYPTO_rsa_key_free (my_private_key);
1425       my_private_key = NULL;
1426     }
1427     GNUNET_SCHEDULER_shutdown ();
1428     return;
1429   }
1430   if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) ||
1431       (sizeof (my_proof) !=
1432        GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof))))
1433     my_proof = 0;
1434   GNUNET_free (proof);
1435   proof_task =
1436       GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1437                                           &find_proof, NULL);
1438
1439   peers = GNUNET_CONTAINER_multihashmap_create (128);
1440   GNUNET_SERVER_add_handlers (server, handlers);
1441   nc = GNUNET_SERVER_notification_context_create (server, 1);
1442   /* Connect to core service and register core handlers */
1443   coreAPI = GNUNET_CORE_connect (cfg,   /* Main configuration */
1444                                  NULL,       /* Closure passed to functions */
1445                                  &core_init,    /* Call core_init once connected */
1446                                  &handle_core_connect,  /* Handle connects */
1447                                  &handle_core_disconnect,       /* Handle disconnects */
1448                                  NULL,  /* Don't want notified about all incoming messages */
1449                                  GNUNET_NO,     /* For header only inbound notification */
1450                                  NULL,  /* Don't want notified about all outbound messages */
1451                                  GNUNET_NO,     /* For header only outbound notification */
1452                                  core_handlers);        /* Register these handlers */
1453   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1454                                 NULL);
1455 #if ENABLE_HISTOGRAM
1456   if (GNUNET_OK ==
1457       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "HISTOGRAM", &proof))
1458   {
1459     wh = GNUNET_BIO_write_open (proof);
1460     GNUNET_free (proof);
1461   }
1462 #endif
1463   if (coreAPI == NULL)
1464   {
1465     GNUNET_SCHEDULER_shutdown ();
1466     return;
1467   }
1468   stats = GNUNET_STATISTICS_create ("nse", cfg);
1469 }
1470
1471
1472 /**
1473  * The main function for the statistics service.
1474  *
1475  * @param argc number of arguments from the command line
1476  * @param argv command line arguments
1477  * @return 0 ok, 1 on error
1478  */
1479 int
1480 main (int argc, char *const *argv)
1481 {
1482   return (GNUNET_OK ==
1483           GNUNET_SERVICE_run (argc, argv, "nse", GNUNET_SERVICE_OPTION_NONE,
1484                               &run, NULL)) ? 0 : 1;
1485 }
1486
1487 /* end of gnunet-service-nse.c */