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