2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file nse/gnunet-service-nse.c
23 * @brief network size estimation service
24 * @author Nathan Evans
26 * The purpose of this service is to estimate the size of the network.
27 * Given a specified interval, each peer hashes the most recent
28 * timestamp which is evenly divisible by that interval. This hash
29 * is compared in distance to the peer identity to choose an offset.
30 * The closer the peer identity to the hashed timestamp, the earlier
31 * the peer sends out a "nearest peer" message. The closest peer's
32 * message should thus be received before any others, which stops
33 * those peer from sending their messages at a later duration. So
34 * every peer should receive the same nearest peer message, and
35 * from this can calculate the expected number of peers in the
40 #include "gnunet_client_lib.h"
41 #include "gnunet_constants.h"
42 #include "gnunet_container_lib.h"
43 #include "gnunet_protocols.h"
44 #include "gnunet_signatures.h"
45 #include "gnunet_service_lib.h"
46 #include "gnunet_server_lib.h"
47 #include "gnunet_statistics_service.h"
48 #include "gnunet_core_service.h"
49 #include "gnunet_time_lib.h"
50 #include "gnunet_nse_service.h"
53 #define DEFAULT_HISTORY_SIZE 10
55 #define DEFAULT_CORE_QUEUE_SIZE 32
57 #define DEFAULT_NSE_PRIORITY 5
59 #define DO_FORWARD GNUNET_YES
62 * Entry in the list of clients which
63 * should be notified upon a new network
64 * size estimate calculation.
66 struct ClientListEntry
69 * Pointer to previous entry
71 struct ClientListEntry *prev;
74 * Pointer to next entry
76 struct ClientListEntry *next;
81 struct GNUNET_SERVER_Client *client;
85 * Per-peer information.
90 * Next peer entry (DLL)
92 struct NSEPeerEntry *next;
95 * Prev peer entry (DLL)
97 struct NSEPeerEntry *prev;
100 * Pending message for this peer.
102 struct GNUNET_MessageHeader *pending_message;
105 * Core handle for sending messages to this peer.
107 struct GNUNET_CORE_TransmitHandle *th;
110 * What is the identity of the peer?
112 struct GNUNET_PeerIdentity id;
116 * Handle to our current configuration.
118 static const struct GNUNET_CONFIGURATION_Handle *cfg;
121 * Handle to the statistics service.
123 static struct GNUNET_STATISTICS_Handle *stats;
126 * Handle to the core service.
128 static struct GNUNET_CORE_Handle *coreAPI;
131 * Head of global list of peers.
133 static struct NSEPeerEntry *peers_head;
136 * Head of global list of clients.
138 static struct NSEPeerEntry *peers_tail;
141 * Head of global list of clients.
143 static struct ClientListEntry *cle_head;
146 * Tail of global list of clients.
148 static struct ClientListEntry *cle_tail;
151 * The current network size estimate.
152 * Number of bits matching on average
155 static double current_size_estimate;
158 * The standard deviation of the last
159 * DEFAULT_HISTORY_SIZE network size estimates.
161 static double current_std_dev;
164 * Array of the last DEFAULT_HISTORY_SIZE
165 * network size estimates (matching bits, actually).
167 static unsigned int size_estimates[DEFAULT_HISTORY_SIZE];
170 * Array of size estimate messages.
172 static struct GNUNET_NSE_FloodMessage
173 size_estimate_messages[DEFAULT_HISTORY_SIZE];
176 * Index of most recent estimate.
178 static unsigned int estimate_index;
181 * Task scheduled to send flood message.
183 static GNUNET_SCHEDULER_TaskIdentifier flood_task;
186 * Task to schedule flood message and update state.
188 static GNUNET_SCHEDULER_TaskIdentifier schedule_flood_task;
191 * Notification context, simplifies client broadcasts.
193 static struct GNUNET_SERVER_NotificationContext *nc;
196 * The previous major time.
198 static struct GNUNET_TIME_Absolute previous_timestamp;
201 * The next major time.
203 static struct GNUNET_TIME_Absolute next_timestamp;
206 * Base increment of time to add to send time.
208 static struct GNUNET_TIME_Relative increment;
211 * The current network size estimate message.
213 static struct GNUNET_NSE_ClientMessage current_estimate_message;
216 * The public key of this peer.
218 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
221 * The private key of this peer.
223 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
226 * The peer identity of this peer.
228 static struct GNUNET_PeerIdentity my_identity;
231 * Our flood message, updated whenever a flood is sent.
233 static struct GNUNET_NSE_FloodMessage flood_message;
236 * Handler for START message from client, triggers an
237 * immediate current network estimate notification.
238 * Also, we remember the client for updates upon future
239 * estimate measurements.
242 * @param client who sent the message
243 * @param message the message received
246 handle_start_message(void *cls, struct GNUNET_SERVER_Client *client,
247 const struct GNUNET_MessageHeader *message)
249 if ((ntohs (message->size) != sizeof(struct GNUNET_MessageHeader))
250 || (ntohs (message->type) != GNUNET_MESSAGE_TYPE_NSE_START))
254 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "NSE",
255 "Received START message from client\n");
257 GNUNET_SERVER_notification_context_add (nc, client);
258 GNUNET_SERVER_receive_done (client, GNUNET_OK);
262 * Called when core is ready to send a message we asked for
263 * out to the destination.
265 * @param cls closure (NULL)
266 * @param size number of bytes available in buf
267 * @param buf where the callee should write the message
268 * @return number of bytes written to buf
271 transmit_ready(void *cls, size_t size, void *buf)
273 struct NSEPeerEntry *peer_entry = cls;
277 peer_entry->th = NULL;
279 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: transmit_ready called\n",
280 GNUNET_i2s (&my_identity));
282 if (buf == NULL) /* client disconnected */
284 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
285 "%s: transmit_ready called (disconnect)\n",
286 GNUNET_i2s (&my_identity));
290 if (peer_entry->pending_message == NULL)
292 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
293 "%s: transmit_ready called (no message)\n",
294 GNUNET_i2s (&my_identity));
298 msize = ntohs (peer_entry->pending_message->size);
300 memcpy (cbuf, peer_entry->pending_message, msize);
302 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
303 "%s: transmit_ready called (transmit %d bytes)\n",
304 GNUNET_i2s (&my_identity), msize);
310 * We sent on our flood message or one that we received
311 * which was validated and closer than ours. Update the
312 * global list of recent messages and the average. Also
313 * re-broadcast the message to any clients.
315 * @param message the network flood message
318 update_network_size_estimate(struct GNUNET_NSE_FloodMessage *message)
326 size_estimates[estimate_index] = htonl (message->distance);
327 memcpy (&size_estimate_messages[estimate_index], message,
328 sizeof(struct GNUNET_NSE_FloodMessage));
333 for (i = 0; i < DEFAULT_HISTORY_SIZE; i++)
335 if (size_estimate_messages[i].distance != 0)
338 average += (1 << htonl (size_estimate_messages[i].distance));
340 average += htonl (size_estimate_messages[i].distance);
348 average /= (double) count;
349 for (i = 0; i < DEFAULT_HISTORY_SIZE; i++)
351 if (size_estimate_messages[i].distance != 0)
354 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%s: estimate %d %d\n", GNUNET_i2s(&my_identity), i, (1 << htonl(size_estimate_messages[i].distance)));
358 - (1 << htonl (size_estimate_messages[i].distance));
360 diff = average - htonl (size_estimate_messages[i].distance);
362 std_dev += diff * diff;
366 std_dev = sqrt (std_dev);
367 current_estimate_message.header.size
368 = htons (sizeof(struct GNUNET_NSE_ClientMessage));
369 current_estimate_message.header.type
370 = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE);
372 current_estimate_message.size_estimate = average;
373 current_estimate_message.std_deviation = std_dev;
375 current_estimate_message.size_estimate = pow(2, average);
376 current_estimate_message.std_deviation = pow(2, std_dev);
378 /* Finally, broadcast the current estimate to all clients */
380 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
381 "%s: sending estimate %f -- %f to client\n",
382 GNUNET_i2s (&my_identity),
386 GNUNET_SERVER_notification_context_broadcast (
388 ¤t_estimate_message.header,
391 GNUNET_STATISTICS_set (stats, "Current network size estimate",
392 (uint64_t) average, GNUNET_NO);
397 send_flood_message(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc);
400 * Schedule a flood message to be sent.
403 * @param tc context for this message
405 * This should be called on startup,
406 * when a valid flood message is received (and
407 * the next send flood message hasn't been
408 * scheduled yet) and when this peer sends
409 * a valid flood message. As such, there should
410 * always be a message scheduled to be sent.
413 schedule_flood_message(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
415 GNUNET_HashCode timestamp_hash;
416 struct GNUNET_TIME_Absolute curr_time;
417 struct GNUNET_TIME_Relative offset;
418 unsigned int matching_bits;
419 double millisecond_offset;
421 schedule_flood_task = GNUNET_SCHEDULER_NO_TASK;
422 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
425 GNUNET_assert(flood_task == GNUNET_SCHEDULER_NO_TASK);
427 if (0 != GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value)
429 GNUNET_break(0); /* Shouldn't ever happen! */
431 = GNUNET_SCHEDULER_add_delayed (
432 GNUNET_TIME_absolute_get_remaining (
434 &schedule_flood_message, NULL);
437 /* Get the current UTC time */
438 curr_time = GNUNET_TIME_absolute_get ();
439 /* Find the previous interval start time */
440 previous_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL)
441 * GNUNET_NSE_INTERVAL;
442 /* Find the next interval start time */
443 next_timestamp.abs_value = previous_timestamp.abs_value + GNUNET_NSE_INTERVAL;
445 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
446 "%s: curr_time %lu, prev timestamp %lu, next timestamp %lu\n",
447 GNUNET_i2s (&my_identity), curr_time.abs_value,
448 previous_timestamp.abs_value, next_timestamp.abs_value);
450 GNUNET_CRYPTO_hash (&next_timestamp.abs_value,
451 sizeof(next_timestamp.abs_value), ×tamp_hash);
452 matching_bits = GNUNET_CRYPTO_hash_matching_bits (×tamp_hash,
453 &my_identity.hashPubKey);
455 flood_message.header.size = htons (sizeof(struct GNUNET_NSE_FloodMessage));
456 flood_message.header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD);
457 flood_message.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND);
458 flood_message.purpose.size = htonl (sizeof(struct GNUNET_NSE_FloodMessage)
459 - sizeof(struct GNUNET_MessageHeader) - sizeof(flood_message.signature));
460 flood_message.distance = htonl (matching_bits);
461 flood_message.timestamp = GNUNET_TIME_absolute_hton (next_timestamp);
462 memcpy (&flood_message.pkey, &my_public_key,
463 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
464 flood_message.proof_of_work = htonl (0);
465 GNUNET_CRYPTO_rsa_sign (my_private_key, &flood_message.purpose,
466 &flood_message.signature);
468 /*S + f/2 - (f / pi) * (atan(x - p'))*/
470 // S is next_timestamp
471 // f is frequency (GNUNET_NSE_INTERVAL)
472 // x is matching_bits
473 // p' is current_size_estimate
474 millisecond_offset = ((double) GNUNET_NSE_INTERVAL / (double) 2)
475 - ((GNUNET_NSE_INTERVAL / M_PI) * atan (matching_bits
476 - current_size_estimate));
478 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
479 "%s: id matches %d bits, offset is %lu\n\n",
480 GNUNET_i2s (&my_identity), matching_bits,
481 (uint64_t) millisecond_offset);
483 /* Stop initial call from incrementing */
484 if (size_estimate_messages[estimate_index].distance != 0)
487 if (estimate_index >= DEFAULT_HISTORY_SIZE)
490 if (millisecond_offset < curr_time.abs_value - previous_timestamp.abs_value)
491 offset.rel_value = 0;
493 offset.rel_value = (uint64_t) millisecond_offset + curr_time.abs_value
494 - previous_timestamp.abs_value;
497 GNUNET_ERROR_TYPE_WARNING,
498 "%s: milliseconds until next timestamp %lu, sending flood in %lu\n",
499 GNUNET_i2s (&my_identity),
500 GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value,
503 flood_task = GNUNET_SCHEDULER_add_delayed (offset, &send_flood_message, NULL);
509 * Check whether the given public key
510 * and integer are a valid proof of work.
512 * @param pkey the public key
513 * @param val the integer
514 * @param want the number of trailing zeroes
516 * @return GNUNET_YES if valid, GNUNET_NO if not
518 static int check_proof_of_work(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey, uint64_t val, unsigned int want)
525 * Count the trailing zeroes in hash.
529 * @return the number of trailing zero bits.
531 static unsigned int count_trailing_zeroes(GNUNET_HashCode *hash)
533 unsigned int hash_count;
535 hash_count = sizeof(GNUNET_HashCode) * 8;
536 while ((0 == GNUNET_CRYPTO_hash_get_bit(hash, hash_count)))
538 return (sizeof(GNUNET_HashCode) * 8) - hash_count;
542 * Given a public key, find an integer such that
543 * the hash of the key concatenated with the integer
544 * has <param>want</param> trailing 0 bits.
546 * @param pkey the public key
547 * @param want the number of trailing 0 bits
549 * @return 64 bit number that satisfies the
552 * FIXME: use pointer and return GNUNET_YES or
553 * GNUNET_NO in case no such number works?
555 static uint64_t find_proof_of_work(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey, unsigned int want)
558 static char buf[sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof(uint64_t)];
559 unsigned int data_size;
560 static GNUNET_HashCode result;
562 data_size = sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof(uint64_t);
563 memcpy(buf, pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
565 while (counter != (uint64_t)-1)
567 memcpy(&buf[sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)], &counter, sizeof(uint64_t));
568 GNUNET_CRYPTO_hash(buf, data_size, &result);
569 if (want == count_trailing_zeroes(&result)) /* Found good proof of work! */
573 if (counter < (uint64_t)-1)
574 return counter; /* Found valid proof of work */
576 return 0; /* Did not find valid proof of work */
580 * An incoming flood message has been received which claims
581 * to have more bits matching than any we know in this time
582 * period. Verify the signature and/or proof of work.
584 * @param incoming_flood the message to verify
586 * @return GNUNET_YES if the message is verified
587 * GNUNET_NO if the key/signature don't verify
589 static int verify_message_crypto(struct GNUNET_NSE_FloodMessage *incoming_flood)
592 if (GNUNET_OK == (ret
593 = GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND,
594 &incoming_flood->purpose,
595 &incoming_flood->signature,
596 &incoming_flood->pkey)))
604 * Core handler for size estimate flooding messages.
606 * @param cls closure unused
607 * @param message message
608 * @param peer peer identity this message is from (ignored)
609 * @param atsi performance data (ignored)
613 handle_p2p_size_estimate(void *cls, const struct GNUNET_PeerIdentity *peer,
614 const struct GNUNET_MessageHeader *message,
615 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
617 struct GNUNET_NSE_FloodMessage *incoming_flood;
618 struct GNUNET_TIME_Absolute curr_time;
622 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: received flood message!\n",
623 GNUNET_i2s (&my_identity));
625 if (ntohs (message->size) != sizeof(struct GNUNET_NSE_FloodMessage))
627 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: bad message size!\n",
628 GNUNET_i2s (&my_identity));
632 GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO);
633 incoming_flood = (struct GNUNET_NSE_FloodMessage *) message;
634 if (ntohl (incoming_flood->distance)
635 <= ntohl (size_estimate_messages[estimate_index].distance)) /* Not closer than our most recent message */
638 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
639 "%s: distance %d not greater than %d, discarding\n",
640 GNUNET_i2s (&my_identity), ntohl (incoming_flood->distance),
641 ntohl (size_estimate_messages[estimate_index].distance));
643 GNUNET_STATISTICS_update (stats,
644 "# flood messages discarded (had closer)", 1,
649 curr_time = GNUNET_TIME_absolute_get ();
650 if (curr_time.abs_value
651 > GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value)
652 drift = curr_time.abs_value
653 - GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value;
655 drift = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value
656 - curr_time.abs_value;
658 if (drift > GNUNET_NSE_DRIFT_TOLERANCE)
660 GNUNET_STATISTICS_update (
662 "# flood messages discarded (clock skew too high)",
668 if (GNUNET_YES != verify_message_crypto(incoming_flood))
670 GNUNET_STATISTICS_update (stats,
671 "# flood messages discarded (bad crypto)",
677 /* Have a new, better size estimate! */
678 update_network_size_estimate (incoming_flood);
680 if (flood_task != GNUNET_SCHEDULER_NO_TASK)
683 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: received closer message, canceling my flood task!\n", GNUNET_i2s(&my_identity));
685 GNUNET_SCHEDULER_cancel (flood_task);
686 flood_task = GNUNET_SCHEDULER_NO_TASK;
689 /** Commenting out prevents forwarding of messages */
691 GNUNET_SCHEDULER_add_now(&send_flood_message, &size_estimate_messages[estimate_index]);
693 if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK)
694 GNUNET_SCHEDULER_cancel (schedule_flood_task);
697 = GNUNET_SCHEDULER_add_delayed (
698 GNUNET_TIME_absolute_get_remaining (
700 &schedule_flood_message, NULL);
706 * Send a flood message.
708 * If we've gotten here, it means either we haven't received
709 * a network size estimate message closer than ours, or
710 * we need to forward a message we received which was closer
714 send_flood_message(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
716 struct NSEPeerEntry *peer_entry;
717 struct GNUNET_NSE_FloodMessage *to_send;
719 if (cls == NULL) /* Means we are sending our OWN flood message */
720 to_send = &flood_message;
722 /* Received a message from another peer that should be forwarded */
723 to_send = (struct GNUNET_NSE_FloodMessage *) cls;
725 flood_task = GNUNET_SCHEDULER_NO_TASK;
726 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
729 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
730 "%s: my time has come, sending flood message of size %d!\n",
731 GNUNET_i2s (&my_identity), ntohs (to_send->header.size));
733 peer_entry = peers_head;
735 while (peer_entry != NULL)
737 peer_entry->pending_message = &to_send->header;
739 = GNUNET_CORE_notify_transmit_ready (
742 DEFAULT_NSE_PRIORITY,
743 GNUNET_TIME_absolute_get_remaining (
746 ntohs (to_send->header.size),
747 &transmit_ready, peer_entry);
748 if (peer_entry->th == NULL)
749 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
750 "%s: transmit handle is null!\n", GNUNET_i2s (&my_identity));
752 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
753 "%s: Sending flood message (distance %d) to %s!\n",
754 GNUNET_i2s (&my_identity), ntohl (to_send->distance),
755 GNUNET_h2s (&peer_entry->id.hashPubKey));
757 peer_entry = peer_entry->next;
760 if (cls == NULL) /* Need to update our size estimate */
762 update_network_size_estimate (to_send);
763 GNUNET_STATISTICS_update (stats, "# flood messages sent", 1, GNUNET_NO);
766 GNUNET_STATISTICS_update (stats, "# flood messages forwarded", 1, GNUNET_NO);
769 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
770 "%s: scheduling schedule_flood_message in %lu\n",
771 GNUNET_i2s (&my_identity),
772 GNUNET_TIME_absolute_get_remaining (next_timestamp).rel_value);
774 if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK)
775 GNUNET_SCHEDULER_cancel (schedule_flood_task);
778 = GNUNET_SCHEDULER_add_delayed (
779 GNUNET_TIME_absolute_get_remaining (
781 &schedule_flood_message, NULL);
785 * Method called whenever a peer connects.
788 * @param peer peer identity this notification is about
789 * @param atsi performance data
792 handle_core_connect(void *cls, const struct GNUNET_PeerIdentity *peer,
793 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
795 struct NSEPeerEntry *peer_entry;
797 if (0 == (memcmp (peer, &my_identity, sizeof(struct GNUNET_PeerIdentity))))
798 return; /* Do not connect to self... */
800 peer_entry = GNUNET_malloc(sizeof(struct NSEPeerEntry));
801 memcpy (&peer_entry->id, peer, sizeof(struct GNUNET_PeerIdentity));
802 GNUNET_CONTAINER_DLL_insert(peers_head, peers_tail, peer_entry);
806 * Method called whenever a peer disconnects.
809 * @param peer peer identity this notification is about
812 handle_core_disconnect(void *cls, const struct GNUNET_PeerIdentity *peer)
814 struct NSEPeerEntry *pos;
816 if (0 == (memcmp (peer, &my_identity, sizeof(struct GNUNET_PeerIdentity))))
817 return; /* Ignore disconnect from self... */
820 while ((NULL != pos) && (0 != memcmp (&pos->id, peer,
821 sizeof(struct GNUNET_PeerIdentity))))
825 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
826 "Received disconnect before connect!\n");
827 GNUNET_break(0); /* Should never receive a disconnect message for a peer we don't know about... */
831 /* TODO: decide whether to copy the message, or always use the static pointer */
833 if (pos->pending_message != NULL)
834 GNUNET_free(pos->pending_message);
838 GNUNET_CORE_notify_transmit_ready_cancel (pos->th);
839 GNUNET_CONTAINER_DLL_remove(peers_head, peers_tail, pos);
844 * A client disconnected. Remove it from the
845 * global DLL of clients.
847 * @param cls closure, NULL
848 * @param client identification of the client
851 handle_client_disconnect(void *cls, struct GNUNET_SERVER_Client* client)
853 struct ClientListEntry *cle;
855 while (NULL != (cle = cle_head))
860 GNUNET_SERVER_client_drop (cle->client);
861 GNUNET_CONTAINER_DLL_remove(cle_head,
868 GNUNET_CORE_disconnect (coreAPI);
874 * Task run during shutdown.
880 shutdown_task(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
882 struct ClientListEntry *cle;
884 if (flood_task != GNUNET_SCHEDULER_NO_TASK)
885 GNUNET_SCHEDULER_cancel (flood_task);
886 GNUNET_SERVER_notification_context_destroy (nc);
888 while (NULL != (cle = cle_head))
890 GNUNET_SERVER_client_drop (cle->client);
891 GNUNET_CONTAINER_DLL_remove (cle_head,
899 GNUNET_CORE_disconnect (coreAPI);
904 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
909 * Called on core init/fail.
911 * @param cls service closure
912 * @param server handle to the server for this service
913 * @param identity the public identity of this peer
914 * @param publicKey the public key of this peer
917 core_init(void *cls, struct GNUNET_CORE_Handle *server,
918 const struct GNUNET_PeerIdentity *identity,
919 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
921 struct GNUNET_TIME_Absolute curr_time;
925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Connection to core FAILED!\n",
926 "nse", GNUNET_i2s (identity));
928 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
932 /* Copy our identity so we can use it */
933 memcpy (&my_identity, identity, sizeof(struct GNUNET_PeerIdentity));
934 /* Copy our public key for inclusion in flood messages */
935 memcpy (&my_public_key, publicKey,
936 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
938 if (flood_task != GNUNET_SCHEDULER_NO_TASK)
939 GNUNET_SCHEDULER_cancel (flood_task);
941 /* Get the current UTC time */
942 curr_time = GNUNET_TIME_absolute_get ();
943 /* Find the previous interval start time */
944 previous_timestamp.abs_value = (curr_time.abs_value / GNUNET_NSE_INTERVAL)
945 * GNUNET_NSE_INTERVAL;
946 /* Find the next interval start time */
947 next_timestamp.abs_value = previous_timestamp.abs_value + GNUNET_NSE_INTERVAL;
950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
951 "%s: Core connection initialized, I am peer: %s, scheduling flood task in %lu\n", "nse",
952 GNUNET_i2s (identity), GNUNET_TIME_absolute_get_remaining(next_timestamp));
954 /* FIXME: In production, we'd likely want to do this immediately, but in test-beds it causes stupid behavior */
955 if (schedule_flood_task != GNUNET_SCHEDULER_NO_TASK)
956 GNUNET_SCHEDULER_cancel (schedule_flood_task);
958 = GNUNET_SCHEDULER_add_delayed (
959 GNUNET_TIME_absolute_get_remaining (
961 &schedule_flood_message, NULL);
963 GNUNET_SERVER_notification_context_broadcast (
965 ¤t_estimate_message.header,
970 * Handle network size estimate clients.
973 * @param server the initialized server
974 * @param c configuration to use
977 run(void *cls, struct GNUNET_SERVER_Handle *server,
978 const struct GNUNET_CONFIGURATION_Handle *c)
981 static const struct GNUNET_SERVER_MessageHandler handlers[] =
983 { &handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START, 0 },
984 { NULL, NULL, 0, 0 } };
986 static const struct GNUNET_CORE_MessageHandler core_handlers[] =
988 { &handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD, 0 },
994 != GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY",
997 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _
998 ("NSE service is lacking key configuration settings. Exiting.\n"));
999 GNUNET_SCHEDULER_shutdown ();
1003 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1004 GNUNET_free (keyfile);
1005 if (my_private_key == NULL)
1007 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1008 _("NSE Service could not access hostkey. Exiting.\n"));
1009 GNUNET_SCHEDULER_shutdown ();
1013 GNUNET_SERVER_add_handlers (server, handlers);
1014 nc = GNUNET_SERVER_notification_context_create (server, 16);
1015 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1017 flood_task = GNUNET_SCHEDULER_NO_TASK;
1018 /** Connect to core service and register core handlers */
1019 coreAPI = GNUNET_CORE_connect (cfg, /* Main configuration */
1020 DEFAULT_CORE_QUEUE_SIZE, /* queue size */
1021 NULL, /* Closure passed to functions */
1022 &core_init, /* Call core_init once connected */
1023 &handle_core_connect, /* Handle connects */
1024 &handle_core_disconnect, /* Handle disconnects */
1025 NULL, /* Do we care about "status" updates? */
1026 NULL, /* Don't want notified about all incoming messages */
1027 GNUNET_NO, /* For header only inbound notification */
1028 NULL, /* Don't want notified about all outbound messages */
1029 GNUNET_NO, /* For header only outbound notification */
1030 core_handlers); /* Register these handlers */
1032 if (coreAPI == NULL)
1034 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1038 stats = GNUNET_STATISTICS_create ("NSE", cfg);
1041 = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
1043 / (sizeof(GNUNET_HashCode) * 8));
1044 /* Set we have no idea defaults for network size estimate */
1045 current_size_estimate = 0.0;
1046 current_std_dev = NAN;
1047 size_estimates[estimate_index] = 0;
1048 current_estimate_message.header.size
1049 = htons (sizeof(struct GNUNET_NSE_ClientMessage));
1050 current_estimate_message.header.type
1051 = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE);
1052 current_estimate_message.size_estimate = current_size_estimate;
1053 current_estimate_message.std_deviation = current_std_dev;
1054 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1059 * The main function for the statistics service.
1061 * @param argc number of arguments from the command line
1062 * @param argv command line arguments
1063 * @return 0 ok, 1 on error
1066 main(int argc, char * const *argv)
1068 return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "nse",
1069 GNUNET_SERVICE_OPTION_NONE, &run,
1073 /* End of gnunet-service-nse.c */