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