2 This file is part of GNUnet.
3 Copyright (C) 2009-2017 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @file dht/gnunet-service-dht_neighbours.c
21 * @brief GNUnet DHT service's bucket and neighbour management code
22 * @author Christian Grothoff
23 * @author Nathan Evans
26 #include "gnunet_util_lib.h"
27 #include "gnunet_block_lib.h"
28 #include "gnunet_hello_lib.h"
29 #include "gnunet_constants.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_nse_service.h"
32 #include "gnunet_ats_service.h"
33 #include "gnunet_core_service.h"
34 #include "gnunet_datacache_lib.h"
35 #include "gnunet_transport_service.h"
36 #include "gnunet_hello_lib.h"
37 #include "gnunet_dht_service.h"
38 #include "gnunet_statistics_service.h"
39 #include "gnunet-service-dht.h"
40 #include "gnunet-service-dht_datacache.h"
41 #include "gnunet-service-dht_hello.h"
42 #include "gnunet-service-dht_neighbours.h"
43 #include "gnunet-service-dht_nse.h"
44 #include "gnunet-service-dht_routing.h"
47 #define LOG_TRAFFIC(kind,...) GNUNET_log_from (kind, "dht-traffic",__VA_ARGS__)
50 * Enable slow sanity checks to debug issues.
52 #define SANITY_CHECKS 1
55 * How many buckets will we allow total.
57 #define MAX_BUCKETS sizeof (struct GNUNET_HashCode) * 8
60 * What is the maximum number of peers in a given bucket.
62 #define DEFAULT_BUCKET_SIZE 8
65 * Desired replication level for FIND PEER requests
67 #define FIND_PEER_REPLICATION_LEVEL 4
70 * Maximum allowed replication level for all requests.
72 #define MAXIMUM_REPLICATION_LEVEL 16
75 * Maximum allowed number of pending messages per peer.
77 #define MAXIMUM_PENDING_PER_PEER 64
80 * How long at least to wait before sending another find peer request.
82 #define DHT_MINIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
85 * How long at most to wait before sending another find peer request.
87 #define DHT_MAXIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 10)
90 * How long at most to wait for transmission of a GET request to another peer?
92 #define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
95 * Hello address expiration
97 extern struct GNUNET_TIME_Relative hello_expiration;
100 GNUNET_NETWORK_STRUCT_BEGIN
105 struct PeerPutMessage
108 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_PUT
110 struct GNUNET_MessageHeader header;
115 uint32_t options GNUNET_PACKED;
120 uint32_t type GNUNET_PACKED;
125 uint32_t hop_count GNUNET_PACKED;
128 * Replication level for this message
130 uint32_t desired_replication_level GNUNET_PACKED;
133 * Length of the PUT path that follows (if tracked).
135 uint32_t put_path_length GNUNET_PACKED;
138 * When does the content expire?
140 struct GNUNET_TIME_AbsoluteNBO expiration_time;
143 * Bloomfilter (for peer identities) to stop circular routes
145 char bloomfilter[DHT_BLOOM_SIZE];
148 * The key we are storing under.
150 struct GNUNET_HashCode key;
152 /* put path (if tracked) */
162 struct PeerResultMessage
165 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT
167 struct GNUNET_MessageHeader header;
172 uint32_t type GNUNET_PACKED;
175 * Length of the PUT path that follows (if tracked).
177 uint32_t put_path_length GNUNET_PACKED;
180 * Length of the GET path that follows (if tracked).
182 uint32_t get_path_length GNUNET_PACKED;
185 * When does the content expire?
187 struct GNUNET_TIME_AbsoluteNBO expiration_time;
190 * The key of the corresponding GET request.
192 struct GNUNET_HashCode key;
194 /* put path (if tracked) */
196 /* get path (if tracked) */
206 struct PeerGetMessage
209 * Type: #GNUNET_MESSAGE_TYPE_DHT_P2P_GET
211 struct GNUNET_MessageHeader header;
216 uint32_t options GNUNET_PACKED;
219 * Desired content type.
221 uint32_t type GNUNET_PACKED;
226 uint32_t hop_count GNUNET_PACKED;
229 * Desired replication level for this request.
231 uint32_t desired_replication_level GNUNET_PACKED;
234 * Size of the extended query.
236 uint32_t xquery_size;
239 * Bloomfilter mutator.
244 * Bloomfilter (for peer identities) to stop circular routes
246 char bloomfilter[DHT_BLOOM_SIZE];
249 * The key we are looking for.
251 struct GNUNET_HashCode key;
255 /* result bloomfilter */
258 GNUNET_NETWORK_STRUCT_END
262 * Entry for a peer in a bucket.
267 * Next peer entry (DLL)
269 struct PeerInfo *next;
272 * Prev peer entry (DLL)
274 struct PeerInfo *prev;
277 * Handle for sending messages to this peer.
279 struct GNUNET_MQ_Handle *mq;
282 * What is the identity of the peer?
284 const struct GNUNET_PeerIdentity *id;
289 struct GNUNET_HashCode phash;
292 * Which bucket is this peer in?
300 * Peers are grouped into buckets.
307 struct PeerInfo *head;
312 struct PeerInfo *tail;
315 * Number of peers in the bucket.
317 unsigned int peers_size;
322 * Information about a peer that we would like to connect to.
328 * Handle to active HELLO offer operation, or NULL.
330 struct GNUNET_TRANSPORT_OfferHelloHandle *oh;
333 * Handle to active connectivity suggestion operation, or NULL.
335 struct GNUNET_ATS_ConnectivitySuggestHandle *sh;
338 * How much would we like to connect to this peer?
345 * Do we cache all results that we are routing in the local datacache?
347 static int cache_results;
350 * Should routing details be logged to stderr (for debugging)?
352 static int log_route_details_stderr;
355 * The lowest currently used bucket, initially 0 (for 0-bits matching bucket).
357 static unsigned int closest_bucket;
360 * How many peers have we added since we sent out our last
363 static unsigned int newly_found_peers;
366 * Option for testing that disables the 'connect' function of the DHT.
368 static int disable_try_connect;
371 * The buckets. Array of size #MAX_BUCKETS. Offset 0 means 0 bits matching.
373 static struct PeerBucket k_buckets[MAX_BUCKETS];
376 * Hash map of all CORE-connected peers, for easy removal from
377 * #k_buckets on disconnect. Values are of type `struct PeerInfo`.
379 static struct GNUNET_CONTAINER_MultiPeerMap *all_connected_peers;
382 * Hash map of all peers we would like to be connected to.
383 * Values are of type `struct ConnectInfo`.
385 static struct GNUNET_CONTAINER_MultiPeerMap *all_desired_peers;
388 * Maximum size for each bucket.
390 static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
393 * Task that sends FIND PEER requests.
395 static struct GNUNET_SCHEDULER_Task *find_peer_task;
398 * Identity of this peer.
400 static struct GNUNET_PeerIdentity my_identity;
403 * Hash of the identity of this peer.
405 struct GNUNET_HashCode my_identity_hash;
410 static struct GNUNET_CORE_Handle *core_api;
413 * Handle to ATS connectivity.
415 static struct GNUNET_ATS_ConnectivityHandle *ats_ch;
419 * Find the optimal bucket for this key.
421 * @param hc the hashcode to compare our identity to
422 * @return the proper bucket index, or #GNUNET_SYSERR
423 * on error (same hashcode)
426 find_bucket (const struct GNUNET_HashCode *hc)
430 bits = GNUNET_CRYPTO_hash_matching_bits (&my_identity_hash, hc);
431 if (bits == MAX_BUCKETS)
433 /* How can all bits match? Got my own ID? */
435 return GNUNET_SYSERR;
437 return MAX_BUCKETS - bits - 1;
442 * Function called when #GNUNET_TRANSPORT_offer_hello() is done.
443 * Clean up the "oh" field in the @a cls
445 * @param cls a `struct ConnectInfo`
448 offer_hello_done (void *cls)
450 struct ConnectInfo *ci = cls;
457 * Function called for all entries in #all_desired_peers to clean up.
460 * @param peer peer the entry is for
461 * @param value the value to remove
462 * @return #GNUNET_YES
465 free_connect_info (void *cls,
466 const struct GNUNET_PeerIdentity *peer,
469 struct ConnectInfo *ci = value;
471 GNUNET_assert (GNUNET_YES ==
472 GNUNET_CONTAINER_multipeermap_remove (all_desired_peers,
477 GNUNET_ATS_connectivity_suggest_cancel (ci->sh);
482 GNUNET_TRANSPORT_offer_hello_cancel (ci->oh);
491 * Consider if we want to connect to a given peer, and if so
492 * let ATS know. If applicable, the HELLO is offered to the
495 * @param pid peer to consider connectivity requirements for
496 * @param h a HELLO message, or NULL
499 try_connect (const struct GNUNET_PeerIdentity *pid,
500 const struct GNUNET_MessageHeader *h)
503 struct GNUNET_HashCode pid_hash;
504 struct ConnectInfo *ci;
507 GNUNET_CRYPTO_hash (pid,
508 sizeof (struct GNUNET_PeerIdentity),
510 bucket = find_bucket (&pid_hash);
513 ci = GNUNET_CONTAINER_multipeermap_get (all_desired_peers,
516 if (k_buckets[bucket].peers_size < bucket_size)
517 strength = (bucket_size - k_buckets[bucket].peers_size) * bucket;
519 strength = bucket; /* minimum value of connectivity */
521 GNUNET_CONTAINER_multipeermap_contains (all_connected_peers,
523 strength *= 2; /* double for connected peers */
524 else if (k_buckets[bucket].peers_size > bucket_size)
525 strength = 0; /* bucket full, we really do not care about more */
527 if ( (0 == strength) &&
530 /* release request */
531 GNUNET_assert (GNUNET_YES ==
532 free_connect_info (NULL,
539 ci = GNUNET_new (struct ConnectInfo);
540 GNUNET_assert (GNUNET_OK ==
541 GNUNET_CONTAINER_multipeermap_put (all_desired_peers,
544 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
546 if ( (NULL != ci->oh) &&
548 GNUNET_TRANSPORT_offer_hello_cancel (ci->oh);
550 ci->oh = GNUNET_TRANSPORT_offer_hello (GDS_cfg,
554 if ( (NULL != ci->sh) &&
555 (ci->strength != strength) )
556 GNUNET_ATS_connectivity_suggest_cancel (ci->sh);
557 if (ci->strength != strength)
558 ci->sh = GNUNET_ATS_connectivity_suggest (ats_ch,
561 ci->strength = strength;
566 * Function called for each peer in #all_desired_peers during
567 * #update_connect_preferences() if we have reason to adjust
568 * the strength of our desire to keep connections to certain
569 * peers. Calls #try_connect() to update the calculations for
573 * @param pid peer to update
574 * @param value unused
575 * @return #GNUNET_YES (continue to iterate)
578 update_desire_strength (void *cls,
579 const struct GNUNET_PeerIdentity *pid,
582 try_connect (pid, NULL);
588 * Update our preferences for connectivity as given to ATS.
590 * @param cls the `struct PeerInfo` of the peer
591 * @param tc scheduler context.
594 update_connect_preferences ()
596 GNUNET_CONTAINER_multipeermap_iterate (all_desired_peers,
597 &update_desire_strength,
603 * Add each of the peers we already know to the bloom filter of
604 * the request so that we don't get duplicate HELLOs.
606 * @param cls the `struct GNUNET_BLOCK_Group`
607 * @param key peer identity to add to the bloom filter
608 * @param value value the peer information (unused)
609 * @return #GNUNET_YES (we should continue to iterate)
612 add_known_to_bloom (void *cls,
613 const struct GNUNET_PeerIdentity *key,
616 struct GNUNET_BLOCK_Group *bg = cls;
617 struct GNUNET_HashCode key_hash;
619 GNUNET_CRYPTO_hash (key,
620 sizeof (struct GNUNET_PeerIdentity),
622 GNUNET_BLOCK_group_set_seen (bg,
625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
626 "Adding known peer (%s) to bloomfilter for FIND PEER\n",
633 * Task to send a find peer message for our own peer identifier
634 * so that we can find the closest peers in the network to ourselves
635 * and attempt to connect to them.
637 * @param cls closure for this task
640 send_find_peer_message (void *cls)
642 struct GNUNET_TIME_Relative next_send_time;
643 struct GNUNET_BLOCK_Group *bg;
644 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
646 find_peer_task = NULL;
647 if (newly_found_peers > bucket_size)
649 /* If we are finding many peers already, no need to send out our request right now! */
651 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
652 &send_find_peer_message,
654 newly_found_peers = 0;
657 bg = GNUNET_BLOCK_group_create (GDS_block_context,
658 GNUNET_BLOCK_TYPE_DHT_HELLO,
659 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
666 GNUNET_CONTAINER_multipeermap_iterate (all_connected_peers,
669 GNUNET_STATISTICS_update (GDS_stats,
670 gettext_noop ("# FIND PEER messages initiated"),
674 = GNUNET_CONTAINER_bloomfilter_init (NULL,
676 GNUNET_CONSTANTS_BLOOMFILTER_K);
677 // FIXME: pass priority!?
678 GDS_NEIGHBOURS_handle_get (GNUNET_BLOCK_TYPE_DHT_HELLO,
679 GNUNET_DHT_RO_FIND_PEER | GNUNET_DHT_RO_RECORD_ROUTE,
680 FIND_PEER_REPLICATION_LEVEL,
687 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
688 GNUNET_BLOCK_group_destroy (bg);
689 /* schedule next round */
690 next_send_time.rel_value_us =
691 DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value_us +
692 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
693 DHT_MAXIMUM_FIND_PEER_INTERVAL.rel_value_us /
694 (newly_found_peers + 1));
695 newly_found_peers = 0;
696 GNUNET_assert (NULL == find_peer_task);
698 GNUNET_SCHEDULER_add_delayed (next_send_time,
699 &send_find_peer_message,
705 * Method called whenever a peer connects.
708 * @param peer peer identity this notification is about
709 * @param mq message queue for sending messages to @a peer
710 * @return our `struct PeerInfo` for @a peer
713 handle_core_connect (void *cls,
714 const struct GNUNET_PeerIdentity *peer,
715 struct GNUNET_MQ_Handle *mq)
719 /* Check for connect to self message */
720 if (0 == memcmp (&my_identity,
722 sizeof (struct GNUNET_PeerIdentity)))
724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
727 GNUNET_assert (GNUNET_NO ==
728 GNUNET_CONTAINER_multipeermap_get (all_connected_peers,
730 GNUNET_STATISTICS_update (GDS_stats,
731 gettext_noop ("# peers connected"),
734 pi = GNUNET_new (struct PeerInfo);
737 GNUNET_CRYPTO_hash (peer,
738 sizeof (struct GNUNET_PeerIdentity),
740 pi->peer_bucket = find_bucket (&pi->phash);
741 GNUNET_assert ( (pi->peer_bucket >= 0) &&
742 (pi->peer_bucket < MAX_BUCKETS) );
743 GNUNET_CONTAINER_DLL_insert_tail (k_buckets[pi->peer_bucket].head,
744 k_buckets[pi->peer_bucket].tail,
746 k_buckets[pi->peer_bucket].peers_size++;
747 closest_bucket = GNUNET_MAX (closest_bucket,
749 GNUNET_assert (GNUNET_OK ==
750 GNUNET_CONTAINER_multipeermap_put (all_connected_peers,
753 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
754 if ( (pi->peer_bucket > 0) &&
755 (k_buckets[pi->peer_bucket].peers_size <= bucket_size))
757 update_connect_preferences ();
760 if ( (1 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
761 (GNUNET_YES != disable_try_connect))
763 /* got a first connection, good time to start with FIND PEER requests... */
764 GNUNET_assert (NULL == find_peer_task);
765 find_peer_task = GNUNET_SCHEDULER_add_now (&send_find_peer_message,
773 * Method called whenever a peer disconnects.
776 * @param peer peer identity this notification is about
777 * @param internal_cls our `struct PeerInfo` for @a peer
780 handle_core_disconnect (void *cls,
781 const struct GNUNET_PeerIdentity *peer,
784 struct PeerInfo *to_remove = internal_cls;
786 /* Check for disconnect from self message */
787 if (NULL == to_remove)
789 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
792 GNUNET_STATISTICS_update (GDS_stats,
793 gettext_noop ("# peers connected"),
796 GNUNET_assert (GNUNET_YES ==
797 GNUNET_CONTAINER_multipeermap_remove (all_connected_peers,
800 if ( (0 == GNUNET_CONTAINER_multipeermap_size (all_connected_peers)) &&
801 (GNUNET_YES != disable_try_connect) )
803 GNUNET_SCHEDULER_cancel (find_peer_task);
804 find_peer_task = NULL;
806 GNUNET_assert (to_remove->peer_bucket >= 0);
807 GNUNET_CONTAINER_DLL_remove (k_buckets[to_remove->peer_bucket].head,
808 k_buckets[to_remove->peer_bucket].tail,
810 GNUNET_assert (k_buckets[to_remove->peer_bucket].peers_size > 0);
811 k_buckets[to_remove->peer_bucket].peers_size--;
812 while ( (closest_bucket > 0) &&
813 (0 == k_buckets[to_remove->peer_bucket].peers_size) )
815 if (k_buckets[to_remove->peer_bucket].peers_size < bucket_size)
816 update_connect_preferences ();
817 GNUNET_free (to_remove);
822 * To how many peers should we (on average) forward the request to
823 * obtain the desired target_replication count (on average).
825 * @param hop_count number of hops the message has traversed
826 * @param target_replication the number of total paths desired
827 * @return Some number of peers to forward the message to
830 get_forward_count (uint32_t hop_count,
831 uint32_t target_replication)
833 uint32_t random_value;
834 uint32_t forward_count;
837 if (hop_count > GDS_NSE_get () * 4.0)
839 /* forcefully terminate */
840 GNUNET_STATISTICS_update (GDS_stats,
841 gettext_noop ("# requests TTL-dropped"),
845 if (hop_count > GDS_NSE_get () * 2.0)
847 /* Once we have reached our ideal number of hops, only forward to 1 peer */
850 /* bound by system-wide maximum */
852 GNUNET_MIN (MAXIMUM_REPLICATION_LEVEL, target_replication);
854 1 + (target_replication - 1.0) / (GDS_NSE_get () +
855 ((float) (target_replication - 1.0) *
857 /* Set forward count to floor of target_value */
858 forward_count = (uint32_t) target_value;
859 /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
860 target_value = target_value - forward_count;
862 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
863 if (random_value < (target_value * UINT32_MAX))
865 return forward_count;
870 * Compute the distance between have and target as a 32-bit value.
871 * Differences in the lower bits must count stronger than differences
872 * in the higher bits.
876 * @return 0 if have==target, otherwise a number
877 * that is larger as the distance between
878 * the two hash codes increases
881 get_distance (const struct GNUNET_HashCode *target,
882 const struct GNUNET_HashCode *have)
889 /* We have to represent the distance between two 2^9 (=512)-bit
890 * numbers as a 2^5 (=32)-bit number with "0" being used for the
891 * two numbers being identical; furthermore, we need to
892 * guarantee that a difference in the number of matching
893 * bits is always represented in the result.
895 * We use 2^32/2^9 numerical values to distinguish between
896 * hash codes that have the same LSB bit distance and
897 * use the highest 2^9 bits of the result to signify the
898 * number of (mis)matching LSB bits; if we have 0 matching
899 * and hence 512 mismatching LSB bits we return -1 (since
900 * 512 itself cannot be represented with 9 bits) */
902 /* first, calculate the most significant 9 bits of our
903 * result, aka the number of LSBs */
904 bucket = GNUNET_CRYPTO_hash_matching_bits (target,
906 /* bucket is now a value between 0 and 512 */
908 return 0; /* perfect match */
910 return (unsigned int) -1; /* LSB differs; use max (if we did the bit-shifting
911 * below, we'd end up with max+1 (overflow)) */
913 /* calculate the most significant bits of the final result */
914 msb = (512 - bucket) << (32 - 9);
915 /* calculate the 32-9 least significant bits of the final result by
916 * looking at the differences in the 32-9 bits following the
917 * mismatching bit at 'bucket' */
920 (i < sizeof (struct GNUNET_HashCode) * 8) && (i < bucket + 1 + 32 - 9); i++)
922 if (GNUNET_CRYPTO_hash_get_bit (target, i) !=
923 GNUNET_CRYPTO_hash_get_bit (have, i))
924 lsb |= (1 << (bucket + 32 - 9 - i)); /* first bit set will be 10,
925 * last bit set will be 31 -- if
926 * i does not reach 512 first... */
933 * Check whether my identity is closer than any known peers. If a
934 * non-null bloomfilter is given, check if this is the closest peer
935 * that hasn't already been routed to.
937 * @param key hash code to check closeness to
938 * @param bloom bloomfilter, exclude these entries from the decision
939 * @return #GNUNET_YES if node location is closest,
940 * #GNUNET_NO otherwise.
943 GDS_am_closest_peer (const struct GNUNET_HashCode *key,
944 const struct GNUNET_CONTAINER_BloomFilter *bloom)
950 struct PeerInfo *pos;
952 if (0 == memcmp (&my_identity_hash, key, sizeof (struct GNUNET_HashCode)))
954 bucket_num = find_bucket (key);
955 GNUNET_assert (bucket_num >= 0);
956 bits = GNUNET_CRYPTO_hash_matching_bits (&my_identity_hash,
958 pos = k_buckets[bucket_num].head;
960 while ((NULL != pos) && (count < bucket_size))
962 if ((NULL != bloom) &&
964 GNUNET_CONTAINER_bloomfilter_test (bloom,
968 continue; /* Skip already checked entries */
970 other_bits = GNUNET_CRYPTO_hash_matching_bits (&pos->phash,
972 if (other_bits > bits)
974 if (other_bits == bits) /* We match the same number of bits */
978 /* No peers closer, we are the closest! */
984 * Select a peer from the routing table that would be a good routing
985 * destination for sending a message for "key". The resulting peer
986 * must not be in the set of blocked peers.<p>
988 * Note that we should not ALWAYS select the closest peer to the
989 * target, peers further away from the target should be chosen with
990 * exponentially declining probability.
992 * FIXME: double-check that this is fine
995 * @param key the key we are selecting a peer to route to
996 * @param bloom a bloomfilter containing entries this request has seen already
997 * @param hops how many hops has this message traversed thus far
998 * @return Peer to route to, or NULL on error
1000 static struct PeerInfo *
1001 select_peer (const struct GNUNET_HashCode *key,
1002 const struct GNUNET_CONTAINER_BloomFilter *bloom,
1007 unsigned int selected;
1008 struct PeerInfo *pos;
1010 unsigned int smallest_distance;
1011 struct PeerInfo *chosen;
1013 if (hops >= GDS_NSE_get ())
1015 /* greedy selection (closest peer that is not in bloomfilter) */
1016 smallest_distance = UINT_MAX;
1018 for (bc = 0; bc <= closest_bucket; bc++)
1020 pos = k_buckets[bc].head;
1022 while ((pos != NULL) && (count < bucket_size))
1024 if ( (NULL == bloom) ||
1026 GNUNET_CONTAINER_bloomfilter_test (bloom,
1029 dist = get_distance (key,
1031 if (dist < smallest_distance)
1034 smallest_distance = dist;
1039 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1040 "Excluded peer `%s' due to BF match in greedy routing for %s\n",
1041 GNUNET_i2s (pos->id),
1043 GNUNET_STATISTICS_update (GDS_stats,
1044 gettext_noop ("# Peers excluded from routing due to Bloomfilter"),
1047 dist = get_distance (key,
1049 if (dist < smallest_distance)
1052 smallest_distance = dist;
1060 GNUNET_STATISTICS_update (GDS_stats,
1061 gettext_noop ("# Peer selection failed"),
1065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1066 "Selected peer `%s' in greedy routing for %s\n",
1067 GNUNET_i2s (chosen->id),
1072 /* select "random" peer */
1073 /* count number of peers that are available and not filtered */
1075 for (bc = 0; bc <= closest_bucket; bc++)
1077 pos = k_buckets[bc].head;
1078 while ( (NULL != pos) && (count < bucket_size) )
1080 if ( (NULL != bloom) &&
1082 GNUNET_CONTAINER_bloomfilter_test (bloom,
1085 GNUNET_STATISTICS_update (GDS_stats,
1087 ("# Peers excluded from routing due to Bloomfilter"),
1089 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1090 "Excluded peer `%s' due to BF match in random routing for %s\n",
1091 GNUNET_i2s (pos->id),
1094 continue; /* Ignore bloomfiltered peers */
1100 if (0 == count) /* No peers to select from! */
1102 GNUNET_STATISTICS_update (GDS_stats,
1103 gettext_noop ("# Peer selection failed"), 1,
1107 /* Now actually choose a peer */
1108 selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1111 for (bc = 0; bc <= closest_bucket; bc++)
1113 for (pos = k_buckets[bc].head; ((pos != NULL) && (count < bucket_size)); pos = pos->next)
1115 if ((bloom != NULL) &&
1117 GNUNET_CONTAINER_bloomfilter_test (bloom,
1120 continue; /* Ignore bloomfiltered peers */
1122 if (0 == selected--)
1124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1125 "Selected peer `%s' in random routing for %s\n",
1126 GNUNET_i2s (pos->id),
1138 * Compute the set of peers that the given request should be
1141 * @param key routing key
1142 * @param bloom bloom filter excluding peers as targets, all selected
1143 * peers will be added to the bloom filter
1144 * @param hop_count number of hops the request has traversed so far
1145 * @param target_replication desired number of replicas
1146 * @param targets where to store an array of target peers (to be
1147 * free'd by the caller)
1148 * @return number of peers returned in 'targets'.
1151 get_target_peers (const struct GNUNET_HashCode *key,
1152 struct GNUNET_CONTAINER_BloomFilter *bloom,
1154 uint32_t target_replication,
1155 struct PeerInfo ***targets)
1159 struct PeerInfo **rtargets;
1160 struct PeerInfo *nxt;
1162 GNUNET_assert (NULL != bloom);
1163 ret = get_forward_count (hop_count,
1164 target_replication);
1170 rtargets = GNUNET_new_array (ret,
1172 for (off = 0; off < ret; off++)
1174 nxt = select_peer (key,
1179 rtargets[off] = nxt;
1180 GNUNET_break (GNUNET_NO ==
1181 GNUNET_CONTAINER_bloomfilter_test (bloom,
1183 GNUNET_CONTAINER_bloomfilter_add (bloom,
1186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1187 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1189 GNUNET_CONTAINER_multipeermap_size (all_connected_peers),
1190 (unsigned int) hop_count,
1195 GNUNET_free (rtargets);
1199 *targets = rtargets;
1200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1201 "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1210 * Perform a PUT operation. Forwards the given request to other
1211 * peers. Does not store the data locally. Does not give the
1212 * data to local clients. May do nothing if this is the only
1213 * peer in the network (or if we are the closest peer in the
1216 * @param type type of the block
1217 * @param options routing options
1218 * @param desired_replication_level desired replication count
1219 * @param expiration_time when does the content expire
1220 * @param hop_count how many hops has this message traversed so far
1221 * @param bf Bloom filter of peers this PUT has already traversed
1222 * @param key key for the content
1223 * @param put_path_length number of entries in @a put_path
1224 * @param put_path peers this request has traversed so far (if tracked)
1225 * @param data payload to store
1226 * @param data_size number of bytes in @a data
1227 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
1230 GDS_NEIGHBOURS_handle_put (enum GNUNET_BLOCK_Type type,
1231 enum GNUNET_DHT_RouteOption options,
1232 uint32_t desired_replication_level,
1233 struct GNUNET_TIME_Absolute expiration_time,
1235 struct GNUNET_CONTAINER_BloomFilter *bf,
1236 const struct GNUNET_HashCode *key,
1237 unsigned int put_path_length,
1238 struct GNUNET_PeerIdentity *put_path,
1242 unsigned int target_count;
1244 struct PeerInfo **targets;
1245 struct PeerInfo *target;
1247 struct GNUNET_MQ_Envelope *env;
1248 struct PeerPutMessage *ppm;
1249 struct GNUNET_PeerIdentity *pp;
1250 unsigned int skip_count;
1252 GNUNET_assert (NULL != bf);
1253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1254 "Adding myself (%s) to PUT bloomfilter for %s\n",
1255 GNUNET_i2s (&my_identity),
1257 GNUNET_CONTAINER_bloomfilter_add (bf,
1259 GNUNET_STATISTICS_update (GDS_stats,
1260 gettext_noop ("# PUT requests routed"),
1264 = get_target_peers (key,
1267 desired_replication_level,
1269 if (0 == target_count)
1271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1272 "Routing PUT for %s terminates after %u hops at %s\n",
1274 (unsigned int) hop_count,
1275 GNUNET_i2s (&my_identity));
1278 msize = put_path_length * sizeof (struct GNUNET_PeerIdentity) + data_size;
1279 if (msize + sizeof (struct PeerPutMessage)
1280 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1282 put_path_length = 0;
1285 if (msize + sizeof (struct PeerPutMessage)
1286 >= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)
1289 GNUNET_free (targets);
1292 GNUNET_STATISTICS_update (GDS_stats,
1293 gettext_noop ("# PUT messages queued for transmission"),
1297 for (i = 0; i < target_count; i++)
1299 target = targets[i];
1300 if (GNUNET_MQ_get_length (target->mq) >= MAXIMUM_PENDING_PER_PEER)
1303 GNUNET_STATISTICS_update (GDS_stats,
1304 gettext_noop ("# P2P messages dropped due to full queue"),
1310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1311 "Routing PUT for %s after %u hops to %s\n",
1313 (unsigned int) hop_count,
1314 GNUNET_i2s (target->id));
1315 env = GNUNET_MQ_msg_extra (ppm,
1317 GNUNET_MESSAGE_TYPE_DHT_P2P_PUT);
1318 ppm->options = htonl (options);
1319 ppm->type = htonl (type);
1320 ppm->hop_count = htonl (hop_count + 1);
1321 ppm->desired_replication_level = htonl (desired_replication_level);
1322 ppm->put_path_length = htonl (put_path_length);
1323 ppm->expiration_time = GNUNET_TIME_absolute_hton (expiration_time);
1324 GNUNET_break (GNUNET_YES ==
1325 GNUNET_CONTAINER_bloomfilter_test (bf,
1327 GNUNET_assert (GNUNET_OK ==
1328 GNUNET_CONTAINER_bloomfilter_get_raw_data (bf,
1332 pp = (struct GNUNET_PeerIdentity *) &ppm[1];
1335 sizeof (struct GNUNET_PeerIdentity) * put_path_length);
1336 GNUNET_memcpy (&pp[put_path_length],
1339 GNUNET_MQ_send (target->mq,
1342 GNUNET_free (targets);
1343 return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1348 * Perform a GET operation. Forwards the given request to other
1349 * peers. Does not lookup the key locally. May do nothing if this is
1350 * the only peer in the network (or if we are the closest peer in the
1353 * @param type type of the block
1354 * @param options routing options
1355 * @param desired_replication_level desired replication count
1356 * @param hop_count how many hops did this request traverse so far?
1357 * @param key key for the content
1358 * @param xquery extended query
1359 * @param xquery_size number of bytes in @a xquery
1360 * @param bg group to use for filtering replies
1361 * @param peer_bf filter for peers not to select (again)
1362 * @return #GNUNET_OK if the request was forwarded, #GNUNET_NO if not
1365 GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
1366 enum GNUNET_DHT_RouteOption options,
1367 uint32_t desired_replication_level,
1369 const struct GNUNET_HashCode *key,
1372 struct GNUNET_BLOCK_Group *bg,
1373 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
1375 unsigned int target_count;
1376 struct PeerInfo **targets;
1377 struct PeerInfo *target;
1378 struct GNUNET_MQ_Envelope *env;
1380 struct PeerGetMessage *pgm;
1382 size_t reply_bf_size;
1384 unsigned int skip_count;
1387 GNUNET_assert (NULL != peer_bf);
1388 GNUNET_STATISTICS_update (GDS_stats,
1389 gettext_noop ("# GET requests routed"),
1392 target_count = get_target_peers (key,
1395 desired_replication_level,
1397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1398 "Adding myself (%s) to GET bloomfilter for %s\n",
1399 GNUNET_i2s (&my_identity),
1401 GNUNET_CONTAINER_bloomfilter_add (peer_bf,
1403 if (0 == target_count)
1405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1406 "Routing GET for %s terminates after %u hops at %s\n",
1408 (unsigned int) hop_count,
1409 GNUNET_i2s (&my_identity));
1413 GNUNET_BLOCK_group_serialize (bg,
1420 bf_nonce = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1423 msize = xquery_size + reply_bf_size;
1424 if (msize + sizeof (struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1427 GNUNET_free_non_null (reply_bf);
1428 GNUNET_free (targets);
1431 GNUNET_STATISTICS_update (GDS_stats,
1432 gettext_noop ("# GET messages queued for transmission"),
1435 /* forward request */
1437 for (unsigned int i = 0; i < target_count; i++)
1439 target = targets[i];
1440 if (GNUNET_MQ_get_length (target->mq) >= MAXIMUM_PENDING_PER_PEER)
1443 GNUNET_STATISTICS_update (GDS_stats,
1444 gettext_noop ("# P2P messages dropped due to full queue"),
1449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1450 "Routing GET for %s after %u hops to %s\n",
1452 (unsigned int) hop_count,
1453 GNUNET_i2s (target->id));
1454 env = GNUNET_MQ_msg_extra (pgm,
1456 GNUNET_MESSAGE_TYPE_DHT_P2P_GET);
1457 pgm->options = htonl (options);
1458 pgm->type = htonl (type);
1459 pgm->hop_count = htonl (hop_count + 1);
1460 pgm->desired_replication_level = htonl (desired_replication_level);
1461 pgm->xquery_size = htonl (xquery_size);
1462 pgm->bf_mutator = bf_nonce;
1463 GNUNET_break (GNUNET_YES ==
1464 GNUNET_CONTAINER_bloomfilter_test (peer_bf,
1466 GNUNET_assert (GNUNET_OK ==
1467 GNUNET_CONTAINER_bloomfilter_get_raw_data (peer_bf,
1471 xq = (char *) &pgm[1];
1475 GNUNET_memcpy (&xq[xquery_size],
1478 GNUNET_MQ_send (target->mq,
1481 GNUNET_free (targets);
1482 GNUNET_free_non_null (reply_bf);
1483 return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1488 * Handle a reply (route to origin). Only forwards the reply back to
1489 * the given peer. Does not do local caching or forwarding to local
1492 * @param target neighbour that should receive the block (if still connected)
1493 * @param type type of the block
1494 * @param expiration_time when does the content expire
1495 * @param key key for the content
1496 * @param put_path_length number of entries in @a put_path
1497 * @param put_path peers the original PUT traversed (if tracked)
1498 * @param get_path_length number of entries in @a get_path
1499 * @param get_path peers this reply has traversed so far (if tracked)
1500 * @param data payload of the reply
1501 * @param data_size number of bytes in @a data
1504 GDS_NEIGHBOURS_handle_reply (const struct GNUNET_PeerIdentity *target,
1505 enum GNUNET_BLOCK_Type type,
1506 struct GNUNET_TIME_Absolute expiration_time,
1507 const struct GNUNET_HashCode *key,
1508 unsigned int put_path_length,
1509 const struct GNUNET_PeerIdentity *put_path,
1510 unsigned int get_path_length,
1511 const struct GNUNET_PeerIdentity *get_path,
1515 struct PeerInfo *pi;
1516 struct GNUNET_MQ_Envelope *env;
1518 struct PeerResultMessage *prm;
1519 struct GNUNET_PeerIdentity *paths;
1521 msize = data_size + (get_path_length + put_path_length) *
1522 sizeof (struct GNUNET_PeerIdentity);
1523 if ((msize + sizeof (struct PeerResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
1525 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
1527 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
1528 (data_size > GNUNET_MAX_MESSAGE_SIZE))
1533 pi = GNUNET_CONTAINER_multipeermap_get (all_connected_peers,
1537 /* peer disconnected in the meantime, drop reply */
1538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1539 "No matching peer for reply for key %s\n",
1543 if (GNUNET_MQ_get_length (pi->mq) >= MAXIMUM_PENDING_PER_PEER)
1546 GNUNET_STATISTICS_update (GDS_stats,
1547 gettext_noop ("# P2P messages dropped due to full queue"),
1550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1551 "Peer queue full, ignoring reply for key %s\n",
1556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1557 "Forwarding reply for key %s to peer %s\n",
1559 GNUNET_i2s (target));
1560 GNUNET_STATISTICS_update (GDS_stats,
1562 ("# RESULT messages queued for transmission"), 1,
1564 env = GNUNET_MQ_msg_extra (prm,
1566 GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT);
1567 prm->type = htonl (type);
1568 prm->put_path_length = htonl (put_path_length);
1569 prm->get_path_length = htonl (get_path_length);
1570 prm->expiration_time = GNUNET_TIME_absolute_hton (expiration_time);
1572 paths = (struct GNUNET_PeerIdentity *) &prm[1];
1573 GNUNET_memcpy (paths,
1575 put_path_length * sizeof (struct GNUNET_PeerIdentity));
1576 GNUNET_memcpy (&paths[put_path_length],
1578 get_path_length * sizeof (struct GNUNET_PeerIdentity));
1579 GNUNET_memcpy (&paths[put_path_length + get_path_length],
1582 GNUNET_MQ_send (pi->mq,
1588 * To be called on core init/fail.
1590 * @param cls service closure
1591 * @param identity the public identity of this peer
1594 core_init (void *cls,
1595 const struct GNUNET_PeerIdentity *identity)
1597 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1598 "CORE called, I am %s\n",
1599 GNUNET_i2s (identity));
1600 my_identity = *identity;
1601 GNUNET_CRYPTO_hash (identity,
1602 sizeof (struct GNUNET_PeerIdentity),
1604 GNUNET_SERVICE_resume (GDS_service);
1609 * Check validity of a p2p put request.
1611 * @param cls closure with the `struct PeerInfo` of the sender
1612 * @param message message
1613 * @return #GNUNET_OK if the message is valid
1616 check_dht_p2p_put (void *cls,
1617 const struct PeerPutMessage *put)
1622 msize = ntohs (put->header.size);
1623 putlen = ntohl (put->put_path_length);
1625 sizeof (struct PeerPutMessage) +
1626 putlen * sizeof (struct GNUNET_PeerIdentity)) ||
1628 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
1630 GNUNET_break_op (0);
1631 return GNUNET_SYSERR;
1638 * Core handler for p2p put requests.
1640 * @param cls closure with the `struct PeerInfo` of the sender
1641 * @param message message
1644 handle_dht_p2p_put (void *cls,
1645 const struct PeerPutMessage *put)
1647 struct PeerInfo *peer = cls;
1648 const struct GNUNET_PeerIdentity *put_path;
1649 const void *payload;
1652 size_t payload_size;
1653 enum GNUNET_DHT_RouteOption options;
1654 struct GNUNET_CONTAINER_BloomFilter *bf;
1655 struct GNUNET_HashCode test_key;
1658 msize = ntohs (put->header.size);
1659 putlen = ntohl (put->put_path_length);
1660 GNUNET_STATISTICS_update (GDS_stats,
1661 gettext_noop ("# P2P PUT requests received"),
1664 GNUNET_STATISTICS_update (GDS_stats,
1665 gettext_noop ("# P2P PUT bytes received"),
1668 put_path = (const struct GNUNET_PeerIdentity *) &put[1];
1669 payload = &put_path[putlen];
1670 options = ntohl (put->options);
1671 payload_size = msize - (sizeof (struct PeerPutMessage) +
1672 putlen * sizeof (struct GNUNET_PeerIdentity));
1674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1675 "PUT for `%s' from %s\n",
1676 GNUNET_h2s (&put->key),
1677 GNUNET_i2s (peer->id));
1678 if (GNUNET_YES == log_route_details_stderr)
1683 pp = GNUNET_STRINGS_pp2s (put_path,
1685 tmp = GNUNET_strdup (GNUNET_i2s (&my_identity));
1686 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
1687 "R5N PUT %s: %s->%s (%u, %u=>%u, PP: %s)\n",
1688 GNUNET_h2s (&put->key),
1689 GNUNET_i2s (peer->id),
1691 ntohl(put->hop_count),
1692 GNUNET_CRYPTO_hash_matching_bits (&peer->phash,
1694 GNUNET_CRYPTO_hash_matching_bits (&my_identity_hash,
1700 switch (GNUNET_BLOCK_get_key
1708 if (0 != memcmp (&test_key,
1710 sizeof (struct GNUNET_HashCode)))
1712 char *put_s = GNUNET_strdup (GNUNET_h2s_full (&put->key));
1714 GNUNET_break_op (0);
1715 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1716 "PUT with key `%s' for block with key %s\n",
1718 GNUNET_h2s_full (&test_key));
1719 GNUNET_free (put_s);
1724 GNUNET_break_op (0);
1727 /* cannot verify, good luck */
1730 if (ntohl (put->type) == GNUNET_BLOCK_TYPE_REGEX) /* FIXME: do for all tpyes */
1732 switch (GNUNET_BLOCK_evaluate (GDS_block_context,
1734 NULL, /* query group */
1735 GNUNET_BLOCK_EO_NONE,
1737 NULL, 0, /* xquery */
1741 case GNUNET_BLOCK_EVALUATION_OK_MORE:
1742 case GNUNET_BLOCK_EVALUATION_OK_LAST:
1745 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
1746 case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
1747 case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
1748 case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
1749 case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
1750 case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
1752 GNUNET_break_op (0);
1757 bf = GNUNET_CONTAINER_bloomfilter_init (put->bloomfilter,
1759 GNUNET_CONSTANTS_BLOOMFILTER_K);
1760 GNUNET_break_op (GNUNET_YES ==
1761 GNUNET_CONTAINER_bloomfilter_test (bf,
1764 struct GNUNET_PeerIdentity pp[putlen + 1];
1766 /* extend 'put path' by sender */
1767 if (0 != (options & GNUNET_DHT_RO_RECORD_ROUTE))
1770 for (unsigned int i=0;i<=putlen;i++)
1772 for (unsigned int j=0;j<i;j++)
1774 GNUNET_break (0 != memcmp (&pp[i],
1776 sizeof (struct GNUNET_PeerIdentity)));
1778 GNUNET_break (0 != memcmp (&pp[i],
1780 sizeof (struct GNUNET_PeerIdentity)));
1785 putlen * sizeof (struct GNUNET_PeerIdentity));
1786 pp[putlen] = *peer->id;
1792 /* give to local clients */
1793 GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (put->expiration_time),
1803 if ((0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
1804 (GDS_am_closest_peer (&put->key, bf)))
1805 GDS_DATACACHE_handle_put (GNUNET_TIME_absolute_ntoh (put->expiration_time),
1812 /* route to other peers */
1813 forwarded = GDS_NEIGHBOURS_handle_put (ntohl (put->type),
1815 ntohl (put->desired_replication_level),
1816 GNUNET_TIME_absolute_ntoh (put->expiration_time),
1817 ntohl (put->hop_count),
1824 /* notify monitoring clients */
1825 GDS_CLIENTS_process_put (options
1826 | ( (GNUNET_OK == forwarded)
1827 ? GNUNET_DHT_RO_LAST_HOP
1830 ntohl (put->hop_count),
1831 ntohl (put->desired_replication_level),
1833 GNUNET_TIME_absolute_ntoh (put->expiration_time),
1838 GNUNET_CONTAINER_bloomfilter_free (bf);
1843 * We have received a FIND PEER request. Send matching
1846 * @param sender sender of the FIND PEER request
1847 * @param key peers close to this key are desired
1848 * @param bg group for filtering peers
1851 handle_find_peer (const struct GNUNET_PeerIdentity *sender,
1852 const struct GNUNET_HashCode *key,
1853 struct GNUNET_BLOCK_Group *bg)
1856 struct PeerBucket *bucket;
1857 struct PeerInfo *peer;
1858 unsigned int choice;
1859 const struct GNUNET_HELLO_Message *hello;
1862 /* first, check about our own HELLO */
1863 if (NULL != GDS_my_hello)
1865 hello_size = GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message *) GDS_my_hello);
1866 GNUNET_break (hello_size >= sizeof (struct GNUNET_MessageHeader));
1867 if (GNUNET_BLOCK_EVALUATION_OK_MORE ==
1868 GNUNET_BLOCK_evaluate (GDS_block_context,
1869 GNUNET_BLOCK_TYPE_DHT_HELLO,
1871 GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO,
1877 GDS_NEIGHBOURS_handle_reply (sender,
1878 GNUNET_BLOCK_TYPE_DHT_HELLO,
1879 GNUNET_TIME_relative_to_absolute (hello_expiration),
1890 GNUNET_STATISTICS_update (GDS_stats,
1891 gettext_noop ("# FIND PEER requests ignored due to Bloomfilter"),
1898 GNUNET_STATISTICS_update (GDS_stats,
1899 gettext_noop ("# FIND PEER requests ignored due to lack of HELLO"),
1904 /* then, also consider sending a random HELLO from the closest bucket */
1905 if (0 == memcmp (&my_identity_hash,
1907 sizeof (struct GNUNET_HashCode)))
1908 bucket_idx = closest_bucket;
1910 bucket_idx = GNUNET_MIN (closest_bucket,
1912 if (bucket_idx == GNUNET_SYSERR)
1914 bucket = &k_buckets[bucket_idx];
1915 if (bucket->peers_size == 0)
1917 choice = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1918 bucket->peers_size);
1919 peer = bucket->head;
1922 GNUNET_assert (NULL != peer);
1926 choice = bucket->peers_size;
1931 return; /* no non-masked peer available */
1933 peer = bucket->head;
1934 hello = GDS_HELLO_get (peer->id);
1935 } while ( (NULL == hello) ||
1936 (GNUNET_BLOCK_EVALUATION_OK_MORE !=
1937 GNUNET_BLOCK_evaluate (GDS_block_context,
1938 GNUNET_BLOCK_TYPE_DHT_HELLO,
1940 GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO,
1944 (hello_size = GNUNET_HELLO_size (hello)))) );
1945 GDS_NEIGHBOURS_handle_reply (sender,
1946 GNUNET_BLOCK_TYPE_DHT_HELLO,
1947 GNUNET_TIME_relative_to_absolute
1948 (GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION),
1960 * Handle a result from local datacache for a GET operation.
1962 * @param cls the `struct PeerInfo` for which this is a reply
1963 * @param type type of the block
1964 * @param expiration_time when does the content expire
1965 * @param key key for the content
1966 * @param put_path_length number of entries in @a put_path
1967 * @param put_path peers the original PUT traversed (if tracked)
1968 * @param get_path_length number of entries in @a get_path
1969 * @param get_path peers this reply has traversed so far (if tracked)
1970 * @param data payload of the reply
1971 * @param data_size number of bytes in @a data
1974 handle_local_result (void *cls,
1975 enum GNUNET_BLOCK_Type type,
1976 struct GNUNET_TIME_Absolute expiration_time,
1977 const struct GNUNET_HashCode *key,
1978 unsigned int put_path_length,
1979 const struct GNUNET_PeerIdentity *put_path,
1980 unsigned int get_path_length,
1981 const struct GNUNET_PeerIdentity *get_path,
1985 struct PeerInfo *peer = cls;
1988 pp = GNUNET_STRINGS_pp2s (put_path,
1990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1991 "Found local result for %s (PP: %s)\n",
1995 GDS_NEIGHBOURS_handle_reply (peer->id,
1999 put_path_length, put_path,
2000 get_path_length, get_path,
2006 * Check validity of p2p get request.
2008 * @param cls closure with the `struct PeerInfo` of the sender
2009 * @param get the message
2010 * @return #GNUNET_OK if the message is well-formed
2013 check_dht_p2p_get (void *cls,
2014 const struct PeerGetMessage *get)
2016 uint32_t xquery_size;
2019 msize = ntohs (get->header.size);
2020 xquery_size = ntohl (get->xquery_size);
2021 if (msize < sizeof (struct PeerGetMessage) + xquery_size)
2023 GNUNET_break_op (0);
2024 return GNUNET_SYSERR;
2031 * Core handler for p2p get requests.
2033 * @param cls closure with the `struct PeerInfo` of the sender
2034 * @param get the message
2037 handle_dht_p2p_get (void *cls,
2038 const struct PeerGetMessage *get)
2040 struct PeerInfo *peer = cls;
2041 uint32_t xquery_size;
2042 size_t reply_bf_size;
2044 enum GNUNET_BLOCK_Type type;
2045 enum GNUNET_DHT_RouteOption options;
2046 enum GNUNET_BLOCK_EvaluationResult eval;
2047 struct GNUNET_BLOCK_Group *bg;
2048 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
2052 /* parse and validate message */
2053 msize = ntohs (get->header.size);
2054 xquery_size = ntohl (get->xquery_size);
2055 reply_bf_size = msize - (sizeof (struct PeerGetMessage) + xquery_size);
2056 type = ntohl (get->type);
2057 options = ntohl (get->options);
2058 xquery = (const char *) &get[1];
2059 GNUNET_STATISTICS_update (GDS_stats,
2060 gettext_noop ("# P2P GET requests received"),
2063 GNUNET_STATISTICS_update (GDS_stats,
2064 gettext_noop ("# P2P GET bytes received"),
2067 if (GNUNET_YES == log_route_details_stderr)
2071 tmp = GNUNET_strdup (GNUNET_i2s (&my_identity));
2072 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
2073 "R5N GET %s: %s->%s (%u, %u=>%u) xq: %.*s\n",
2074 GNUNET_h2s (&get->key),
2075 GNUNET_i2s (peer->id),
2077 ntohl(get->hop_count),
2078 GNUNET_CRYPTO_hash_matching_bits (&peer->phash,
2080 GNUNET_CRYPTO_hash_matching_bits (&my_identity_hash,
2082 ntohl(get->xquery_size),
2087 = GNUNET_BLOCK_evaluate (GDS_block_context,
2090 GNUNET_BLOCK_EO_NONE,
2096 if (eval != GNUNET_BLOCK_EVALUATION_REQUEST_VALID)
2098 /* request invalid or block type not supported */
2099 GNUNET_break_op (eval == GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED);
2102 peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2104 GNUNET_CONSTANTS_BLOOMFILTER_K);
2105 GNUNET_break_op (GNUNET_YES ==
2106 GNUNET_CONTAINER_bloomfilter_test (peer_bf,
2108 bg = GNUNET_BLOCK_group_create (GDS_block_context,
2111 &xquery[xquery_size],
2116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2117 "GET for %s at %s after %u hops\n",
2118 GNUNET_h2s (&get->key),
2119 GNUNET_i2s (&my_identity),
2120 (unsigned int) ntohl (get->hop_count));
2121 /* local lookup (this may update the reply_bf) */
2122 if ((0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2123 (GDS_am_closest_peer (&get->key,
2126 if ((0 != (options & GNUNET_DHT_RO_FIND_PEER)))
2128 GNUNET_STATISTICS_update (GDS_stats,
2129 gettext_noop ("# P2P FIND PEER requests processed"),
2132 handle_find_peer (peer->id,
2138 eval = GDS_DATACACHE_handle_get (&get->key,
2143 &handle_local_result,
2149 GNUNET_STATISTICS_update (GDS_stats,
2150 gettext_noop ("# P2P GET requests ONLY routed"),
2155 /* remember request for routing replies */
2156 GDS_ROUTING_add (peer->id,
2158 bg, /* bg now owned by routing, but valid at least until end of this function! */
2164 /* P2P forwarding */
2165 forwarded = GNUNET_NO;
2166 if (eval != GNUNET_BLOCK_EVALUATION_OK_LAST)
2167 forwarded = GDS_NEIGHBOURS_handle_get (type,
2169 ntohl (get->desired_replication_level),
2170 ntohl (get->hop_count),
2176 GDS_CLIENTS_process_get (options
2177 | (GNUNET_OK == forwarded)
2178 ? GNUNET_DHT_RO_LAST_HOP : 0,
2180 ntohl (get->hop_count),
2181 ntohl (get->desired_replication_level),
2186 /* clean up; note that 'bg' is owned by routing now! */
2187 GNUNET_CONTAINER_bloomfilter_free (peer_bf);
2192 * Check validity of p2p result message.
2194 * @param cls closure
2195 * @param message message
2196 * @return #GNUNET_YES if the message is well-formed
2199 check_dht_p2p_result (void *cls,
2200 const struct PeerResultMessage *prm)
2202 uint32_t get_path_length;
2203 uint32_t put_path_length;
2206 msize = ntohs (prm->header.size);
2207 put_path_length = ntohl (prm->put_path_length);
2208 get_path_length = ntohl (prm->get_path_length);
2210 sizeof (struct PeerResultMessage) + (get_path_length +
2212 sizeof (struct GNUNET_PeerIdentity)) ||
2214 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
2216 GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
2218 GNUNET_break_op (0);
2219 return GNUNET_SYSERR;
2226 * Process a reply, after the @a get_path has been updated.
2228 * @param expiration_time when does the reply expire
2229 * @param key key matching the query
2230 * @param get_path_length number of entries in @a get_path
2231 * @param get_path path the reply has taken
2232 * @param put_path_length number of entries in @a put_path
2233 * @param put_path path the PUT has taken
2234 * @param type type of the block
2235 * @param data_size number of bytes in @a data
2236 * @param data payload of the reply
2239 process_reply_with_path (struct GNUNET_TIME_Absolute expiration_time,
2240 const struct GNUNET_HashCode *key,
2241 unsigned int get_path_length,
2242 const struct GNUNET_PeerIdentity *get_path,
2243 unsigned int put_path_length,
2244 const struct GNUNET_PeerIdentity *put_path,
2245 enum GNUNET_BLOCK_Type type,
2249 /* forward to local clients */
2250 GDS_CLIENTS_handle_reply (expiration_time,
2259 GDS_CLIENTS_process_get_resp (type,
2268 if (GNUNET_YES == cache_results)
2270 struct GNUNET_PeerIdentity xput_path[get_path_length + 1 + put_path_length];
2272 GNUNET_memcpy (xput_path,
2274 put_path_length * sizeof (struct GNUNET_PeerIdentity));
2275 GNUNET_memcpy (&xput_path[put_path_length],
2277 get_path_length * sizeof (struct GNUNET_PeerIdentity));
2279 GDS_DATACACHE_handle_put (expiration_time,
2281 get_path_length + put_path_length,
2287 /* forward to other peers */
2288 GDS_ROUTING_process (type,
2301 * Core handler for p2p result messages.
2303 * @param cls closure
2304 * @param message message
2307 handle_dht_p2p_result (void *cls,
2308 const struct PeerResultMessage *prm)
2310 struct PeerInfo *peer = cls;
2311 const struct GNUNET_PeerIdentity *put_path;
2312 const struct GNUNET_PeerIdentity *get_path;
2314 uint32_t get_path_length;
2315 uint32_t put_path_length;
2318 enum GNUNET_BLOCK_Type type;
2320 /* parse and validate message */
2321 msize = ntohs (prm->header.size);
2322 put_path_length = ntohl (prm->put_path_length);
2323 get_path_length = ntohl (prm->get_path_length);
2324 put_path = (const struct GNUNET_PeerIdentity *) &prm[1];
2325 get_path = &put_path[put_path_length];
2326 type = ntohl (prm->type);
2327 data = (const void *) &get_path[get_path_length];
2328 data_size = msize - (sizeof (struct PeerResultMessage) +
2330 put_path_length) * sizeof (struct GNUNET_PeerIdentity));
2331 GNUNET_STATISTICS_update (GDS_stats,
2332 gettext_noop ("# P2P RESULTS received"),
2335 GNUNET_STATISTICS_update (GDS_stats,
2336 gettext_noop ("# P2P RESULT bytes received"),
2339 if (GNUNET_YES == log_route_details_stderr)
2345 gp = GNUNET_STRINGS_pp2s (get_path,
2347 pp = GNUNET_STRINGS_pp2s (put_path,
2349 tmp = GNUNET_strdup (GNUNET_i2s (&my_identity));
2350 LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG,
2351 "R5N RESULT %s: %s->%s (GP: %s, PP: %s)\n",
2352 GNUNET_h2s (&prm->key),
2353 GNUNET_i2s (peer->id),
2361 /* if we got a HELLO, consider it for our own routing table */
2362 if (GNUNET_BLOCK_TYPE_DHT_HELLO == type)
2364 const struct GNUNET_MessageHeader *h;
2365 struct GNUNET_PeerIdentity pid;
2367 /* Should be a HELLO, validate and consider using it! */
2368 if (data_size < sizeof (struct GNUNET_HELLO_Message))
2370 GNUNET_break_op (0);
2374 if (data_size != ntohs (h->size))
2376 GNUNET_break_op (0);
2380 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) h,
2383 GNUNET_break_op (0);
2386 if ( (GNUNET_YES != disable_try_connect) &&
2387 (0 != memcmp (&my_identity,
2389 sizeof (struct GNUNET_PeerIdentity))) )
2395 /* First, check if 'peer' is already on the path, and if
2396 so, truncate it instead of expanding. */
2397 for (unsigned int i=0;i<=get_path_length;i++)
2398 if (0 == memcmp (&get_path[i],
2400 sizeof (struct GNUNET_PeerIdentity)))
2402 process_reply_with_path (GNUNET_TIME_absolute_ntoh (prm->expiration_time),
2414 /* Need to append 'peer' to 'get_path' (normal case) */
2416 struct GNUNET_PeerIdentity xget_path[get_path_length + 1];
2418 GNUNET_memcpy (xget_path,
2420 get_path_length * sizeof (struct GNUNET_PeerIdentity));
2421 xget_path[get_path_length] = *peer->id;
2423 process_reply_with_path (GNUNET_TIME_absolute_ntoh (prm->expiration_time),
2425 get_path_length + 1,
2437 * Initialize neighbours subsystem.
2439 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
2442 GDS_NEIGHBOURS_init ()
2444 struct GNUNET_MQ_MessageHandler core_handlers[] = {
2445 GNUNET_MQ_hd_var_size (dht_p2p_get,
2446 GNUNET_MESSAGE_TYPE_DHT_P2P_GET,
2447 struct PeerGetMessage,
2449 GNUNET_MQ_hd_var_size (dht_p2p_put,
2450 GNUNET_MESSAGE_TYPE_DHT_P2P_PUT,
2451 struct PeerPutMessage,
2453 GNUNET_MQ_hd_var_size (dht_p2p_result,
2454 GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT,
2455 struct PeerResultMessage,
2457 GNUNET_MQ_handler_end ()
2459 unsigned long long temp_config_num;
2462 = GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
2464 "DISABLE_TRY_CONNECT");
2466 GNUNET_CONFIGURATION_get_value_number (GDS_cfg,
2470 bucket_size = (unsigned int) temp_config_num;
2472 = GNUNET_CONFIGURATION_get_value_yesno (GDS_cfg,
2476 log_route_details_stderr =
2477 (NULL != getenv("GNUNET_DHT_ROUTE_DEBUG")) ? GNUNET_YES : GNUNET_NO;
2478 ats_ch = GNUNET_ATS_connectivity_init (GDS_cfg);
2479 core_api = GNUNET_CORE_connect (GDS_cfg,
2482 &handle_core_connect,
2483 &handle_core_disconnect,
2485 if (NULL == core_api)
2486 return GNUNET_SYSERR;
2487 all_connected_peers = GNUNET_CONTAINER_multipeermap_create (256,
2489 all_desired_peers = GNUNET_CONTAINER_multipeermap_create (256,
2496 * Shutdown neighbours subsystem.
2499 GDS_NEIGHBOURS_done ()
2501 if (NULL == core_api)
2503 GNUNET_CORE_disconnect (core_api);
2506 GNUNET_CONTAINER_multipeermap_size (all_connected_peers));
2507 GNUNET_CONTAINER_multipeermap_destroy (all_connected_peers);
2508 all_connected_peers = NULL;
2509 GNUNET_CONTAINER_multipeermap_iterate (all_desired_peers,
2512 GNUNET_CONTAINER_multipeermap_destroy (all_desired_peers);
2513 all_desired_peers = NULL;
2514 GNUNET_ATS_connectivity_done (ats_ch);
2516 GNUNET_assert (NULL == find_peer_task);
2521 * Get the ID of the local node.
2523 * @return identity of the local node
2525 struct GNUNET_PeerIdentity *
2526 GDS_NEIGHBOURS_get_id ()
2528 return &my_identity;
2532 /* end of gnunet-service-dht_neighbours.c */