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