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