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