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