removing deprecated argument in 'init' callback of GNUNET_CORE_connect
[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  * Generate extensive debug-level log messages?
63  */
64 #define DEBUG_NSE GNUNET_NO
65
66 /**
67  * Over how many values do we calculate the weighted average?
68  */
69 #define HISTORY_SIZE 64
70
71 /**
72  * Message priority to use.
73  */
74 #define NSE_PRIORITY 5
75
76 #if FREEBSD
77 #define log2(a) (log(a)/log(2))
78 #endif
79
80 /**
81  * Amount of work required (W-bit collisions) for NSE proofs, in collision-bits.
82  */
83 static unsigned long long nse_work_required;
84
85 /**
86  * Interval for sending network size estimation flood requests.
87  */
88 static struct GNUNET_TIME_Relative gnunet_nse_interval;
89
90 /**
91  * Interval between proof find runs.
92  */
93 static struct GNUNET_TIME_Relative proof_find_delay;
94
95 #if ENABLE_NSE_HISTOGRAM
96 /**
97  * Handle for writing when we received messages to disk.
98  */
99 static struct GNUNET_TESTBED_LOGGER_Handle *lh;
100 #endif
101
102
103 /**
104  * Per-peer information.
105  */
106 struct NSEPeerEntry
107 {
108
109   /**
110    * Core handle for sending messages to this peer.
111    */
112   struct GNUNET_CORE_TransmitHandle *th;
113
114   /**
115    * What is the identity of the peer?
116    */
117   struct GNUNET_PeerIdentity id;
118
119   /**
120    * Task scheduled to send message to this peer.
121    */
122   GNUNET_SCHEDULER_TaskIdentifier transmit_task;
123
124   /**
125    * Did we receive or send a message about the previous round
126    * to this peer yet?   GNUNET_YES if the previous round has
127    * been taken care of.
128    */
129   int previous_round;
130
131 #if ENABLE_NSE_HISTOGRAM
132
133   /**
134    * Amount of messages received from this peer on this round.
135    */
136   unsigned int received_messages;
137
138   /**
139    * Amount of messages transmitted to this peer on this round.
140    */
141   unsigned int transmitted_messages;
142
143   /**
144    * Which size did we tell the peer the network is?
145    */
146   unsigned int last_transmitted_size;
147
148 #endif
149
150 };
151
152
153 GNUNET_NETWORK_STRUCT_BEGIN
154
155 /**
156  * Network size estimate reply; sent when "this"
157  * peer's timer has run out before receiving a
158  * valid reply from another peer.
159  */
160 struct GNUNET_NSE_FloodMessage
161 {
162   /**
163    * Type: GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD
164    */
165   struct GNUNET_MessageHeader header;
166
167   /**
168    * Number of hops this message has taken so far.
169    */
170   uint32_t hop_count GNUNET_PACKED;
171
172   /**
173    * Purpose.
174    */
175   struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
176
177   /**
178    * The current timestamp value (which all
179    * peers should agree on).
180    */
181   struct GNUNET_TIME_AbsoluteNBO timestamp;
182
183   /**
184    * Number of matching bits between the hash
185    * of timestamp and the initiator's public
186    * key.
187    */
188   uint32_t matching_bits GNUNET_PACKED;
189
190   /**
191    * Public key of the originator.
192    */
193   struct GNUNET_CRYPTO_EccPublicKey pkey;
194
195   /**
196    * Proof of work, causing leading zeros when hashed with pkey.
197    */
198   uint64_t proof_of_work GNUNET_PACKED;
199
200   /**
201    * Signature (over range specified in purpose).
202    */
203   struct GNUNET_CRYPTO_EccSignature signature;
204 };
205 GNUNET_NETWORK_STRUCT_END
206
207 /**
208  * Handle to our current configuration.
209  */
210 static const struct GNUNET_CONFIGURATION_Handle *cfg;
211
212 /**
213  * Handle to the statistics service.
214  */
215 static struct GNUNET_STATISTICS_Handle *stats;
216
217 /**
218  * Handle to the core service.
219  */
220 static struct GNUNET_CORE_Handle *coreAPI;
221
222 /**
223  * Map of all connected peers.
224  */
225 static struct GNUNET_CONTAINER_MultiHashMap *peers;
226
227 /**
228  * The current network size estimate.  Number of bits matching on
229  * average thus far.
230  */
231 static double current_size_estimate;
232
233 /**
234  * The standard deviation of the last HISTORY_SIZE network
235  * size estimates.
236  */
237 static double current_std_dev = NAN;
238
239 /**
240  * Current hop counter estimate (estimate for network diameter).
241  */
242 static uint32_t hop_count_max;
243
244 /**
245  * Message for the next round, if we got any.
246  */
247 static struct GNUNET_NSE_FloodMessage next_message;
248
249 /**
250  * Array of recent size estimate messages.
251  */
252 static struct GNUNET_NSE_FloodMessage size_estimate_messages[HISTORY_SIZE];
253
254 /**
255  * Index of most recent estimate.
256  */
257 static unsigned int estimate_index;
258
259 /**
260  * Number of valid entries in the history.
261  */
262 static unsigned int estimate_count;
263
264 /**
265  * Task scheduled to update our flood message for the next round.
266  */
267 static GNUNET_SCHEDULER_TaskIdentifier flood_task;
268
269 /**
270  * Task scheduled to compute our proof.
271  */
272 static GNUNET_SCHEDULER_TaskIdentifier proof_task;
273
274 /**
275  * Notification context, simplifies client broadcasts.
276  */
277 static struct GNUNET_SERVER_NotificationContext *nc;
278
279 /**
280  * The next major time.
281  */
282 static struct GNUNET_TIME_Absolute next_timestamp;
283
284 /**
285  * The current major time.
286  */
287 static struct GNUNET_TIME_Absolute current_timestamp;
288
289 /**
290  * The public key of this peer.
291  */
292 static struct GNUNET_CRYPTO_EccPublicKey my_public_key;
293
294 /**
295  * The private key of this peer.
296  */
297 static struct GNUNET_CRYPTO_EccPrivateKey *my_private_key;
298
299 /**
300  * The peer identity of this peer.
301  */
302 static struct GNUNET_PeerIdentity my_identity;
303
304 /**
305  * Proof of work for this peer.
306  */
307 static uint64_t my_proof;
308
309 /**
310  * Handle to this serivce's server.
311  */
312 static struct GNUNET_SERVER_Handle *srv;
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_us / (double) 2.0) -
444       ((gnunet_nse_interval.rel_value_us / 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   ret.rel_value_us = i;
466   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
467               "Randomizing flood using latencies up to %s\n",
468               GNUNET_STRINGS_relative_time_to_string (ret,
469                                                       GNUNET_YES));
470   ret.rel_value_us = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, i + 1);
471   return ret;
472 #else
473   return GNUNET_TIME_UNIT_ZERO;
474 #endif
475 }
476
477
478 /**
479  * Calculate the 'proof-of-work' hash (an expensive hash).
480  *
481  * @param buf data to hash
482  * @param buf_len number of bytes in 'buf'
483  * @param result where to write the resulting hash
484  */
485 static void
486 pow_hash (const void *buf,
487           size_t buf_len,
488           struct GNUNET_HashCode *result)
489 {
490   GNUNET_break (0 == 
491                 gcry_kdf_derive (buf, buf_len,
492                                  GCRY_KDF_SCRYPT,
493                                  1 /* subalgo */,
494                                  "gnunet-proof-of-work", strlen ("gnunet-proof-of-work"),
495                                  2 /* iterations; keep cost of individual op small */,
496                                  sizeof (struct GNUNET_HashCode), result));
497 }
498
499
500 /**
501  * Get the number of matching bits that the given timestamp has to the given peer ID.
502  *
503  * @param timestamp time to generate key
504  * @param id peer identity to compare with
505  * @return number of matching bits
506  */
507 static uint32_t
508 get_matching_bits (struct GNUNET_TIME_Absolute timestamp,
509                    const struct GNUNET_PeerIdentity *id)
510 {
511   struct GNUNET_HashCode timestamp_hash;
512
513   GNUNET_CRYPTO_hash (&timestamp.abs_value_us, sizeof (timestamp.abs_value_us),
514                       &timestamp_hash);
515   return GNUNET_CRYPTO_hash_matching_bits (&timestamp_hash, &id->hashPubKey);
516 }
517
518
519 /**
520  * Get the transmission delay that should be applied for a
521  * particular round.
522  *
523  * @param round_offset -1 for the previous round (random delay between 0 and 50ms)
524  *                      0 for the current round (based on our proximity to time key)
525  * @return delay that should be applied
526  */
527 static struct GNUNET_TIME_Relative
528 get_transmit_delay (int round_offset)
529 {
530   struct GNUNET_TIME_Relative ret;
531   struct GNUNET_TIME_Absolute tgt;
532   double dist_delay;
533   uint32_t matching_bits;
534
535   switch (round_offset)
536   {
537   case -1:
538     /* previous round is randomized between 0 and 50 ms */
539 #if USE_RANDOM_DELAYS
540     ret.rel_value_us = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, 50);
541 #else
542     ret = GNUNET_TIME_UNIT_ZERO;
543 #endif
544     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
545                 "Transmitting previous round behind schedule in %s\n",
546                 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
547     return ret;
548   case 0:
549     /* current round is based on best-known matching_bits */
550     matching_bits =
551         ntohl (size_estimate_messages[estimate_index].matching_bits);
552     dist_delay = get_matching_bits_delay (matching_bits);
553     dist_delay += get_delay_randomization (matching_bits).rel_value_us;
554     ret.rel_value_us = (uint64_t) dist_delay;
555     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
556                 "For round %s, delay for %u matching bits is %s\n",
557                 GNUNET_STRINGS_absolute_time_to_string (current_timestamp),
558                 (unsigned int) matching_bits,
559                 GNUNET_STRINGS_relative_time_to_string (ret,
560                                                         GNUNET_YES));
561     /* now consider round start time and add delay to it */
562     tgt = GNUNET_TIME_absolute_add (current_timestamp, ret);
563     return GNUNET_TIME_absolute_get_remaining (tgt);
564   }
565   GNUNET_break (0);
566   return GNUNET_TIME_UNIT_FOREVER_REL;
567 }
568
569
570 /**
571  * Task that triggers a NSE P2P transmission.
572  *
573  * @param cls the 'struct NSEPeerEntry'
574  * @param tc scheduler context
575  */
576 static void
577 transmit_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
578
579
580 /**
581  * Called when core is ready to send a message we asked for
582  * out to the destination.
583  *
584  * @param cls closure (NULL)
585  * @param size number of bytes available in buf
586  * @param buf where the callee should write the message
587  * @return number of bytes written to buf
588  */
589 static size_t
590 transmit_ready (void *cls, size_t size, void *buf)
591 {
592   struct NSEPeerEntry *peer_entry = cls;
593   unsigned int idx;
594
595   peer_entry->th = NULL;
596   if (NULL == buf)
597   {
598     /* client disconnected */
599     return 0;
600   }
601   GNUNET_assert (size >= sizeof (struct GNUNET_NSE_FloodMessage));
602   idx = estimate_index;
603   if (GNUNET_NO == peer_entry->previous_round)
604   {
605     idx = (idx + HISTORY_SIZE - 1) % HISTORY_SIZE;
606     peer_entry->previous_round = GNUNET_YES;
607     peer_entry->transmit_task =
608         GNUNET_SCHEDULER_add_delayed (get_transmit_delay (0), &transmit_task_cb,
609                                       peer_entry);
610   }
611   if ((0 == ntohl (size_estimate_messages[idx].hop_count)) &&
612       (GNUNET_SCHEDULER_NO_TASK != proof_task))
613   {
614     GNUNET_STATISTICS_update (stats,
615                               "# flood messages not generated (no proof yet)",
616                               1, GNUNET_NO);
617     return 0;
618   }
619   if (0 == ntohs (size_estimate_messages[idx].header.size))
620   {
621     GNUNET_STATISTICS_update (stats,
622                               "# flood messages not generated (lack of history)",
623                               1, GNUNET_NO);
624     return 0;
625   }
626   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
627               "In round s, sending to `%s' estimate with %u bits\n",
628               GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (size_estimate_messages[idx].timestamp)),
629               GNUNET_i2s (&peer_entry->id),
630               (unsigned int) ntohl (size_estimate_messages[idx].matching_bits));
631   if (ntohl (size_estimate_messages[idx].hop_count) == 0)
632     GNUNET_STATISTICS_update (stats, "# flood messages started", 1, GNUNET_NO);
633   GNUNET_STATISTICS_update (stats, "# flood messages transmitted", 1,
634                             GNUNET_NO);
635 #if ENABLE_NSE_HISTOGRAM
636   peer_entry->transmitted_messages++;
637   peer_entry->last_transmitted_size = 
638       ntohl(size_estimate_messages[idx].matching_bits);
639 #endif
640   memcpy (buf, &size_estimate_messages[idx],
641           sizeof (struct GNUNET_NSE_FloodMessage));
642   return sizeof (struct GNUNET_NSE_FloodMessage);
643 }
644
645
646 /**
647  * Task that triggers a NSE P2P transmission.
648  *
649  * @param cls the 'struct NSEPeerEntry'
650  * @param tc scheduler context
651  */
652 static void
653 transmit_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
654 {
655   struct NSEPeerEntry *peer_entry = cls;
656
657   peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
658
659   GNUNET_assert (NULL == peer_entry->th);
660   peer_entry->th =
661       GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_NO, NSE_PRIORITY,
662                                          GNUNET_TIME_UNIT_FOREVER_REL,
663                                          &peer_entry->id,
664                                          sizeof (struct
665                                                  GNUNET_NSE_FloodMessage),
666                                          &transmit_ready, peer_entry);
667 }
668
669
670 /**
671  * We've sent on our flood message or one that we received which was
672  * validated and closer than ours.  Update the global list of recent
673  * messages and the average.  Also re-broadcast the message to any
674  * clients.
675  */
676 static void
677 update_network_size_estimate ()
678 {
679   struct GNUNET_NSE_ClientMessage em;
680
681   setup_estimate_message (&em);
682   GNUNET_SERVER_notification_context_broadcast (nc, &em.header, GNUNET_YES);
683 }
684
685
686 /**
687  * Setup a flood message in our history array at the given
688  * slot offset for the given timestamp.
689  *
690  * @param slot index to use
691  * @param ts timestamp to use
692  */
693 static void
694 setup_flood_message (unsigned int slot,
695                      struct GNUNET_TIME_Absolute ts)
696 {
697   struct GNUNET_NSE_FloodMessage *fm;
698   uint32_t matching_bits;
699
700   matching_bits = get_matching_bits (ts, &my_identity);
701   fm = &size_estimate_messages[slot];
702   fm->header.size = htons (sizeof (struct GNUNET_NSE_FloodMessage));
703   fm->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD);
704   fm->hop_count = htonl (0);
705   fm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND);
706   fm->purpose.size =
707       htonl (sizeof (struct GNUNET_NSE_FloodMessage) -
708              sizeof (struct GNUNET_MessageHeader) - sizeof (uint32_t) -
709              sizeof (struct GNUNET_CRYPTO_EccSignature));
710   fm->matching_bits = htonl (matching_bits);
711   fm->timestamp = GNUNET_TIME_absolute_hton (ts);
712   fm->pkey = my_public_key;
713   fm->proof_of_work = my_proof;
714   if (nse_work_required > 0)
715     GNUNET_assert (GNUNET_OK ==
716                    GNUNET_CRYPTO_ecc_sign (my_private_key, &fm->purpose,
717                                            &fm->signature));
718   else
719     memset (&fm->signature, 0, sizeof (fm->signature));
720 }
721
722
723 /**
724  * Schedule transmission for the given peer for the current round based
725  * on what we know about the desired delay.
726  *
727  * @param cls unused
728  * @param key hash of peer identity
729  * @param value the 'struct NSEPeerEntry'
730  * @return GNUNET_OK (continue to iterate)
731  */
732 static int
733 schedule_current_round (void *cls, 
734                         const struct GNUNET_HashCode * key, 
735                         void *value)
736 {
737   struct NSEPeerEntry *peer_entry = value;
738   struct GNUNET_TIME_Relative delay;
739
740   if (NULL != peer_entry->th)
741   {
742     peer_entry->previous_round = GNUNET_NO;
743     return GNUNET_OK;
744   }
745   if (GNUNET_SCHEDULER_NO_TASK != peer_entry->transmit_task)
746   {
747     GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
748     peer_entry->previous_round = GNUNET_NO;
749   }
750 #if ENABLE_NSE_HISTOGRAM
751   if (peer_entry->received_messages > 1)
752     GNUNET_STATISTICS_update(stats, "# extra messages",
753                              peer_entry->received_messages - 1, GNUNET_NO);
754   peer_entry->transmitted_messages = 0;
755   peer_entry->last_transmitted_size = 0;
756   peer_entry->received_messages = 0;
757 #endif
758   delay =
759       get_transmit_delay ((peer_entry->previous_round == GNUNET_NO) ? -1 : 0);
760   peer_entry->transmit_task =
761       GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
762   return GNUNET_OK;
763 }
764
765
766 /**
767  * Update our flood message to be sent (and our timestamps).
768  *
769  * @param cls unused
770  * @param tc context for this message
771  */
772 static void
773 update_flood_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
774 {
775   struct GNUNET_TIME_Relative offset;
776   unsigned int i;
777
778   flood_task = GNUNET_SCHEDULER_NO_TASK;
779   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
780     return;
781   offset = GNUNET_TIME_absolute_get_remaining (next_timestamp);
782   if (0 != offset.rel_value_us)
783   {
784     /* somehow run early, delay more */
785     flood_task =
786         GNUNET_SCHEDULER_add_delayed (offset, &update_flood_message, NULL);
787     return;
788   }
789   estimate_index = (estimate_index + 1) % HISTORY_SIZE;
790   if (estimate_count < HISTORY_SIZE)
791     estimate_count++;
792   current_timestamp = next_timestamp;
793   next_timestamp =
794       GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
795   if ((current_timestamp.abs_value_us ==
796       GNUNET_TIME_absolute_ntoh (next_message.timestamp).abs_value_us) &&
797       (get_matching_bits (current_timestamp, &my_identity) <
798       ntohl(next_message.matching_bits)))
799   {
800     /* we received a message for this round way early, use it! */
801     size_estimate_messages[estimate_index] = next_message;
802     size_estimate_messages[estimate_index].hop_count =
803         htonl (1 + ntohl (next_message.hop_count));
804   }
805   else
806     setup_flood_message (estimate_index, current_timestamp);
807   next_message.matching_bits = htonl (0);       /* reset for 'next' round */
808   hop_count_max = 0;
809   for (i = 0; i < HISTORY_SIZE; i++)
810     hop_count_max =
811         GNUNET_MAX (ntohl (size_estimate_messages[i].hop_count), hop_count_max);
812   GNUNET_CONTAINER_multihashmap_iterate (peers, &schedule_current_round, NULL);
813   flood_task =
814       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
815                                     (next_timestamp), &update_flood_message,
816                                     NULL);
817 }
818
819
820 /**
821  * Count the leading zeroes in hash.
822  *
823  * @param hash
824  * @return the number of leading zero bits.
825  */
826 static unsigned int
827 count_leading_zeroes (const struct GNUNET_HashCode * hash)
828 {
829   unsigned int hash_count;
830
831   hash_count = 0;
832   while ((0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count)))
833     hash_count++;
834   return hash_count;
835 }
836
837
838 /**
839  * Check whether the given public key
840  * and integer are a valid proof of work.
841  *
842  * @param pkey the public key
843  * @param val the integer
844  *
845  * @return GNUNET_YES if valid, GNUNET_NO if not
846  */
847 static int
848 check_proof_of_work (const struct GNUNET_CRYPTO_EccPublicKey *pkey,
849                      uint64_t val)
850 {
851   char buf[sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
852            sizeof (val)] GNUNET_ALIGN;
853   struct GNUNET_HashCode result;
854
855   memcpy (buf, &val, sizeof (val));
856   memcpy (&buf[sizeof (val)], pkey,
857           sizeof (struct GNUNET_CRYPTO_EccPublicKey));
858   pow_hash (buf, sizeof (buf), &result);
859   return (count_leading_zeroes (&result) >=
860           nse_work_required) ? GNUNET_YES : GNUNET_NO;
861 }
862
863
864 /**
865  * Write our current proof to disk.
866  */
867 static void
868 write_proof ()
869 {
870   char *proof;
871
872   if (GNUNET_OK !=
873       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
874     return;
875   if (sizeof (my_proof) !=
876       GNUNET_DISK_fn_write (proof, &my_proof, sizeof (my_proof),
877                             GNUNET_DISK_PERM_USER_READ |
878                             GNUNET_DISK_PERM_USER_WRITE))
879     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", proof);
880   GNUNET_free (proof);
881
882 }
883
884
885 /**
886  * Find our proof of work.
887  *
888  * @param cls closure (unused)
889  * @param tc task context
890  */
891 static void
892 find_proof (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
893 {
894 #define ROUND_SIZE 10
895   uint64_t counter;
896   char buf[sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
897            sizeof (uint64_t)] GNUNET_ALIGN;
898   struct GNUNET_HashCode result;
899   unsigned int i;
900
901   proof_task = GNUNET_SCHEDULER_NO_TASK;
902   memcpy (&buf[sizeof (uint64_t)], &my_public_key,
903           sizeof (struct GNUNET_CRYPTO_EccPublicKey));
904   i = 0;
905   counter = my_proof;
906   while ((counter != UINT64_MAX) && (i < ROUND_SIZE))
907   {
908     memcpy (buf, &counter, sizeof (uint64_t));
909     pow_hash (buf, sizeof (buf), &result);
910     if (nse_work_required <= count_leading_zeroes (&result))
911     {
912       my_proof = counter;
913       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Proof of work found: %llu!\n",
914                   (unsigned long long) GNUNET_ntohll (counter));
915       write_proof ();
916       setup_flood_message (estimate_index, current_timestamp);
917       return;
918     }
919     counter++;
920     i++;
921   }
922   if (my_proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE))
923   {
924     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing proofs currently at %llu\n",
925                 (unsigned long long) counter);
926     /* remember progress every 100 rounds */
927     my_proof = counter;
928     write_proof ();
929   }
930   else
931   {
932     my_proof = counter;
933   }
934   proof_task =
935       GNUNET_SCHEDULER_add_delayed_with_priority (proof_find_delay,
936                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
937                                                   &find_proof, NULL);
938 }
939
940
941 /**
942  * An incoming flood message has been received which claims
943  * to have more bits matching than any we know in this time
944  * period.  Verify the signature and/or proof of work.
945  *
946  * @param incoming_flood the message to verify
947  *
948  * @return GNUNET_YES if the message is verified
949  *         GNUNET_NO if the key/signature don't verify
950  */
951 static int
952 verify_message_crypto (const struct GNUNET_NSE_FloodMessage *incoming_flood)
953 {
954   if (GNUNET_YES !=
955       check_proof_of_work (&incoming_flood->pkey,
956                            incoming_flood->proof_of_work))
957   {
958     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Proof of work invalid: %llu!\n",
959                 (unsigned long long)
960                 GNUNET_ntohll (incoming_flood->proof_of_work));
961     GNUNET_break_op (0);
962     return GNUNET_NO;
963   }
964   if ((nse_work_required > 0) &&
965       (GNUNET_OK !=
966        GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND,
967                                  &incoming_flood->purpose,
968                                  &incoming_flood->signature,
969                                  &incoming_flood->pkey)))
970   {
971     GNUNET_break_op (0);
972     return GNUNET_NO;
973   }
974   return GNUNET_YES;
975 }
976
977
978 /**
979  * Update transmissions for the given peer for the current round based
980  * on updated proximity information.
981  *
982  * @param cls peer entry to exclude from updates
983  * @param key hash of peer identity
984  * @param value the 'struct NSEPeerEntry'
985  * @return GNUNET_OK (continue to iterate)
986  */
987 static int
988 update_flood_times (void *cls, const struct GNUNET_HashCode * key, void *value)
989 {
990   struct NSEPeerEntry *exclude = cls;
991   struct NSEPeerEntry *peer_entry = value;
992   struct GNUNET_TIME_Relative delay;
993
994   if (NULL != peer_entry->th)
995     return GNUNET_OK;           /* already active */
996   if (peer_entry == exclude)
997     return GNUNET_OK;           /* trigger of the update */
998   if (peer_entry->previous_round == GNUNET_NO)
999   {
1000     /* still stuck in previous round, no point to update, check that
1001      * we are active here though... */
1002     if ( (GNUNET_SCHEDULER_NO_TASK == peer_entry->transmit_task) &&
1003          (NULL == peer_entry->th) )
1004     {
1005         GNUNET_break (0);
1006     }
1007     return GNUNET_OK;
1008   }
1009   if (GNUNET_SCHEDULER_NO_TASK != peer_entry->transmit_task)
1010   {
1011     GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
1012     peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK;
1013   }
1014   delay = get_transmit_delay (0);
1015   peer_entry->transmit_task =
1016       GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry);
1017   return GNUNET_OK;
1018 }
1019
1020
1021 /**
1022  * Core handler for size estimate flooding messages.
1023  *
1024  * @param cls closure unused
1025  * @param message message
1026  * @param peer peer identity this message is from (ignored)
1027  */
1028 static int
1029 handle_p2p_size_estimate (void *cls, const struct GNUNET_PeerIdentity *peer,
1030                           const struct GNUNET_MessageHeader *message)
1031 {
1032   const struct GNUNET_NSE_FloodMessage *incoming_flood;
1033   struct GNUNET_TIME_Absolute ts;
1034   struct NSEPeerEntry *peer_entry;
1035   uint32_t matching_bits;
1036   unsigned int idx;
1037
1038 #if ENABLE_NSE_HISTOGRAM
1039   {
1040     uint64_t t;
1041
1042     t = GNUNET_TIME_absolute_get().abs_value_us;
1043     GNUNET_TESTBED_LOGGER_write (lh, &t, sizeof (uint64_t));
1044   }
1045 #endif
1046   incoming_flood = (const struct GNUNET_NSE_FloodMessage *) message;
1047   GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO);
1048   matching_bits = ntohl (incoming_flood->matching_bits);
1049 #if DEBUG_NSE
1050   {
1051     char origin[5];
1052     char pred[5];
1053     struct GNUNET_PeerIdentity os;
1054
1055     GNUNET_CRYPTO_hash (&incoming_flood->pkey,
1056                         sizeof (struct GNUNET_CRYPTO_EccPublicKey),
1057                         &os.hashPubKey);
1058     GNUNET_snprintf (origin, sizeof (origin), "%s", GNUNET_i2s (&os));
1059     GNUNET_snprintf (pred, sizeof (pred), "%s", GNUNET_i2s (peer));
1060     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1061                 "Flood at %s from `%s' via `%s' at `%s' with bits %u\n",
1062                 GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp)),
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_us == current_timestamp.abs_value_us)
1083     idx = estimate_index;
1084   else if (ts.abs_value_us ==
1085            current_timestamp.abs_value_us - gnunet_nse_interval.rel_value_us)
1086     idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1087   else if (ts.abs_value_us == next_timestamp.abs_value_us)
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 != nc)
1307   {
1308     GNUNET_SERVER_notification_context_destroy (nc);
1309     nc = NULL;
1310   }
1311   if (NULL != coreAPI)
1312   {
1313     GNUNET_CORE_disconnect (coreAPI);
1314     coreAPI = NULL;
1315   }
1316   if (NULL != stats)
1317   {
1318     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1319     stats = NULL;
1320   }
1321   if (NULL != peers)
1322   {
1323     GNUNET_CONTAINER_multihashmap_destroy (peers);
1324     peers = NULL;
1325   }
1326   if (NULL != my_private_key)
1327   {
1328     GNUNET_free (my_private_key);
1329     my_private_key = NULL;
1330   }
1331 #if ENABLE_NSE_HISTOGRAM
1332   struct GNUNET_TIME_Relative timeout;
1333   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30);
1334   GNUNET_TESTBED_LOGGER_flush (lh, timeout, &flush_comp_cb, NULL);
1335 #endif
1336 }
1337
1338
1339 /**
1340  * Called on core init/fail.
1341  *
1342  * @param cls service closure
1343  * @param identity the public identity of this peer
1344  */
1345 static void
1346 core_init (void *cls, 
1347            const struct GNUNET_PeerIdentity *identity)
1348 {
1349   struct GNUNET_TIME_Absolute now;
1350   struct GNUNET_TIME_Absolute prev_time;
1351
1352   if (NULL == identity)
1353   {
1354     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection to core FAILED!\n");
1355     GNUNET_SCHEDULER_shutdown ();
1356     return;
1357   }
1358   GNUNET_assert (0 ==
1359                  memcmp (&my_identity, identity,
1360                          sizeof (struct GNUNET_PeerIdentity)));
1361   now = GNUNET_TIME_absolute_get ();
1362   current_timestamp.abs_value_us =
1363       (now.abs_value_us / gnunet_nse_interval.rel_value_us) *
1364       gnunet_nse_interval.rel_value_us;
1365   next_timestamp =
1366       GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval);
1367   estimate_index = HISTORY_SIZE - 1;
1368   estimate_count = 0;
1369   if (GNUNET_YES == check_proof_of_work (&my_public_key, my_proof))
1370   {
1371     int idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE;
1372     prev_time.abs_value_us =
1373         current_timestamp.abs_value_us - gnunet_nse_interval.rel_value_us;
1374     setup_flood_message (idx, prev_time);
1375     setup_flood_message (estimate_index, current_timestamp);
1376     estimate_count++;
1377   }
1378   flood_task =
1379       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
1380                                     (next_timestamp), &update_flood_message,
1381                                     NULL);
1382 }
1383
1384
1385 /**
1386  * Handle network size estimate clients.
1387  *
1388  * @param cls closure
1389  * @param server the initialized server
1390  * @param c configuration to use
1391  */
1392 static void
1393 run (void *cls, 
1394      struct GNUNET_SERVER_Handle *server,
1395      const struct GNUNET_CONFIGURATION_Handle *c)
1396 {
1397   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1398     {&handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START,
1399      sizeof (struct GNUNET_MessageHeader)},
1400     {NULL, NULL, 0, 0}
1401   };
1402   static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
1403     {&handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD,
1404      sizeof (struct GNUNET_NSE_FloodMessage)},
1405     {NULL, 0, 0}
1406   };
1407   char *proof;
1408   char *keyfile;
1409   struct GNUNET_CRYPTO_EccPrivateKey *pk;
1410
1411   cfg = c;
1412   srv = server;  
1413   if ((GNUNET_OK !=
1414        GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "INTERVAL",
1415                                             &gnunet_nse_interval)) ||
1416       (GNUNET_OK !=
1417        GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "WORKDELAY",
1418                                             &proof_find_delay)) ||
1419       (GNUNET_OK !=
1420        GNUNET_CONFIGURATION_get_value_number (cfg, "NSE", "WORKBITS",
1421                                               &nse_work_required)))
1422   {
1423     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1424                 _
1425                 ("%s service is lacking key configuration settings (%s).  Exiting.\n"),
1426                 "NSE", "interval/workdelay/workbits");
1427     GNUNET_SCHEDULER_shutdown ();
1428     return;
1429   }
1430   if (nse_work_required >= sizeof (struct GNUNET_HashCode) * 8)
1431   {
1432     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1433                 _("Invalid work requirement for NSE service. Exiting.\n"));
1434     GNUNET_SCHEDULER_shutdown ();
1435     return;
1436   }
1437   if (GNUNET_OK !=
1438       GNUNET_CONFIGURATION_get_value_filename (c, "PEER", "PRIVATE_KEY",
1439                                                &keyfile))
1440   {
1441     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1442                 _
1443                 ("%s service is lacking key configuration settings (%s).  Exiting.\n"),
1444                 "NSE", "peer/privatekey");
1445     GNUNET_SCHEDULER_shutdown ();
1446     return;
1447   }
1448 #if ENABLE_NSE_HISTOGRAM
1449   if (NULL == (lh = GNUNET_TESTBED_LOGGER_connect (cfg)))
1450   {
1451     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1452                 "Cannot connect to the testbed logger.  Exiting.\n");
1453     GNUNET_SCHEDULER_shutdown ();
1454     return;
1455   }
1456 #endif
1457
1458   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1459                                 NULL);
1460   pk = GNUNET_CRYPTO_ecc_key_create_from_file (keyfile);
1461   GNUNET_free (keyfile);
1462   GNUNET_assert (NULL != pk);
1463   my_private_key = pk;
1464   GNUNET_CRYPTO_ecc_key_get_public (my_private_key, &my_public_key);
1465   GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
1466                       &my_identity.hashPubKey);
1467   if (GNUNET_OK !=
1468       GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof))
1469   {
1470     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1471                 _
1472                 ("NSE service is lacking key configuration settings.  Exiting.\n"));
1473     GNUNET_free (my_private_key);
1474     my_private_key = NULL;    
1475     GNUNET_SCHEDULER_shutdown ();
1476     return;
1477   }
1478   if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) ||
1479       (sizeof (my_proof) !=
1480        GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof))))
1481     my_proof = 0;
1482   GNUNET_free (proof);
1483   proof_task =
1484       GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
1485                                           &find_proof, NULL);
1486
1487   peers = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
1488   GNUNET_SERVER_add_handlers (srv, handlers);
1489   nc = GNUNET_SERVER_notification_context_create (srv, 1);
1490   /* Connect to core service and register core handlers */
1491   coreAPI = GNUNET_CORE_connect (cfg,   /* Main configuration */
1492                                  NULL,       /* Closure passed to functions */
1493                                  &core_init,    /* Call core_init once connected */
1494                                  &handle_core_connect,  /* Handle connects */
1495                                  &handle_core_disconnect,       /* Handle disconnects */
1496                                  NULL,  /* Don't want notified about all incoming messages */
1497                                  GNUNET_NO,     /* For header only inbound notification */
1498                                  NULL,  /* Don't want notified about all outbound messages */
1499                                  GNUNET_NO,     /* For header only outbound notification */
1500                                  core_handlers);        /* Register these handlers */
1501   if (NULL == coreAPI)
1502   {
1503     GNUNET_SCHEDULER_shutdown ();
1504     return;
1505   }
1506   stats = GNUNET_STATISTICS_create ("nse", cfg);
1507 }
1508
1509
1510 /**
1511  * The main function for the network size estimation service.
1512  *
1513  * @param argc number of arguments from the command line
1514  * @param argv command line arguments
1515  * @return 0 ok, 1 on error
1516  */
1517 int
1518 main (int argc, char *const *argv)
1519 {
1520   return (GNUNET_OK ==
1521           GNUNET_SERVICE_run (argc, argv, "nse", GNUNET_SERVICE_OPTION_NONE,
1522                               &run, NULL)) ? 0 : 1;
1523 }
1524
1525
1526 #ifdef LINUX
1527 #include <malloc.h>
1528
1529 /**
1530  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1531  */
1532 void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
1533 {
1534   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1535   mallopt (M_TOP_PAD, 1 * 1024);
1536   malloc_trim (0);
1537 }
1538 #endif
1539
1540
1541
1542 /* end of gnunet-service-nse.c */