GNUnet 0.28.1-dev.4
 
Loading...
Searching...
No Matches
gnunet-service-dht_neighbours.c File Reference

GNUnet DHT service's bucket and neighbour management code. More...

Include dependency graph for gnunet-service-dht_neighbours.c:

Go to the source code of this file.

Data Structures

struct  PeerResultMessage
 P2P Result message. More...
 
struct  PeerGetMessage
 P2P GET message. More...
 
struct  Target
 List of targets that we can use to reach this peer. More...
 
struct  PeerInfo
 Entry for a peer in a bucket. More...
 
struct  PeerBucket
 Peers are grouped into buckets. More...
 
struct  GDS_RoutingPutCallbackData
 
struct  GDS_NeighboursReply
 
struct  ForwardedDHTPut
 
struct  BlockCls
 
struct  HandleCallbackGet
 

Macros

#define LOG_TRAFFIC(kind, ...)
 
#define SANITY_CHECKS   2
 Enable slow sanity checks to debug issues.
 
#define MAX_BUCKETS   sizeof(struct GNUNET_HashCode) * 8
 How many buckets will we allow in total.
 
#define DEFAULT_BUCKET_SIZE   8
 What is the maximum number of peers in a given bucket.
 
#define FIND_PEER_REPLICATION_LEVEL   4
 Desired replication level for FIND PEER requests.
 
#define MAXIMUM_PENDING_PER_PEER   64
 Maximum allowed number of pending messages per peer.
 
#define DHT_MINIMUM_FIND_PEER_INTERVAL
 How long at least to wait before sending another find peer request.
 
#define DHT_AVG_FIND_PEER_INTERVAL
 How long to additionally wait on average per bucket_size to send out the FIND PEER requests if we did successfully connect (!) to a a new peer and added it to a bucket (as counted in newly_found_peers).
 
#define GET_TIMEOUT   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
 How long at most to wait for transmission of a GET request to another peer?
 

Functions

static void send_done_cb (void *cls)
 Function called whenever we finished sending to a target.
 
static void do_send (struct PeerInfo *pi, const struct GNUNET_MessageHeader *msg)
 Send msg to pi.
 
static int find_bucket (const struct GNUNET_HashCode *hc)
 Find the optimal bucket for this key.
 
static enum GNUNET_GenericReturnValue add_known_to_bloom (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
 Add each of the peers we already know to the Bloom filter of the request so that we don't get duplicate HELLOs.
 
static void send_find_peer_message (void *cls)
 Task to send a find peer message for our own peer identifier so that we can find the closest peers in the network to ourselves and attempt to connect to them.
 
static void update_hold (struct PeerBucket *bucket)
 The list of the first bucket_size peers of bucket changed.
 
void GDS_u_connect (void *cls, struct GNUNET_DHTU_Target *target, const struct GNUNET_PeerIdentity *pid, void **ctx)
 Function to call when we connect to a peer and can henceforth transmit to that peer.
 
void GDS_u_disconnect (void *ctx)
 Function to call when we disconnected from a peer and can henceforth cannot transmit to that peer anymore.
 
static unsigned int get_forward_count (uint16_t hop_count, uint16_t target_replication)
 To how many peers should we (on average) forward the request to obtain the desired target_replication count (on average).
 
enum GNUNET_GenericReturnValue GDS_am_closest_peer (const struct GNUNET_HashCode *key, const struct GNUNET_CONTAINER_BloomFilter *bloom)
 Check whether my identity is closer than any known peers.
 
static struct PeerInfoselect_peer (const struct GNUNET_HashCode *key, const struct GNUNET_CONTAINER_BloomFilter *bloom, uint32_t hops)
 Select a peer from the routing table that would be a good routing destination for sending a message for key.
 
static unsigned int get_target_peers (const struct GNUNET_HashCode *key, struct GNUNET_CONTAINER_BloomFilter *bloom, uint16_t hop_count, uint16_t target_replication, struct PeerInfo ***targets)
 Compute the set of peers that the given request should be forwarded to.
 
static void hello_check (const struct GNUNET_DATACACHE_Block *bd)
 If we got a HELLO, consider it for our own routing table.
 
static bool cb_routing_put_message (void *cls, size_t msize, struct PeerPutMessage *ppm)
 
void GDS_NEIGHBOURS_handle_put (const struct GNUNET_DATACACHE_Block *bd, uint16_t desired_replication_level, uint16_t hop_count, struct GNUNET_CONTAINER_BloomFilter *bf, GDS_PutOperationCallback cb, void *cb_cls)
 Perform a PUT operation.
 
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type, enum GNUNET_DHT_RouteOption options, uint16_t desired_replication_level, uint16_t hop_count, const struct GNUNET_HashCode *key, const void *xquery, size_t xquery_size, struct GNUNET_BLOCK_Group *bg, struct GNUNET_CONTAINER_BloomFilter *peer_bf)
 Perform a GET operation.
 
struct PeerInfoGDS_NEIGHBOURS_lookup_peer (const struct GNUNET_PeerIdentity *target)
 Lookup peer by peer's identity.
 
static void cleanup_neighbours_reply (struct GDS_NeighboursReply *reply)
 
static void safe_neighbours_callback (void *cls, GNUNET_SCHEDULER_TaskCallback cb, bool success)
 
static bool cb_path_signed (void *cls, const struct GNUNET_CRYPTO_EddsaSignature *sig)
 
void GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi, const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path, GNUNET_SCHEDULER_TaskCallback cb, void *cb_cls)
 Handle a reply (route to origin).
 
static enum GNUNET_GenericReturnValue check_dht_p2p_put (void *cls, const struct PeerPutMessage *put)
 Check validity of a p2p put request.
 
static void cb_forwarded_dht_p2p_put (void *cls, enum GNUNET_GenericReturnValue forwarded)
 
static void handle_dht_p2p_put (void *cls, const struct PeerPutMessage *put)
 Core handler for p2p put requests.
 
static void handle_find_my_hello (struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg, GNUNET_SCHEDULER_TaskCallback cb, void *cb_cls)
 We have received a request for a HELLO.
 
static void handle_find_local_hello (struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg, GNUNET_SCHEDULER_TaskCallback cb, void *cb_cls)
 We have received a request for nearby HELLOs.
 
static void handle_local_result (void *cls, const struct GNUNET_DATACACHE_Block *bd)
 Handle an exact result from local datacache for a GET operation.
 
static enum GNUNET_GenericReturnValue check_dht_p2p_get (void *cls, const struct PeerGetMessage *get)
 Check validity of p2p get request.
 
static void cb_handle_dht_p2p_get_local_result (void *cls)
 
static void cb_handle_dht_p2p_get_local_hello (void *cls)
 
static void cb_handle_dht_p2p_get_my_hello (void *cls)
 
static void handle_dht_p2p_get (void *cls, const struct PeerGetMessage *get)
 Core handler for p2p get requests.
 
static void process_reply_with_path (const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path)
 Process a reply, after the get_path has been updated.
 
static enum GNUNET_GenericReturnValue check_dht_p2p_result (void *cls, const struct PeerResultMessage *prm)
 Check validity of p2p result message.
 
static void handle_dht_p2p_result (void *cls, const struct PeerResultMessage *prm)
 Core handler for p2p result messages.
 
static enum GNUNET_GenericReturnValue check_dht_p2p_hello (void *cls, const struct GNUNET_MessageHeader *hello)
 Check validity of a p2p hello message.
 
static void handle_dht_p2p_hello (void *cls, const struct GNUNET_MessageHeader *hello)
 Core handler for p2p HELLO messages.
 
void GDS_u_receive (void *cls, void **tctx, void **sctx, const void *message, size_t message_size)
 Function to call when we receive a message.
 
void GDS_try_connect (void *cls, const struct GNUNET_PeerIdentity *pid, const char *uri)
 Callback function used to extract URIs from a builder.
 
void GDS_NEIGHBOURS_broadcast (const struct GNUNET_MessageHeader *msg)
 Send msg to all peers in our buckets.
 
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_init ()
 Initialize neighbours subsystem.
 
void GDS_NEIGHBOURS_done ()
 Shutdown neighbours subsystem.
 
const struct GNUNET_PeerIdentityGDS_NEIGHBOURS_get_id ()
 Get the ID of the local node.
 

Variables

static int cache_results
 Do we cache all results that we are routing in the local datacache?
 
static unsigned int closest_bucket
 One past the deepest currently used bucket, initially 0 (no peers at all).
 
static unsigned int newly_found_peers
 How many peers have we added since we sent out our last find peer request?
 
static int disable_try_connect
 Option for testing that disables the 'connect' function of the DHT.
 
static struct PeerBucket k_buckets [sizeof(struct GNUNET_HashCode) *8]
 The buckets.
 
static struct GNUNET_CONTAINER_MultiPeerMapall_connected_peers
 Hash map of all CORE-connected peers, for easy removal from k_buckets on disconnect.
 
static unsigned int bucket_size = 8
 Maximum size for each bucket.
 
static struct GNUNET_SCHEDULER_Taskfind_peer_task
 Task that sends FIND PEER requests.
 

Detailed Description

GNUnet DHT service's bucket and neighbour management code.

Author
Christian Grothoff
Nathan Evans

Definition in file gnunet-service-dht_neighbours.c.

Macro Definition Documentation

◆ LOG_TRAFFIC

#define LOG_TRAFFIC (   kind,
  ... 
)
Value:
GNUNET_log_from (kind, "dht-traffic", \
__VA_ARGS__)
#define GNUNET_log_from(kind, comp,...)

Definition at line 42 of file gnunet-service-dht_neighbours.c.

111{
115 struct GNUNET_MessageHeader header;
116
120 uint32_t type GNUNET_PACKED;
121
125 uint16_t reserved GNUNET_PACKED;
126
130 uint16_t options GNUNET_PACKED;
131
135 uint16_t put_path_length GNUNET_PACKED;
136
140 uint16_t get_path_length GNUNET_PACKED;
141
145 struct GNUNET_TIME_AbsoluteNBO expiration_time;
146
150 struct GNUNET_HashCode key;
151
152 /* trunc_peer (if truncated) */
153
154 /* put path (if tracked) */
155
156 /* get path (if tracked) */
157
158 /* sender_sig (if path tracking is on) */
159
160 /* Payload */
161};
162
163
167struct PeerGetMessage
168{
173
177 uint32_t type GNUNET_PACKED;
178
182 uint16_t options GNUNET_PACKED;
183
187 uint16_t hop_count GNUNET_PACKED;
188
193
198
203
207 struct GNUNET_HashCode key;
208
209 /* result bloomfilter */
210
211 /* xquery */
212
213};
215
216
220struct PeerInfo;
221
222
226struct Target
227{
231 struct Target *next;
232
236 struct Target *prev;
237
242
246 struct GDS_Underlay *u;
247
251 struct PeerInfo *pi;
252
257
261 unsigned int load;
262
267 bool dropped;
268
269};
270
271
275struct PeerInfo
276{
280 struct GNUNET_PeerIdentity id;
281
285 struct GNUNET_HashCode phash;
286
291
295 struct PeerInfo *next;
296
300 struct PeerInfo *prev;
301
305 struct Target *t_head;
306
310 struct Target *t_tail;
311
315 void *hello;
316
320 size_t hello_size;
321
325 int peer_bucket;
326};
327
328
332struct PeerBucket
333{
337 struct PeerInfo *head;
338
342 struct PeerInfo *tail;
343
347 unsigned int peers_size;
348};
349
350
354static int cache_results;
355
360static unsigned int closest_bucket;
361
366static unsigned int newly_found_peers;
367
371static int disable_try_connect;
372
376static struct PeerBucket k_buckets[MAX_BUCKETS];
377
383
387static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
388
393
394
402static void
403send_done_cb (void *cls)
404{
405 struct Target *t = cls;
406 struct PeerInfo *pi = t->pi; /* NULL if t->dropped! */
407
408 GNUNET_assert (t->load > 0);
409 t->load--;
410 if (0 < t->load)
411 return;
412 if (t->dropped)
413 {
414 GNUNET_free (t);
415 return;
416 }
417 /* move target back to the front */
419 pi->t_tail,
420 t);
422 pi->t_tail,
423 t);
424}
425
426
433static void
434do_send (struct PeerInfo *pi,
435 const struct GNUNET_MessageHeader *msg)
436{
437 struct Target *t;
438
439 for (t = pi->t_head;
440 NULL != t;
441 t = t->next)
442 if (t->load < MAXIMUM_PENDING_PER_PEER)
443 break;
444 if (NULL == t)
445 {
446 /* all targets busy, drop message */
448 "# messages dropped (underlays busy)",
449 1,
450 GNUNET_NO);
451 return;
452 }
453 t->load++;
454 /* rotate busy targets to the end */
455 if (MAXIMUM_PENDING_PER_PEER == t->load)
456 {
458 pi->t_tail,
459 t);
461 pi->t_tail,
462 t);
463 }
464 GDS_u_send (t->u,
465 t->utarget,
466 msg,
467 ntohs (msg->size),
469 t);
470}
471
472
483static int
484find_bucket (const struct GNUNET_HashCode *hc)
485{
486 const struct GNUNET_HashCode *my_identity_hash;
487 struct GNUNET_HashCode xor;
488 unsigned int bits;
489
490 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
491 GNUNET_assert (NULL != my_identity_hash);
492
494 my_identity_hash,
495 &xor);
497 if (bits == MAX_BUCKETS)
498 {
499 /* How can all bits match? Got my own ID? */
500 GNUNET_break (0);
501 return -1;
502 }
503 return bits;
504}
505
506
517add_known_to_bloom (void *cls,
518 const struct GNUNET_PeerIdentity *key,
519 void *value)
520{
521 struct GNUNET_BLOCK_Group *bg = cls;
522 struct PeerInfo *pi = value;
523
525 &pi->phash,
526 1);
528 "Adding known peer (%s) to Bloom filter for FIND PEER\n",
529 GNUNET_i2s (key));
530 return GNUNET_YES;
531}
532
533
541static void
542send_find_peer_message (void *cls)
543{
544 (void) cls;
545
546 /* Compute when to do this again (and if we should
547 even send a message right now) */
548 {
549 struct GNUNET_TIME_Relative next_send_time;
550 bool done_early;
551
552 find_peer_task = NULL;
553 done_early = (newly_found_peers > bucket_size);
554 /* schedule next round, taking longer if we found more peers
555 in the last round. */
556 next_send_time.rel_value_us =
561 1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
565 GNUNET_SCHEDULER_add_delayed (next_send_time,
567 NULL);
568 if (done_early)
569 return;
570 }
571
572 /* actually send 'find peer' request */
573 {
574 const struct GNUNET_HashCode *my_identity_hash;
575 struct GNUNET_BLOCK_Group *bg;
576 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
577
578 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
579 GNUNET_assert (NULL != my_identity_hash);
580
583 NULL,
584 0,
585 "seen-set-size",
588 NULL);
591 bg);
592 peer_bf
596 if (GNUNET_OK !=
601 0, /* hop count */
602 my_identity_hash,
603 NULL, 0, /* xquery */
604 bg,
605 peer_bf))
606 {
608 "# Failed to initiate FIND PEER lookup",
609 1,
610 GNUNET_NO);
611 }
612 else
613 {
615 "# FIND PEER messages initiated",
616 1,
617 GNUNET_NO);
618 }
621 }
622}
623
624
632static void
633update_hold (struct PeerBucket *bucket)
634{
635 unsigned int off = 0;
636
637 /* find the peer -- we just go over all of them, should
638 be hardly any more expensive than just finding the 'right'
639 one. */
640 for (struct PeerInfo *pos = bucket->head;
641 NULL != pos;
642 pos = pos->next)
643 {
644 if (off > bucket_size)
645 break; /* We only hold up to #bucket_size peers per bucket */
646 off++;
647 for (struct Target *tp = pos->t_head;
648 NULL != tp;
649 tp = tp->next)
650 if (NULL == tp->ph)
651 tp->ph = GDS_u_hold (tp->u,
652 tp->utarget);
653 }
654}
655
656
657void
658GDS_u_connect (void *cls,
659 struct GNUNET_DHTU_Target *target,
660 const struct GNUNET_PeerIdentity *pid,
661 void **ctx)
662{
663 const struct GNUNET_PeerIdentity *my_identity;
664 struct GDS_Underlay *u = cls;
665 struct PeerInfo *pi;
666 struct PeerBucket *bucket;
667 bool do_hold = false;
668
670 GNUNET_assert (NULL != my_identity);
671
672 /* Check for connect to self message */
673 if (0 == GNUNET_memcmp (my_identity, pid))
674 return;
676 "Connected to peer %s\n",
677 GNUNET_i2s (pid));
679 pid);
680 if (NULL == pi)
681 {
683 "# peers connected",
684 1,
685 GNUNET_NO);
686 pi = GNUNET_new (struct PeerInfo);
687 pi->id = *pid;
689 sizeof(*pid),
690 &pi->phash);
691 pi->peer_bucket = find_bucket (&pi->phash);
692 GNUNET_assert ( (pi->peer_bucket >= 0) &&
693 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
694 bucket = &k_buckets[pi->peer_bucket];
696 bucket->tail,
697 pi);
698 bucket->peers_size++;
700 (unsigned int) pi->peer_bucket + 1);
703 &pi->id,
704 pi,
706 if (bucket->peers_size <= bucket_size)
707 {
709 do_hold = true;
710 }
713 {
714 /* got a first connection, good time to start with FIND PEER requests... */
717 NULL);
718 }
719 /* A pending GET that found no route is sitting on an exponential
720 back-off of up to 15 minutes; now that we have somewhere to send
721 it, do so immediately. */
723 }
724 {
725 struct Target *t;
726
727 t = GNUNET_new (struct Target);
728 t->u = u;
729 t->utarget = target;
730 t->pi = pi;
732 pi->t_tail,
733 t);
734 *ctx = t;
735
736 }
737 if (do_hold)
738 update_hold (bucket);
739}
740
741
742void
743GDS_u_disconnect (void *ctx)
744{
745 struct Target *t = ctx;
746 struct PeerInfo *pi;
747 struct PeerBucket *bucket;
748 bool was_held = false;
749
750 /* Check for disconnect from self message (on shutdown) */
751 if (NULL == t)
752 return;
753 pi = t->pi;
755 pi->t_tail,
756 t);
757 if (NULL != t->ph)
758 {
759 GDS_u_drop (t->u,
760 t->ph);
761 t->ph = NULL;
762 was_held = true;
763 }
764 if (t->load > 0)
765 {
766 t->dropped = true;
767 t->pi = NULL;
768 }
769 else
770 {
771 GNUNET_free (t);
772 }
773 if (NULL != pi->t_head)
774 return; /* got other connections still */
776 "Disconnected from peer %s\n",
777 GNUNET_i2s (&pi->id));
779 "# peers connected",
780 -1,
781 GNUNET_NO);
784 &pi->id,
785 pi));
788 {
790 find_peer_task = NULL;
791 }
792 GNUNET_assert (pi->peer_bucket >= 0);
793 bucket = &k_buckets[pi->peer_bucket];
795 bucket->tail,
796 pi);
797 GNUNET_assert (bucket->peers_size > 0);
798 bucket->peers_size--;
799 if ( (was_held) &&
800 (bucket->peers_size >= bucket_size - 1) )
801 update_hold (bucket);
802 while ( (closest_bucket > 0) &&
805 GNUNET_free (pi->hello);
806 GNUNET_free (pi);
807}
808
809
818static unsigned int
819get_forward_count (uint16_t hop_count,
820 uint16_t target_replication)
821{
822 uint32_t random_value;
823 uint32_t forward_count;
824 float target_value;
825 double rm1;
826 double nse = GDS_NSE_get ();
827
828 /* Guard the divisor below: an NSE of zero would make target_value
829 infinite (or NaN), and the conversion to uint32_t undefined. */
830 if (! (nse >= MINIMUM_LOG_NSE))
832 if (hop_count > nse * 4.0)
833 {
834 /* forcefully terminate */
836 "# requests TTL-dropped",
837 1,
838 GNUNET_NO);
839 return 0;
840 }
841 if (hop_count > nse * 2.0)
842 {
843 /* Once we have reached our ideal number of hops, only forward to 1 peer */
844 return 1;
845 }
846 /* bound by system-wide maximum and minimum */
847 if (0 == target_replication)
848 target_replication = 1; /* 0 is verboten */
849 target_replication =
851 target_replication);
852 rm1 = target_replication - 1.0;
853 target_value =
854 1 + (rm1) / (nse + (rm1 * hop_count));
855
856 /* Set forward count to floor of target_value */
857 forward_count = (uint32_t) target_value;
858 /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
859 target_value = target_value - forward_count;
860 random_value = GNUNET_CRYPTO_random_u32 (UINT32_MAX);
861 if (random_value < (target_value * UINT32_MAX))
862 forward_count++;
863 return GNUNET_MIN (forward_count,
865}
866
867
880 const struct GNUNET_CONTAINER_BloomFilter *bloom)
881{
882 const struct GNUNET_HashCode *my_identity_hash;
883 int delta;
884 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
885 GNUNET_assert (NULL != my_identity_hash);
886 if (0 == GNUNET_memcmp (my_identity_hash, key))
887 return GNUNET_YES;
888 for (int bucket_num = find_bucket (key);
889 bucket_num < closest_bucket;
890 bucket_num++)
891 {
892 unsigned int count = 0;
893 GNUNET_assert (bucket_num >= 0);
894 for (struct PeerInfo *pos = k_buckets[bucket_num].head;
895 NULL != pos;
896 pos = pos->next)
897 {
898 if (count >= bucket_size)
899 break; /* we only consider first #bucket_size entries per bucket */
900 count++;
901 if ( (NULL != bloom) &&
902 (GNUNET_YES ==
904 &pos->phash)) )
905 continue; /* Ignore filtered peers */
906 /* All peers in this bucket must be closer than us, as
907 they mismatch with our PID on the pivotal bit. So
908 because an unfiltered peer exists, we are not the
909 closest. */
910 delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
911 my_identity_hash,
912 key);
913 switch (delta)
914 {
915 case -1: /* pos closer */
916 return GNUNET_NO;
917 case 0: /* identical, impossible! */
918 GNUNET_assert (0);
919 break;
920 case 1: /* I am closer */
921 break;
922 }
923 }
924 }
925 /* No closer (unfiltered) peers found; we must be the closest! */
926 return GNUNET_YES;
927}
928
929
951static struct PeerInfo *
952select_peer (const struct GNUNET_HashCode *key,
953 const struct GNUNET_CONTAINER_BloomFilter *bloom,
954 uint32_t hops)
955{
956 if (0 == closest_bucket)
957 {
959 "# Peer selection failed",
960 1,
961 GNUNET_NO);
962 return NULL; /* we have zero connections */
963 }
964 if (hops >= GDS_NSE_get ())
965 {
966 /* greedy selection (closest peer that is not in Bloom filter) */
967 struct PeerInfo *chosen = NULL;
968 int best_bucket;
969 int bucket_offset;
970
971 {
972 const struct GNUNET_HashCode *my_identity_hash;
973 struct GNUNET_HashCode xor;
974 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
975 GNUNET_assert (NULL != my_identity_hash);
977 my_identity_hash,
978 &xor);
979 best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
980 }
981 if (best_bucket >= closest_bucket)
982 bucket_offset = closest_bucket - 1;
983 else
984 bucket_offset = best_bucket;
985 while (-1 != bucket_offset)
986 {
987 struct PeerBucket *bucket = &k_buckets[bucket_offset];
988 unsigned int count = 0;
989
990 for (struct PeerInfo *pos = bucket->head;
991 NULL != pos;
992 pos = pos->next)
993 {
994 if (count >= bucket_size)
995 break; /* we only consider first #bucket_size entries per bucket */
996 count++;
997 if ( (NULL != bloom) &&
998 (GNUNET_YES ==
1000 &pos->phash)) )
1001 {
1003 "Excluded peer `%s' due to BF match in greedy routing for %s\n",
1004 GNUNET_i2s (&pos->id),
1005 GNUNET_h2s (key));
1006 continue;
1007 }
1008 if (NULL == chosen)
1009 {
1010 /* First candidate */
1011 chosen = pos;
1012 }
1013 else
1014 {
1015 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
1016 &chosen->phash,
1017 key);
1018 switch (delta)
1019 {
1020 case -1: /* pos closer */
1021 chosen = pos;
1022 break;
1023 case 0: /* identical, impossible! */
1024 GNUNET_assert (0);
1025 break;
1026 case 1: /* chosen closer */
1027 break;
1028 }
1029 }
1030 } /* for all (#bucket_size) peers in bucket */
1031 if (NULL != chosen)
1032 break;
1033
1034 /* If we chose nothing in first iteration, first go through deeper
1035 buckets (best chance to find a good match), and if we still found
1036 nothing, then to shallower buckets. Terminate on any match in the
1037 current bucket, as this search order guarantees that it can only get
1038 worse as we keep going. */
1039 /* Both upward steps must be bounded by #closest_bucket, and the test
1040 has to be `>=': stepping from #best_bucket to #best_bucket + 1
1041 below can jump straight over an `==' test, after which nothing
1042 stops the offset from running off the end of #k_buckets. */
1043 if (bucket_offset > best_bucket)
1044 {
1045 /* Go through more deeper buckets */
1046 bucket_offset++;
1047 if (bucket_offset >= closest_bucket)
1048 {
1049 /* Can't go any deeper, if nothing selected,
1050 go for shallower buckets */
1051 bucket_offset = best_bucket - 1;
1052 }
1053 }
1054 else
1055 {
1056 /* We're either at the 'best_bucket' or already moving
1057 on to shallower buckets. */
1058 if (bucket_offset == best_bucket)
1059 {
1060 bucket_offset++; /* go for deeper buckets */
1061 if (bucket_offset >= closest_bucket)
1062 bucket_offset = best_bucket - 1;
1063 }
1064 else
1065 bucket_offset--; /* go for shallower buckets */
1066 }
1067 } /* for applicable buckets (starting at best match) */
1068 if (NULL == chosen)
1069 {
1071 "# Peer selection failed",
1072 1,
1073 GNUNET_NO);
1074 return NULL;
1075 }
1077 "Selected peer `%s' in greedy routing for %s\n",
1078 GNUNET_i2s (&chosen->id),
1079 GNUNET_h2s (key));
1080 return chosen;
1081 } /* end of 'greedy' peer selection */
1082
1083 /* select "random" peer */
1084 /* count number of peers that are available and not filtered,
1085 but limit to at most #bucket_size peers, starting with
1086 those 'furthest' from us. */
1087 {
1088 unsigned int total = 0;
1089 unsigned int selected;
1090
1091 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1092 {
1093 struct PeerBucket *bucket = &k_buckets[bc];
1094 unsigned int count = 0;
1095
1096 for (struct PeerInfo *pos = bucket->head;
1097 NULL != pos;
1098 pos = pos->next)
1099 {
1100 count++;
1101 if (count > bucket_size)
1102 break; /* limits search to #bucket_size peers per bucket */
1103 if ( (NULL != bloom) &&
1104 (GNUNET_YES ==
1106 &pos->phash)) )
1107 {
1109 "Excluded peer `%s' due to BF match in random routing for %s\n",
1110 GNUNET_i2s (&pos->id),
1111 GNUNET_h2s (key));
1112 continue; /* Ignore filtered peers */
1113 }
1114 total++;
1115 } /* for all peers in bucket */
1116 } /* for all buckets */
1117 if (0 == total) /* No peers to select from! */
1118 {
1120 "# Peer selection failed",
1121 1,
1122 GNUNET_NO);
1123 return NULL;
1124 }
1125
1126 /* Now actually choose a peer */
1127 selected = GNUNET_CRYPTO_random_u32 (total);
1128 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1129 {
1130 unsigned int count = 0;
1131
1132 for (struct PeerInfo *pos = k_buckets[bc].head;
1133 pos != NULL;
1134 pos = pos->next)
1135 {
1136 count++;
1137 if (count > bucket_size)
1138 break; /* limits search to #bucket_size peers per bucket */
1139
1140 if ( (NULL != bloom) &&
1141 (GNUNET_YES ==
1143 &pos->phash)) )
1144 continue; /* Ignore bloomfiltered peers */
1145 if (0 == selected--)
1146 {
1148 "Selected peer `%s' in random routing for %s\n",
1149 GNUNET_i2s (&pos->id),
1150 GNUNET_h2s (key));
1151 return pos;
1152 }
1153 } /* for peers in bucket */
1154 } /* for all buckets */
1155 } /* random peer selection scope */
1156 GNUNET_break (0);
1157 return NULL;
1158}
1159
1160
1174static unsigned int
1175get_target_peers (const struct GNUNET_HashCode *key,
1176 struct GNUNET_CONTAINER_BloomFilter *bloom,
1177 uint16_t hop_count,
1178 uint16_t target_replication,
1179 struct PeerInfo ***targets)
1180{
1181 unsigned int target;
1182 unsigned int off;
1183 struct PeerInfo **rtargets;
1184
1185 GNUNET_assert (NULL != bloom);
1186 target = get_forward_count (hop_count,
1187 target_replication);
1188 if (0 == target)
1189 {
1190 *targets = NULL;
1191 return 0;
1192 }
1193 rtargets = GNUNET_new_array (target,
1194 struct PeerInfo *);
1195 for (off = 0; off < target; off++)
1196 {
1197 struct PeerInfo *nxt;
1198
1199 nxt = select_peer (key,
1200 bloom,
1201 hop_count);
1202 if (NULL == nxt)
1203 break;
1204 rtargets[off] = nxt;
1205 /* Exclude the peer we just picked from the next round, or
1206 select_peer() would hand us the same peer again. */
1209 &nxt->phash));
1211 &nxt->phash);
1212 }
1214 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1215 off,
1217 (unsigned int) hop_count,
1218 GNUNET_h2s (key),
1219 target);
1220 if (0 == off)
1221 {
1222 GNUNET_free (rtargets);
1223 *targets = NULL;
1224 return 0;
1225 }
1226 *targets = rtargets;
1228 "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1229 GNUNET_h2s (key),
1230 off,
1231 target);
1232 return off;
1233}
1234
1235
1241static void
1242hello_check (const struct GNUNET_DATACACHE_Block *bd)
1243{
1244 struct GNUNET_HELLO_Parser *b;
1245
1247 return;
1248
1250 bd->data_size);
1252 {
1255 NULL);
1256 }
1258}
1259
1260
1262{
1263 unsigned int hop_count;
1264 unsigned int target_count;
1265 struct PeerInfo **targets;
1266 struct GNUNET_HashCode key;
1267 unsigned int index;
1268 unsigned int *queued;
1270 void *cb_cls;
1271};
1272
1273
1274static bool
1275cb_routing_put_message (void *cls,
1276 size_t msize,
1277 struct PeerPutMessage *ppm)
1278{
1279 struct GDS_RoutingPutCallbackData *gds_routing = cls;
1280 struct PeerInfo *target;
1281
1282 if (NULL == ppm)
1283 {
1284 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1285 if (*(gds_routing->queued) >= gds_routing->target_count)
1286 {
1287 if (gds_routing->cb)
1288 gds_routing->cb (gds_routing->cb_cls, GNUNET_SYSERR);
1289
1290 GNUNET_free (gds_routing->targets);
1291 GNUNET_free (gds_routing->queued);
1292 }
1293
1294 return true;
1295 }
1296
1297 target = gds_routing->targets[gds_routing->index];
1298
1300 "Routing PUT for %s after %u hops to %s\n",
1301 GNUNET_h2s (&(gds_routing->key)),
1302 (unsigned int) gds_routing->hop_count,
1303 GNUNET_i2s (&target->id));
1304 do_send (target,
1305 &ppm->header);
1306 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1307
1308 if (*(gds_routing->queued) >= gds_routing->target_count)
1309 {
1310 if (gds_routing->cb)
1311 gds_routing->cb (gds_routing->cb_cls, GNUNET_OK);
1312
1313 GNUNET_free (gds_routing->targets);
1315 "# PUT messages queued for transmission",
1316 gds_routing->target_count,
1317 GNUNET_NO);
1318 GNUNET_free (gds_routing->queued);
1319 }
1320
1321 return true;
1322}
1323
1324
1325void
1327 uint16_t desired_replication_level,
1328 uint16_t hop_count,
1331 void *cb_cls)
1332{
1333 const struct GNUNET_PeerIdentity *my_identity;
1334 const struct GNUNET_HashCode *my_identity_hash;
1335 struct GDS_RoutingPutCallbackData gds_routing;
1336 size_t msize;
1337 enum GNUNET_DHT_RouteOption ro = bd->ro;
1338 unsigned int put_path_length = bd->put_path_length;
1339 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1340 bool truncated = (0 != (bd->ro & GNUNET_DHT_RO_TRUNCATED));
1341 const struct GNUNET_PeerIdentity *trunc_peer
1342 = truncated
1343 ? &bd->trunc_peer
1344 : NULL;
1345 struct GNUNET_PeerIdentity trunc_peer_out;
1347
1349 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1350 GNUNET_assert (NULL != my_identity);
1351
1354 bd->ro, &ro,
1355 bd->expiration_time,
1356 bd->data, bd->data_size,
1357 put_path, put_path_length,
1358 &put_path_length,
1359 trunc_peer,
1360 &trunc_peer_out,
1361 &truncated);
1362 if (truncated)
1363 trunc_peer = &trunc_peer_out;
1364 /* Path may have been truncated by the call above */
1366 "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1368 GNUNET_h2s (&bd->key),
1369 (bd->ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1370 (bd->ro & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1371
1372 /* if we got a HELLO, consider it for our own routing table */
1373 hello_check (bd);
1374 GNUNET_assert ((NULL != bf) && (NULL != my_identity_hash));
1375 GNUNET_CONTAINER_bloomfilter_add (bf, my_identity_hash);
1377 "# PUT requests routed",
1378 1,
1379 GNUNET_NO);
1380 if (GNUNET_OK != ret)
1381 {
1382 if (cb)
1383 cb (cb_cls, ret);
1384 return;
1385 }
1386 gds_routing.target_count
1387 = get_target_peers (&bd->key,
1388 bf,
1389 hop_count,
1390 desired_replication_level,
1391 &(gds_routing.targets));
1392 if (0 == gds_routing.target_count)
1393 {
1395 "Routing PUT for %s terminates after %u hops at %s\n",
1396 GNUNET_h2s (&bd->key),
1397 (unsigned int) hop_count,
1399 if (cb)
1400 cb (cb_cls, GNUNET_NO);
1401 if (gds_routing.targets)
1402 GNUNET_free (gds_routing.targets);
1403 return;
1404 }
1405 GNUNET_memcpy (&(gds_routing.key), &(bd->key),
1406 sizeof (gds_routing.key));
1407 /* targets were added to @a bf by get_target_peers() */
1408
1409 gds_routing.queued = GNUNET_new (unsigned int);
1410 *(gds_routing.queued) = 0;
1411
1412 gds_routing.cb = cb;
1413 gds_routing.cb_cls = cb_cls;
1414
1415 for (unsigned int i = 0; i < gds_routing.target_count; i++)
1416 {
1417 struct PeerInfo *target = gds_routing.targets[i];
1418 struct PeerPutMessage *ppm;
1419 char buf[msize] GNUNET_ALIGN;
1420
1421 gds_routing.index = i;
1422
1423 ppm = (struct PeerPutMessage *) buf;
1424 GDS_helper_make_put_message (ppm, msize,
1426 &target->id,
1427 &target->phash,
1428 bf,
1429 &bd->key,
1430 ro,
1431 bd->type,
1432 bd->expiration_time,
1433 bd->data, bd->data_size,
1434 put_path, put_path_length,
1435 hop_count,
1437 trunc_peer,
1439 sizeof (gds_routing),
1440 &gds_routing);
1441 }
1442}
1443
1444
1449 uint16_t hop_count,
1450 const struct GNUNET_HashCode *key,
1451 const void *xquery,
1452 size_t xquery_size,
1453 struct GNUNET_BLOCK_Group *bg,
1454 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
1455{
1456 const struct GNUNET_PeerIdentity *my_identity;
1457 const struct GNUNET_HashCode *my_identity_hash;
1458 unsigned int target_count;
1459 struct PeerInfo **targets;
1460 size_t msize;
1461 size_t result_filter_size;
1462 void *result_filter;
1463
1465 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1466
1467 if (NULL == my_identity_hash)
1468 return GNUNET_NO;
1469
1470 GNUNET_assert (NULL != peer_bf);
1472 "# GET requests routed",
1473 1,
1474 GNUNET_NO);
1475 target_count = get_target_peers (key,
1476 peer_bf,
1477 hop_count,
1478 desired_replication_level,
1479 &targets);
1481 "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1483 GNUNET_h2s (key),
1485 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1486 GNUNET_assert (NULL != my_identity_hash);
1487 GNUNET_CONTAINER_bloomfilter_add (peer_bf, my_identity_hash);
1488 if (0 == target_count)
1489 {
1491 "Routing GET for %s terminates after %u hops at %s\n",
1492 GNUNET_h2s (key),
1493 (unsigned int) hop_count,
1495 return GNUNET_NO;
1496 }
1497 if (GNUNET_OK !=
1499 &result_filter,
1500 &result_filter_size))
1501 {
1502 result_filter = NULL;
1503 result_filter_size = 0;
1504 }
1505 msize = xquery_size + result_filter_size;
1506 if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1507 {
1508 GNUNET_break (0);
1509 GNUNET_free (result_filter);
1510 GNUNET_free (targets);
1511 return GNUNET_NO;
1512 }
1513 /* targets were added to @a peer_bf by get_target_peers() */
1514 /* forward request */
1515 for (unsigned int i = 0; i < target_count; i++)
1516 {
1517 struct PeerInfo *target = targets[i];
1518 struct PeerGetMessage *pgm;
1519 char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1520 char *rf;
1521
1523 "Routing GET for %s after %u hops to %s\n",
1524 GNUNET_h2s (key),
1525 (unsigned int) hop_count,
1526 GNUNET_i2s (&target->id));
1527 pgm = (struct PeerGetMessage *) buf;
1529 pgm->header.size = htons (sizeof (buf));
1530 pgm->type = htonl (type);
1531 pgm->options = htons (options);
1532 pgm->hop_count = htons (hop_count + 1);
1534 pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1537 pgm->bloomfilter,
1539 pgm->key = *key;
1540 rf = (char *) &pgm[1];
1541 GNUNET_memcpy (rf,
1542 result_filter,
1545 xquery,
1546 xquery_size);
1547 do_send (target,
1548 &pgm->header);
1549 }
1551 "# GET messages queued for transmission",
1552 target_count,
1553 GNUNET_NO);
1554 GNUNET_free (targets);
1555 GNUNET_free (result_filter);
1556 return (0 < target_count) ? GNUNET_OK : GNUNET_NO;
1557}
1558
1559
1560struct PeerInfo *
1562{
1564 target);
1565}
1566
1567
1569{
1570 struct PeerInfo *pi;
1571 struct PeerResultMessage *prm;
1574 void *block_data;
1577 bool trunc_peer_is_null;
1578 char *buf;
1579
1581 void *cb_cls;
1582};
1583
1584
1585static void
1587{
1588 if (reply->block_data)
1589 GNUNET_free (reply->block_data);
1590 if ((reply->bd.put_path_length > 0) && (reply->put_path))
1591 GNUNET_free (reply->put_path);
1592 if (reply->buf)
1593 GNUNET_free (reply->buf);
1594}
1595
1596
1597static void
1598safe_neighbours_callback (void *cls,
1600 bool success)
1601{
1602 GNUNET_break (success);
1603 if (cb)
1604 cb (cls);
1605}
1606
1607
1608static bool
1609cb_path_signed (void *cls,
1610 const struct GNUNET_CRYPTO_EddsaSignature *sig)
1611{
1612 struct GDS_NeighboursReply *reply = cls;
1613 struct PeerResultMessage *prm = reply->prm;
1614 struct GNUNET_DHT_PathElement *paths = reply->paths;
1615 unsigned int ppl = ntohs (prm->put_path_length);
1616 unsigned int get_path_length = ntohs (prm->get_path_length);
1617 void *tgt = &paths[get_path_length + ppl];
1618 void *data;
1619
1620 if (! sig)
1621 {
1623 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1624 return true;
1625 }
1626
1627 memcpy (tgt,
1628 sig,
1629 sizeof (*sig));
1630 data = tgt + sizeof (*sig);
1632 "Signing GET PATH %u/%u of %s => %s\n",
1633 ppl,
1634 get_path_length,
1635 GNUNET_h2s (&prm->key),
1636 GNUNET_B2S (sig));
1637#if SANITY_CHECKS > 1
1638 {
1639 const struct GNUNET_PeerIdentity *my_identity;
1640 struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
1641 const struct GNUNET_PeerIdentity *trunc_peer = reply->trunc_peer_is_null?
1642 NULL : &reply->trunc_peer_id;
1643
1645 GNUNET_assert (NULL != my_identity);
1646
1647 memcpy (xpaths,
1648 &paths[ppl],
1649 get_path_length * sizeof (struct GNUNET_DHT_PathElement));
1650 xpaths[get_path_length].sig = *sig;
1651 xpaths[get_path_length].pred = *my_identity;
1652 if (0 !=
1654 reply->bd.data_size,
1655 reply->bd.expiration_time,
1656 trunc_peer,
1657 paths,
1658 ppl,
1659 xpaths,
1660 get_path_length + 1,
1661 &reply->pi->id))
1662 {
1663 GNUNET_break (0);
1665 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1666 return true;
1667 }
1668 }
1669#endif
1671 reply->bd.data,
1672 reply->bd.data_size);
1673 do_send (reply->pi,
1674 &prm->header);
1676 safe_neighbours_callback (reply->cb_cls, reply->cb, true);
1677 return true;
1678}
1679
1680
1681void
1683 const struct GNUNET_DATACACHE_Block *bd,
1684 const struct GNUNET_HashCode *query_hash,
1685 unsigned int get_path_length,
1686 const struct GNUNET_DHT_PathElement *get_path,
1688 void *cb_cls)
1689{
1690 struct GNUNET_DHT_PathElement *paths;
1691 size_t msize;
1692 unsigned int ppl = bd->put_path_length;
1693 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1694 enum GNUNET_DHT_RouteOption ro = bd->ro;
1695 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1696 const struct GNUNET_PeerIdentity *trunc_peer
1697 = truncated
1698 ? &bd->trunc_peer
1699 : NULL;
1700 bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1701#if SANITY_CHECKS > 1
1702 const struct GNUNET_PeerIdentity *my_identity;
1703 unsigned int failure_offset;
1704
1706 GNUNET_assert (NULL != my_identity);
1707
1708 failure_offset
1710 bd->data_size,
1711 bd->expiration_time,
1712 trunc_peer,
1713 put_path,
1714 ppl,
1715 get_path,
1716 get_path_length,
1717 my_identity);
1718 if (0 != failure_offset)
1719 {
1720 GNUNET_assert (failure_offset <= ppl + get_path_length);
1721 GNUNET_break_op (0);
1722 if (failure_offset < ppl)
1723 {
1724 trunc_peer = &put_path[failure_offset - 1].pred;
1725 put_path += failure_offset;
1726 ppl -= failure_offset;
1727 truncated = true;
1729 }
1730 else
1731 {
1732 failure_offset -= ppl;
1733 if (0 == failure_offset)
1734 trunc_peer = &put_path[ppl - 1].pred;
1735 else
1736 trunc_peer = &get_path[failure_offset - 1].pred;
1737 ppl = 0;
1738 put_path = NULL;
1739 truncated = true;
1741 get_path += failure_offset;
1742 get_path_length -= failure_offset;
1743 }
1744 }
1745#endif
1746 msize = bd->data_size + sizeof (struct PeerResultMessage);
1747 if (msize > GNUNET_MAX_MESSAGE_SIZE)
1748 {
1749 GNUNET_break_op (0);
1750 safe_neighbours_callback (cb_cls, cb, false);
1751 return;
1752 }
1753 if (truncated)
1754 msize += sizeof (struct GNUNET_PeerIdentity);
1755 if (tracking)
1756 msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
1757 if (msize < bd->data_size)
1758 {
1759 GNUNET_break_op (0);
1760 safe_neighbours_callback (cb_cls, cb, false);
1761 return;
1762 }
1763 if ( (GNUNET_MAX_MESSAGE_SIZE - msize)
1764 / sizeof(struct GNUNET_DHT_PathElement)
1765 < (get_path_length + ppl) )
1766 {
1767 get_path_length = 0;
1768 ppl = 0;
1769 }
1770 if ( (get_path_length > UINT16_MAX) ||
1771 (ppl > UINT16_MAX) )
1772 {
1773 GNUNET_break (0);
1774 get_path_length = 0;
1775 ppl = 0;
1776 }
1777 msize += (get_path_length + ppl)
1778 * sizeof(struct GNUNET_DHT_PathElement);
1780 "Forwarding reply for key %s to peer %s\n",
1781 GNUNET_h2s (query_hash),
1782 GNUNET_i2s (&pi->id));
1784 "# RESULT messages queued for transmission",
1785 1,
1786 GNUNET_NO);
1787 {
1788 struct PeerResultMessage *prm;
1789 char buf[msize] GNUNET_ALIGN;
1790
1791 prm = (struct PeerResultMessage *) buf;
1793 prm->header.size = htons (sizeof (buf));
1794 prm->type = htonl ((uint32_t) bd->type);
1795 prm->reserved = htons (0);
1796 prm->options = htons ((uint16_t) ro);
1797 prm->put_path_length = htons ((uint16_t) ppl);
1798 prm->get_path_length = htons ((uint16_t) get_path_length);
1800 prm->key = *query_hash;
1801 if (truncated)
1802 {
1803 void *tgt = &prm[1];
1804
1805 GNUNET_memcpy (tgt,
1806 trunc_peer,
1807 sizeof (struct GNUNET_PeerIdentity));
1808 paths = (struct GNUNET_DHT_PathElement *)
1809 (tgt + sizeof (struct GNUNET_PeerIdentity));
1810 }
1811 else
1812 {
1813 paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1814 }
1815 if (NULL != put_path)
1816 {
1817 GNUNET_memcpy (paths,
1818 put_path,
1819 ppl * sizeof(struct GNUNET_DHT_PathElement));
1820 }
1821 else
1822 {
1823 GNUNET_assert (0 == ppl);
1824 }
1825 if (NULL != get_path)
1826 {
1827 GNUNET_memcpy (&paths[ppl],
1828 get_path,
1829 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1830 }
1831 else
1832 {
1833 GNUNET_assert (0 == get_path_length);
1834 }
1835 if (tracking)
1836 {
1837 struct GDS_NeighboursReply reply;
1838 const struct GNUNET_PeerIdentity *pred;
1839
1840 reply.pi = pi;
1841 GNUNET_memcpy (&reply.bd, bd, sizeof (reply.bd));
1842 reply.block_data = GNUNET_memdup (bd->data, bd->data_size);
1843 reply.put_path = GNUNET_memdup (bd->put_path,
1844 sizeof (struct GNUNET_DHT_PathElement)
1845 * bd->put_path_length);
1846
1847 reply.bd.data = reply.block_data;
1848 reply.bd.put_path = reply.put_path;
1849
1850 reply.buf = GNUNET_memdup (buf, msize);
1851 reply.prm = (struct PeerResultMessage*) reply.buf;
1852 reply.paths = (struct GNUNET_DHT_PathElement*)
1853 (reply.buf + ((const char *) paths - buf));
1854
1855 if (trunc_peer)
1856 {
1857 reply.trunc_peer_is_null = false;
1858 GNUNET_memcpy (&reply.trunc_peer_id, trunc_peer,
1859 sizeof (reply.trunc_peer_id));
1860 }
1861 else
1862 {
1863 reply.trunc_peer_is_null = true;
1864 }
1865
1866 reply.cb = cb;
1867 reply.cb_cls = cb_cls;
1868
1869 if (ppl + get_path_length > 0)
1870 pred = &paths[ppl + get_path_length - 1].pred;
1871 else if (truncated)
1872 pred = trunc_peer;
1873 else
1874 pred = NULL; /* we are first! */
1875 /* Note that the last signature in 'paths' was not initialized before,
1876 so this is crucial to avoid sending garbage. */
1878 bd->data_size,
1880 bd->expiration_time,
1881 pred,
1882 &pi->id,
1884 sizeof (reply),
1885 &reply);
1886 }
1887 else
1888 {
1889 void *data;
1890 data = &prm[1];
1892 bd->data,
1893 bd->data_size);
1894 do_send (pi,
1895 &prm->header);
1896 safe_neighbours_callback (cb_cls, cb, true);
1897 return;
1898 }
1899 }
1900}
1901
1902
1910static enum GNUNET_GenericReturnValue
1911check_dht_p2p_put (void *cls,
1912 const struct PeerPutMessage *put)
1913{
1914 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1915 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1916 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1917 uint16_t msize = ntohs (put->header.size);
1918 uint16_t putlen = ntohs (put->put_path_length);
1919 size_t xsize = (has_path
1920 ? sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1921 : 0)
1922 + (truncated
1923 ? sizeof (struct GNUNET_PeerIdentity)
1924 : 0);
1925 size_t var_meta_size
1926 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1927 + xsize;
1928
1929 (void) cls;
1930 if ( (msize <
1931 sizeof (struct PeerPutMessage) + var_meta_size) ||
1932 (putlen >
1933 (GNUNET_MAX_MESSAGE_SIZE
1934 - sizeof (struct PeerPutMessage)
1935 - xsize)
1936 / sizeof(struct GNUNET_DHT_PathElement)) )
1937 {
1938 GNUNET_break_op (0);
1939 return GNUNET_SYSERR;
1940 }
1941 if (GNUNET_BLOCK_TYPE_ANY == htonl (put->type))
1942 {
1943 GNUNET_break_op (0);
1944 return GNUNET_SYSERR;
1945 }
1946 return GNUNET_OK;
1947}
1948
1949
1950struct ForwardedDHTPut
1951{
1953
1955 void *data;
1956
1957 uint32_t hop_count;
1959};
1960
1961
1962static void
1963cb_forwarded_dht_p2p_put (void *cls,
1964 enum GNUNET_GenericReturnValue forwarded)
1965{
1966 struct ForwardedDHTPut *put = cls;
1967
1968 /* notify monitoring clients */
1969 put->block.ro |= ((GNUNET_OK == forwarded)
1971 : 0);
1973 put->hop_count,
1975
1976 if (put->put_path)
1977 GNUNET_free (put->put_path);
1978 GNUNET_free (put->data);
1979 GNUNET_free (put);
1980}
1981
1982
1989static void
1990handle_dht_p2p_put (void *cls,
1991 const struct PeerPutMessage *put)
1992{
1993 struct Target *t = cls;
1994 struct PeerInfo *peer = t->pi;
1995 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1996 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1997 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1998 uint16_t msize = ntohs (put->header.size);
1999 uint16_t putlen = ntohs (put->put_path_length);
2000 const struct GNUNET_PeerIdentity *trunc_peer
2001 = truncated
2002 ? (const struct GNUNET_PeerIdentity *) &put[1]
2003 : NULL;
2004 const struct GNUNET_DHT_PathElement *put_path
2005 = truncated
2006 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2007 : (const struct GNUNET_DHT_PathElement *) &put[1];
2008 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2009 = has_path
2010 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &put_path[putlen]
2011 : NULL;
2012 const char *data
2013 = has_path
2014 ? (const char *) &last_sig[1]
2015 : (const char *) &put_path[putlen];
2016 size_t var_meta_size
2017 = putlen * sizeof(struct GNUNET_DHT_PathElement)
2018 + (has_path ? sizeof (*last_sig) : 0)
2019 + (truncated ? sizeof (*trunc_peer) : 0);
2020 struct GNUNET_DATACACHE_Block bd = {
2021 .key = put->key,
2022 .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
2023 .type = ntohl (put->type),
2024 .ro = ro,
2025 .data_size = msize - sizeof(*put) - var_meta_size,
2026 .data = data
2027 };
2028
2029 if (NULL != trunc_peer)
2030 bd.trunc_peer = *trunc_peer;
2032 "PUT for `%s' from %s with RO (%s/%s)\n",
2033 GNUNET_h2s (&put->key),
2034 GNUNET_i2s (&peer->id),
2035 (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
2036 has_path ? "R" : "-");
2038 {
2040 "# Expired PUTs discarded",
2041 1,
2042 GNUNET_NO);
2043 return;
2044 }
2045 {
2046 /* Only call 'check_block' if that keeps our CPU load (from
2047 the cryptography) below 50% on average */
2048 static struct GNUNET_TIME_Relative avg_latency;
2049 static struct GNUNET_TIME_Absolute next_time;
2050
2051 if (GNUNET_TIME_absolute_is_past (next_time))
2052 {
2053 struct GNUNET_TIME_Absolute now
2055 struct GNUNET_TIME_Relative latency;
2057
2058 if (GNUNET_NO ==
2060 bd.type,
2061 bd.data,
2062 bd.data_size))
2063 {
2064 GNUNET_break_op (0);
2065 return;
2066 }
2067 latency = GNUNET_TIME_absolute_get_duration (now);
2068 /* Use *moving average* to estimate check_block latency */
2069 avg_latency
2072 GNUNET_TIME_relative_multiply (avg_latency,
2073 7),
2074 latency),
2075 8);
2076 /* average delay = 50% of avg_latency => 50% CPU load from crypto (at most) */
2078 = GNUNET_CRYPTO_random_u64 (avg_latency.rel_value_us > 0
2079 ? avg_latency.rel_value_us
2080 : 1LLU);
2082 }
2083 }
2084 if (! has_path)
2085 putlen = 0;
2087 "# P2P PUT requests received",
2088 1,
2089 GNUNET_NO);
2091 "# P2P PUT bytes received",
2092 msize,
2093 GNUNET_NO);
2094 {
2095 struct GNUNET_HashCode test_key;
2097
2099 bd.type,
2100 bd.data,
2101 bd.data_size,
2102 &test_key);
2103 switch (ret)
2104 {
2105 case GNUNET_YES:
2106 if (0 != GNUNET_memcmp (&test_key,
2107 &bd.key))
2108 {
2109 GNUNET_break_op (0);
2110 return;
2111 }
2112 break;
2113 case GNUNET_NO:
2114 /* cannot verify, good luck */
2115 break;
2116 case GNUNET_SYSERR:
2117 /* block type not supported, good luck */
2118 break;
2119 }
2120 }
2121
2122 {
2124 struct GNUNET_DHT_PathElement pp[putlen + 1];
2125
2131 &peer->phash));
2132 /* extend 'put path' by sender */
2133 bd.put_path = pp;
2134 bd.put_path_length = putlen + 1;
2135 if (has_path)
2136 {
2137 unsigned int failure_offset;
2138
2139 GNUNET_memcpy (pp,
2140 put_path,
2141 putlen * sizeof(struct GNUNET_DHT_PathElement));
2142 pp[putlen].pred = peer->id;
2143 pp[putlen].sig = *last_sig;
2144#if SANITY_CHECKS
2145 {
2146 const struct GNUNET_PeerIdentity *my_identity;
2148 GNUNET_assert (NULL != my_identity);
2149 /* TODO: might want to eventually implement probabilistic
2150 load-based path verification, but for now it is all or nothing */
2151 failure_offset
2153 bd.data_size,
2154 bd.expiration_time,
2155 trunc_peer,
2156 pp,
2157 putlen + 1,
2158 NULL, 0, /* get_path */
2159 my_identity);
2160 }
2161#else
2162 failure_offset = 0;
2163#endif
2164 if (0 != failure_offset)
2165 {
2166 GNUNET_break_op (0);
2168 "Recorded put path invalid at offset %u, truncating\n",
2169 failure_offset);
2170 GNUNET_assert (failure_offset <= putlen + 1);
2171 bd.put_path = &pp[failure_offset];
2172 bd.put_path_length = (putlen + 1) - failure_offset;
2174 bd.trunc_peer = pp[failure_offset - 1].pred;
2175 }
2176 }
2177 else
2178 {
2179 bd.put_path_length = 0;
2180 }
2181
2182 /* give to local clients */
2184 &bd.key,
2185 0, NULL /* get path */));
2186
2187 /* store locally */
2188 if ( (0 != (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2189 (GDS_am_closest_peer (&put->key,
2190 bf)) )
2192
2193 {
2195 GNUNET_memcpy (&forward->block, &bd, sizeof (bd));
2196
2197 if (bd.put_path_length > 0)
2198 {
2199 forward->put_path = GNUNET_memdup (
2200 bd.put_path,
2201 sizeof (struct GNUNET_DHT_PathElement) * bd.put_path_length);
2202 forward->block.put_path = forward->put_path;
2203 }
2204
2205 forward->data = GNUNET_memdup (bd.data, bd.data_size);
2206 forward->block.data = forward->data;
2207
2208 forward->desired_replication_level = ntohs (put->desired_replication_level
2209 );
2210 forward->hop_count = ntohs (put->hop_count);
2211
2212 /* route to other peers */
2214 forward->desired_replication_level,
2215 forward->hop_count,
2216 bf,
2218 forward);
2219 }
2221 }
2222}
2223
2224
2225struct BlockCls
2226{
2227 struct PeerInfo *pi;
2228 const struct GNUNET_HashCode *query_hash;
2229 struct GNUNET_BLOCK_Group *bg;
2230};
2231
2232
2241static void
2242handle_find_my_hello (struct PeerInfo *pi,
2243 const struct GNUNET_HashCode *query_hash,
2244 struct GNUNET_BLOCK_Group *bg,
2246 void *cb_cls)
2247{
2248 const struct GNUNET_HashCode *my_identity_hash;
2249 const struct GNUNET_PeerIdentity *my_identity;
2250 struct GNUNET_TIME_Absolute block_expiration;
2251 size_t block_size;
2252 void *block;
2253
2254 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
2257 "Handle finding my own HELLO %s\n",
2258 GNUNET_h2s (my_identity_hash));
2259 if (NULL == GDS_my_hello)
2260 {
2262 "# FIND PEER requests ignored due to lack of HELLO",
2263 1,
2264 GNUNET_NO);
2265 if (cb)
2266 cb (cb_cls);
2267 return;
2268 }
2269
2272 &block,
2273 &block_size,
2274 &block_expiration))
2275 {
2276 if (cb)
2277 cb (cb_cls);
2278 return;
2279 }
2280
2284 bg,
2285 my_identity_hash,
2286 NULL, 0,
2287 block,
2288 block_size))
2289 {
2290 struct GNUNET_DATACACHE_Block bd = {
2292 .expiration_time
2295 .key = *my_identity_hash,
2296 .data = block,
2297 .data_size = block_size
2298 };
2299
2301 &bd,
2302 query_hash,
2303 0, NULL /* get path */,
2304 cb,
2305 cb_cls);
2306 }
2307 else
2308 {
2310 "# FIND PEER requests ignored due to Bloomfilter",
2311 1,
2312 GNUNET_NO);
2313 if (cb)
2314 cb (cb_cls);
2315 }
2316
2317 GNUNET_free (block);
2318}
2319
2320
2329static void
2331 const struct GNUNET_HashCode *query_hash,
2332 struct GNUNET_BLOCK_Group *bg,
2334 void *cb_cls)
2335{
2336 /* Force non-random selection by hop count */
2337 struct PeerInfo *peer;
2338
2339 peer = select_peer (query_hash,
2340 NULL,
2341 GDS_NSE_get () + 1);
2342 if (NULL == peer)
2343 {
2344 /* no neighbour at all, nothing to answer with */
2345 if (cb)
2346 cb (cb_cls);
2347 return;
2348 }
2350 "Handle finding local HELLO %s\n",
2351 GNUNET_h2s (&peer->phash));
2352 if ( (NULL != peer->hello) &&
2358 bg,
2359 &peer->phash,
2360 NULL, 0, /* xquery */
2361 peer->hello,
2362 peer->hello_size)) )
2363 {
2364 struct GNUNET_DATACACHE_Block bd = {
2366 .expiration_time = peer->hello_expiration,
2367 .key = peer->phash,
2368 .data = peer->hello,
2369 .data_size = peer->hello_size
2370 };
2371
2373 &bd,
2374 query_hash,
2375 0, NULL /* get path */,
2376 cb,
2377 cb_cls);
2378 }
2379 else if (cb)
2380 cb (cb_cls);
2381}
2382
2383
2390static void
2391handle_local_result (void *cls,
2392 const struct GNUNET_DATACACHE_Block *bd)
2393{
2394 struct PeerInfo *peer = cls;
2395
2397 bd,
2398 &bd->key,
2399 0, NULL /* get path */,
2400 NULL,
2401 NULL);
2402}
2403
2404
2412static enum GNUNET_GenericReturnValue
2413check_dht_p2p_get (void *cls,
2414 const struct PeerGetMessage *get)
2415{
2416 uint16_t msize = ntohs (get->header.size);
2417 uint16_t result_filter_size = ntohs (get->result_filter_size);
2418
2419 (void) cls;
2420 if (msize < sizeof(*get) + result_filter_size)
2421 {
2422 GNUNET_break_op (0);
2423 return GNUNET_SYSERR;
2424 }
2425 return GNUNET_OK;
2426}
2427
2428
2429struct HandleCallbackGet
2430{
2431 struct Target *t;
2432 struct PeerGetMessage *get;
2434 struct GNUNET_BLOCK_Group *bg;
2436};
2437
2438
2439static void
2441{
2442 struct HandleCallbackGet *handle = cls;
2443 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2444 enum GNUNET_BLOCK_Type type = ntohl (handle->get->type);
2445 const void *result_filter = (const void *) &handle->get[1];
2446 uint16_t msize = ntohs (handle->get->header.size);
2447 uint16_t result_filter_size = ntohs (handle->get->result_filter_size);
2448 const void *xquery = result_filter + result_filter_size;
2449 size_t xquery_size = msize - sizeof (*handle->get) - result_filter_size;
2450
2451 /* remember request for routing replies
2452 TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2453 */
2454 GDS_ROUTING_add (&handle->t->pi->id,
2455 type,
2456 handle->bg, /* bg now owned by routing, but valid at least until end of this function! */
2457 options,
2458 &handle->get->key,
2459 xquery,
2460 xquery_size);
2461
2462 /* P2P forwarding */
2463 {
2464 bool forwarded = false;
2465 uint16_t desired_replication_level = ntohs (
2466 handle->get->desired_replication_level);
2467 uint16_t hop_count = ntohs (handle->get->hop_count);
2468
2470 forwarded = (GNUNET_OK ==
2472 options,
2473 desired_replication_level,
2474 hop_count,
2475 &handle->get->key,
2476 xquery,
2477 xquery_size,
2478 handle->bg,
2479 handle->peer_bf));
2481 options
2482 | (forwarded
2483 ? 0
2485 type,
2486 hop_count,
2487 desired_replication_level,
2488 &handle->get->key);
2489 }
2490 /* clean up; note that 'bg' is owned by routing now! */
2492
2493 GNUNET_free (handle->get);
2495}
2496
2497
2498static void
2500{
2501 struct HandleCallbackGet *handle = cls;
2502 enum GNUNET_BLOCK_Type type = ntohl (handle->get->type);
2503
2505 "Handle getting local HELLO %s of type %u\n",
2506 GNUNET_h2s (&handle->get->key),
2507 type);
2508
2510 {
2511 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2512 const void *result_filter = (const void *) &handle->get[1];
2513 uint16_t msize = ntohs (handle->get->header.size);
2514 uint16_t result_filter_size = ntohs (handle->get->result_filter_size);
2515 const void *xquery = result_filter + result_filter_size;
2516 size_t xquery_size = msize - sizeof (*handle->get) - result_filter_size;
2517 /* The datacache callback runs once per *result*, never on completion,
2518 so it must not carry the continuation: no result would drop the
2519 request, several would run the continuation several times. Both
2520 lookups below are synchronous. */
2522 handle->eval = GDS_DATACACHE_get_closest (&handle->get->key,
2523 type,
2524 xquery,
2525 xquery_size,
2526 handle->bg,
2528 handle->t->pi);
2529 else
2530 handle->eval = GDS_DATACACHE_handle_get (&handle->get->key,
2531 type,
2532 xquery,
2533 xquery_size,
2534 handle->bg,
2536 handle->t->pi);
2537 }
2539}
2540
2541
2542static void
2544{
2545 struct HandleCallbackGet *handle = cls;
2546 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2547
2550 &handle->get->key,
2551 handle->bg,
2553 handle);
2554 else
2556}
2557
2558
2565static void
2566handle_dht_p2p_get (void *cls,
2567 const struct PeerGetMessage *get)
2568{
2569 struct Target *t = cls;
2570 struct PeerInfo *peer = t->pi;
2571 uint16_t msize = ntohs (get->header.size);
2572 uint16_t result_filter_size = ntohs (get->result_filter_size);
2573 uint16_t hop_count = ntohs (get->hop_count);
2574 enum GNUNET_BLOCK_Type type = ntohl (get->type);
2575 enum GNUNET_DHT_RouteOption options = ntohs (get->options);
2576 const void *result_filter = (const void *) &get[1];
2577 const void *xquery = result_filter + result_filter_size;
2578 size_t xquery_size = msize - sizeof (*get) - result_filter_size;
2579
2580 /* parse and validate message */
2582 "# P2P GET requests received",
2583 1,
2584 GNUNET_NO);
2586 "# P2P GET bytes received",
2587 msize,
2588 GNUNET_NO);
2589 if (GNUNET_NO ==
2591 type,
2592 &get->key,
2593 xquery,
2594 xquery_size))
2595 {
2596 /* request invalid */
2597 GNUNET_break_op (0);
2598 return;
2599 }
2600
2601 {
2602 const struct GNUNET_PeerIdentity *my_identity;
2603 struct HandleCallbackGet *handle;
2604
2606 handle->t = t;
2607 handle->get = GNUNET_memdup (get, msize);
2609
2611 GNUNET_assert (NULL != my_identity);
2612
2613 handle->peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2618 &peer->phash));
2620 type,
2621 result_filter,
2622 result_filter_size,
2623 "filter-size",
2624 result_filter_size,
2625 NULL);
2627 "GET for %s at %s after %u hops\n",
2628 GNUNET_h2s (&get->key),
2630 (unsigned int) hop_count);
2631 /* local lookup (this may update the bg) */
2633 (GDS_am_closest_peer (&get->key,
2634 handle->peer_bf)) )
2635 {
2638 {
2640 "# P2P HELLO lookup requests processed",
2641 1,
2642 GNUNET_NO);
2644 &get->key,
2645 handle->bg,
2647 handle);
2648 }
2649 else
2651 }
2652 else
2653 {
2655 "# P2P GET requests ONLY routed",
2656 1,
2657 GNUNET_NO);
2659 }
2660 }
2661}
2662
2663
2672static void
2674 const struct GNUNET_HashCode *query_hash,
2675 unsigned int get_path_length,
2676 const struct GNUNET_DHT_PathElement *get_path)
2677{
2678 /* forward to local clients */
2680 "Forwarding reply to local clients\n");
2681 if (! GDS_CLIENTS_handle_reply (bd,
2682 query_hash,
2683 get_path_length,
2684 get_path))
2685 {
2686 GNUNET_break (0);
2687 return;
2688 }
2690 get_path,
2691 get_path_length);
2693 {
2694 struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2695 + bd->put_path_length)];
2696 struct GNUNET_DATACACHE_Block bdx = *bd;
2697
2698 if (NULL != bd->put_path)
2699 GNUNET_memcpy (xput_path,
2700 bd->put_path,
2701 bd->put_path_length * sizeof(struct
2703 GNUNET_memcpy (&xput_path[bd->put_path_length],
2704 get_path,
2705 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2706 bdx.put_path = xput_path;
2707 bdx.put_path_length += get_path_length;
2709 }
2710 /* forward to other peers */
2712 query_hash,
2713 get_path_length,
2714 get_path);
2715}
2716
2717
2725static enum GNUNET_GenericReturnValue
2726check_dht_p2p_result (void *cls,
2727 const struct PeerResultMessage *prm)
2728{
2729 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2730 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2731 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2732 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2733
2734 uint16_t get_path_length = ntohs (prm->get_path_length);
2735 uint16_t put_path_length = ntohs (prm->put_path_length);
2736 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2737 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2738
2739 (void) cls;
2740 if ( (msize < vsize) ||
2741 (msize - vsize <
2742 (get_path_length + put_path_length)
2743 * sizeof(struct GNUNET_DHT_PathElement)) ||
2744 (get_path_length >
2745 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2746 (put_path_length >
2747 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2748 {
2749 GNUNET_break_op (0);
2750 return GNUNET_SYSERR;
2751 }
2752 return GNUNET_OK;
2753}
2754
2755
2762static void
2763handle_dht_p2p_result (void *cls,
2764 const struct PeerResultMessage *prm)
2765{
2766 struct Target *t = cls;
2767 struct PeerInfo *peer = t->pi;
2768 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2769 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2770 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2771 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2772 uint16_t get_path_length = ntohs (prm->get_path_length);
2773 uint16_t put_path_length = ntohs (prm->put_path_length);
2774 const struct GNUNET_PeerIdentity *trunc_peer
2775 = truncated
2776 ? (const struct GNUNET_PeerIdentity *) &prm[1]
2777 : NULL;
2778 const struct GNUNET_DHT_PathElement *put_path
2779 = truncated
2780 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2781 : (const struct GNUNET_DHT_PathElement *) &prm[1];
2782 const struct GNUNET_DHT_PathElement *get_path
2783 = &put_path[put_path_length];
2784 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2785 = tracked
2786 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &get_path[get_path_length]
2787 : NULL;
2788 const void *data
2789 = tracked
2790 ? (const void *) &last_sig[1]
2791 : (const void *) &get_path[get_path_length];
2792 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2793 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2794 struct GNUNET_DATACACHE_Block bd = {
2796 .put_path = put_path,
2797 .put_path_length = put_path_length,
2798 .key = prm->key,
2799 .type = ntohl (prm->type),
2800 .ro = ro,
2801 .data = data,
2802 .data_size = msize - vsize - (get_path_length + put_path_length)
2803 * sizeof(struct GNUNET_DHT_PathElement)
2804 };
2805
2806 /* parse and validate message */
2808 {
2810 "# Expired results discarded",
2811 1,
2812 GNUNET_NO);
2813 return;
2814 }
2815 if (GNUNET_OK !=
2817 bd.type,
2818 bd.data,
2819 bd.data_size))
2820 {
2821 GNUNET_break_op (0);
2822 return;
2823 }
2825 "# P2P RESULTS received",
2826 1,
2827 GNUNET_NO);
2829 "# P2P RESULT bytes received",
2830 msize,
2831 GNUNET_NO);
2832 {
2834
2836 bd.type,
2837 bd.data,
2838 bd.data_size,
2839 &bd.key);
2840 if (GNUNET_NO == ret)
2841 bd.key = prm->key;
2842 }
2843
2844 /* if we got a HELLO, consider it for our own routing table */
2845 hello_check (&bd);
2846
2847 /* Need to append 'peer' to 'get_path' */
2848 if (tracked)
2849 {
2850 struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2851 struct GNUNET_DHT_PathElement *gp = xget_path;
2852 unsigned int failure_offset;
2853
2854 GNUNET_memcpy (xget_path,
2855 get_path,
2856 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2857 xget_path[get_path_length].pred = peer->id;
2858 /* use memcpy(), as last_sig may not be aligned */
2859 memcpy (&xget_path[get_path_length].sig,
2860 last_sig,
2861 sizeof (*last_sig));
2862#if SANITY_CHECKS
2863 {
2864 const struct GNUNET_PeerIdentity *my_identity;
2866 GNUNET_assert (NULL != my_identity);
2867 /* TODO: might want to eventually implement probabilistic
2868 load-based path verification, but for now it is all or nothing */
2869 failure_offset
2871 bd.data_size,
2872 bd.expiration_time,
2873 trunc_peer,
2874 put_path,
2875 put_path_length,
2876 gp,
2877 get_path_length + 1,
2878 my_identity);
2879 }
2880#else
2881 failure_offset = 0;
2882#endif
2883 if (0 != failure_offset)
2884 {
2886 "Recorded path invalid at offset %u, truncating\n",
2887 failure_offset);
2888 GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length
2889 + 1);
2890 if (failure_offset < bd.put_path_length)
2891 {
2892 /* failure on put path */
2893 trunc_peer = &bd.put_path[failure_offset - 1].pred;
2895 bd.put_path = &bd.put_path[failure_offset];
2896 bd.put_path_length -= failure_offset;
2897 truncated = true;
2898 }
2899 else
2900 {
2901 /* failure on get path */
2902 failure_offset -= bd.put_path_length;
2903 if (0 == failure_offset)
2904 trunc_peer = &bd.put_path[bd.put_path_length - 1].pred;
2905 else
2906 trunc_peer = &gp[failure_offset - 1].pred;
2907 get_path_length -= failure_offset;
2908 gp = &gp[failure_offset];
2909 bd.put_path_length = 0;
2910 bd.put_path = NULL;
2912 truncated = true;
2913 }
2914 }
2916 "Extending GET path of length %u with %s\n",
2917 get_path_length,
2918 GNUNET_i2s (&peer->id));
2919 if (truncated)
2920 {
2921 GNUNET_assert (NULL != trunc_peer);
2922 bd.trunc_peer = *trunc_peer;
2923 }
2925 &prm->key,
2926 get_path_length + 1,
2927 gp);
2928 }
2929 else
2930 {
2931 if (truncated)
2932 {
2933 GNUNET_assert (NULL != trunc_peer);
2934 bd.trunc_peer = *trunc_peer;
2935 }
2937 &prm->key,
2938 0,
2939 NULL);
2940 }
2941}
2942
2943
2951static enum GNUNET_GenericReturnValue
2952check_dht_p2p_hello (void *cls,
2953 const struct GNUNET_MessageHeader *hello)
2954{
2955 struct Target *t = cls;
2956 struct PeerInfo *peer = t->pi;
2958 size_t hellob_size;
2959 void *hellob;
2961
2963 &peer->id,
2964 &hellob,
2965 &hellob_size,
2966 &expiration);
2967 GNUNET_free (hellob);
2968 return ret;
2969}
2970
2971
2978static void
2979handle_dht_p2p_hello (void *cls,
2980 const struct GNUNET_MessageHeader *hello)
2981{
2982 struct Target *t = cls;
2983 struct PeerInfo *peer = t->pi;
2984
2985 GNUNET_free (peer->hello);
2986 peer->hello_size = 0;
2989 &peer->id,
2990 &peer->hello,
2991 &peer->hello_size,
2992 &peer->hello_expiration));
2993}
2994
2995
2996void
2997GDS_u_receive (void *cls,
2998 void **tctx,
2999 void **sctx,
3000 const void *message,
3001 size_t message_size)
3002{
3003 struct Target *t = *tctx;
3004 struct GNUNET_MQ_MessageHandler core_handlers[] = {
3005 GNUNET_MQ_hd_var_size (dht_p2p_get,
3007 struct PeerGetMessage,
3008 t),
3009 GNUNET_MQ_hd_var_size (dht_p2p_put,
3011 struct PeerPutMessage,
3012 t),
3013 GNUNET_MQ_hd_var_size (dht_p2p_result,
3015 struct PeerResultMessage,
3016 t),
3017 GNUNET_MQ_hd_var_size (dht_p2p_hello,
3019 struct GNUNET_MessageHeader,
3020 t),
3022 };
3023 const struct GNUNET_MessageHeader *mh = message;
3024
3025 (void) cls; /* the 'struct GDS_Underlay' */
3026 (void) sctx; /* our receiver address */
3027 if (NULL == t)
3028 {
3029 /* Received message claiming to originate from myself?
3030 Ignore! */
3031 GNUNET_break_op (0);
3032 return;
3033 }
3034 if (message_size < sizeof (*mh))
3035 {
3036 GNUNET_break_op (0);
3037 return;
3038 }
3039 if (message_size != ntohs (mh->size))
3040 {
3041 GNUNET_break_op (0);
3042 return;
3043 }
3045 "Handling message of type %u from peer %s\n",
3046 ntohs (mh->type),
3047 GNUNET_i2s (&t->pi->id));
3048 if (GNUNET_OK !=
3049 GNUNET_MQ_handle_message (core_handlers,
3050 mh))
3051 {
3052 GNUNET_break_op (0);
3053 return;
3054 }
3055}
3056
3057
3065void
3066GDS_try_connect (void *cls,
3067 const struct GNUNET_PeerIdentity *pid,
3068 const char *uri)
3069{
3070 const struct GNUNET_PeerIdentity *my_identity;
3071 struct GNUNET_HashCode phash;
3072 int peer_bucket;
3073 struct PeerBucket *bucket;
3074 (void) cls;
3075
3077 GNUNET_assert (NULL != my_identity);
3078
3079 if (0 == GNUNET_memcmp (my_identity, pid))
3080 {
3082 "Got a HELLO for my own PID, ignoring it\n");
3083 return; /* that's us! */
3084 }
3085 GNUNET_CRYPTO_hash (pid,
3086 sizeof(*pid),
3087 &phash);
3088 peer_bucket = find_bucket (&phash);
3089 GNUNET_assert ( (peer_bucket >= 0) &&
3090 ((unsigned int) peer_bucket < MAX_BUCKETS));
3091 bucket = &k_buckets[peer_bucket];
3092 for (struct PeerInfo *pi = bucket->head;
3093 NULL != pi;
3094 pi = pi->next)
3095 if (0 ==
3096 GNUNET_memcmp (&pi->id,
3097 pid))
3098 {
3099 /* already connected */
3100 GDS_u_try_connect (pid,
3101 uri);
3102 return;
3103 }
3104 if (bucket->peers_size >= bucket_size)
3105 return; /* do not care */
3107 "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
3108 GNUNET_i2s (pid),
3109 uri,
3110 peer_bucket,
3111 bucket->peers_size,
3112 bucket_size);
3113 /* new peer that we like! */
3114 GDS_u_try_connect (pid,
3115 uri);
3116}
3117
3118
3124void
3126{
3127 for (unsigned int bc = 0; bc<closest_bucket; bc++)
3128 {
3129 struct PeerBucket *bucket = &k_buckets[bc];
3130 unsigned int count = 0;
3131
3132 for (struct PeerInfo *pos = bucket->head;
3133 NULL != pos;
3134 pos = pos->next)
3135 {
3136 if (count >= bucket_size)
3137 break; /* we only consider first #bucket_size entries per bucket */
3138 count++;
3139 do_send (pos,
3140 msg);
3141 }
3142 }
3143}
3144
3145
3148{
3149
3150 unsigned long long temp_config_num;
3151
3154 "DHT",
3155 "DISABLE_TRY_CONNECT");
3156 if (GNUNET_OK ==
3158 "DHT",
3159 "bucket_size",
3160 &temp_config_num))
3161 bucket_size = (unsigned int) temp_config_num;
3164 "DHT",
3165 "CACHE_RESULTS");
3167 GNUNET_YES);
3168 return GNUNET_OK;
3169}
3170
3171
3172void
3174{
3175 if (NULL == all_connected_peers)
3176 return;
3177 GNUNET_assert (0 ==
3180 all_connected_peers = NULL;
3181 GNUNET_assert (NULL == find_peer_task);
3182}
3183
3184
3185const struct GNUNET_PeerIdentity *
3187{
3189}
3190
3191
3192/* end of gnunet-service-dht_neighbours.c */
struct GNUNET_GETOPT_CommandLineOption options[]
Definition 002.c:5
struct GNUNET_MessageHeader * msg
Definition 005.c:2
static mp_limb_t u[(((256)+GMP_NUMB_BITS - 1)/GMP_NUMB_BITS)]
#define DHT_BLOOM_SIZE
Size of the bloom filter the DHT uses to filter peers.
Definition dht.h:34
bool GDS_helper_make_put_message(struct PeerPutMessage *ppm, size_t msize, const struct GNUNET_CRYPTO_EddsaPrivateKey *sk, const struct GNUNET_PeerIdentity *target, const struct GNUNET_HashCode *target_hash, const struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_HashCode *block_key, enum GNUNET_DHT_RouteOption ro, enum GNUNET_BLOCK_Type block_type, struct GNUNET_TIME_Absolute block_expiration_time, const uint8_t *block_data, size_t block_data_len, const struct GNUNET_DHT_PathElement *put_path, unsigned int put_path_len, size_t hop_count, uint32_t desired_replication_level, const struct GNUNET_PeerIdentity *trunc_peer, GDS_HelperMsgCallback cb, size_t cb_data_size, void *cb_data)
Definition dht_helper.c:326
bool GDS_helper_sign_path(const void *data, size_t data_size, const struct GNUNET_CRYPTO_EddsaPrivateKey *sk, struct GNUNET_TIME_Absolute exp_time, const struct GNUNET_PeerIdentity *pred, const struct GNUNET_PeerIdentity *succ, GDS_HelperCallback cb, size_t cb_data_size, void *cb_data)
Sign that we are routing a message from pred to succ.
Definition dht_helper.c:226
enum GNUNET_GenericReturnValue GDS_helper_put_message_get_size(size_t *msize_out, const struct GNUNET_PeerIdentity *my_identity, enum GNUNET_DHT_RouteOption ro_in, enum GNUNET_DHT_RouteOption *ro_out, struct GNUNET_TIME_Absolute block_expiration_time, const uint8_t *block_data, size_t block_data_len, const struct GNUNET_DHT_PathElement *put_path_in, unsigned int put_path_len_in, unsigned int *put_path_len_out, const struct GNUNET_PeerIdentity *trunc_peer, struct GNUNET_PeerIdentity *trunc_peer_out, bool *truncated)
Definition dht_helper.c:96
struct GNUNET_PILS_Handle * GDS_pils
Handle for the pils service.
static int forward
Search direction: forward.
Definition gnunet-abd.c:163
static int ret
Final status code.
Definition gnunet-arm.c:93
static struct GNUNET_CADET_Handle * mh
Cadet handle.
static char * data
The data to insert into the dht.
struct GNUNET_HashCode key
The key used in the DHT.
static struct GNUNET_TIME_Relative expiration
User supplied expiration value.
static int get
Get DID Documement for DID Flag.
Definition gnunet-did.c:63
static struct GNUNET_FS_Handle * ctx
static struct GNUNET_SCHEDULER_Task * t
Main task.
static char * value
Value of the record to add/remove.
static uint32_t type
Type string converted to DNS type value.
static size_t data_size
Number of bytes in data.
static struct GNUNET_NSE_Handle * nse
The handle to the NSE service.
Definition gnunet-nse.c:34
static struct GNUNET_FS_Uri * uri
Value of URI provided on command-line (when not publishing a file but just creating UBlocks to refer ...
static struct GNUNET_PeerIdentity my_identity
Identity of this peer.
static unsigned long long reserved
How much space have we currently reserved?
double GDS_NSE_get(void)
Return the current NSE.
struct GNUNET_MessageHeader * GDS_my_hello
Our HELLO.
struct GNUNET_DHTU_PreferenceHandle * GDS_u_hold(struct GDS_Underlay *u, struct GNUNET_DHTU_Target *target)
Create a hold on target at underlay u.
void GDS_u_send(struct GDS_Underlay *u, struct GNUNET_DHTU_Target *target, const void *msg, size_t msg_size, GNUNET_SCHEDULER_TaskCallback finished_cb, void *finished_cb_cls)
Send message to some other participant over the network.
void GDS_u_drop(struct GDS_Underlay *u, struct GNUNET_DHTU_PreferenceHandle *ph)
Drop a hold ph from underlay u.
void GDS_u_try_connect(const struct GNUNET_PeerIdentity *pid, const char *address)
Ask all underlays to connect to peer pid at address.
void GDS_CLIENTS_process_get(enum GNUNET_DHT_RouteOption options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, const struct GNUNET_HashCode *key)
Check if some client is monitoring GET messages and notify them in that case.
void GDS_CLIENTS_process_get_resp(const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_DHT_PathElement *get_path, unsigned int get_path_length)
Check if some client is monitoring GET RESP messages and notify them in that case.
struct GNUNET_STATISTICS_Handle * GDS_stats
Handle for the statistics service.
struct GNUNET_BLOCK_Context * GDS_block_context
Our handle to the BLOCK library.
void GDS_CLIENTS_retry_requests(void)
Our routing table gained a peer.
void GDS_CLIENTS_process_put(const struct GNUNET_DATACACHE_Block *bd, uint32_t hop_count, uint32_t desired_replication_level)
Check if some client is monitoring PUT messages and notify them in that case.
bool GDS_CLIENTS_handle_reply(const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path)
Handle a reply we've received from another peer.
const struct GNUNET_CONFIGURATION_Handle * GDS_cfg
Configuration we use.
#define MINIMUM_LOG_NSE
Floor for the log of the network size estimate, and the value we use before the NSE service has told ...
enum GNUNET_BLOCK_ReplyEvaluationResult GDS_DATACACHE_get_closest(const struct GNUNET_HashCode *key, enum GNUNET_BLOCK_Type type, const void *xquery, size_t xquery_size, struct GNUNET_BLOCK_Group *bg, GDS_DATACACHE_GetCallback cb, void *cb_cls)
Handle a request for data close to a key that we have received from another peer.
enum GNUNET_BLOCK_ReplyEvaluationResult GDS_DATACACHE_handle_get(const struct GNUNET_HashCode *key, enum GNUNET_BLOCK_Type type, const void *xquery, size_t xquery_size, struct GNUNET_BLOCK_Group *bg, GDS_DATACACHE_GetCallback gc, void *gc_cls)
Handle a GET request we've received from another peer.
void GDS_DATACACHE_handle_put(const struct GNUNET_DATACACHE_Block *bd)
Handle a datum we've received from another peer.
static void send_find_peer_message(void *cls)
Task to send a find peer message for our own peer identifier so that we can find the closest peers in...
static void handle_dht_p2p_result(void *cls, const struct PeerResultMessage *prm)
Core handler for p2p result messages.
void GDS_NEIGHBOURS_handle_reply(struct PeerInfo *pi, const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path, GNUNET_SCHEDULER_TaskCallback cb, void *cb_cls)
Handle a reply (route to origin).
#define MAXIMUM_PENDING_PER_PEER
Maximum allowed number of pending messages per peer.
static int disable_try_connect
Option for testing that disables the 'connect' function of the DHT.
void GDS_try_connect(void *cls, const struct GNUNET_PeerIdentity *pid, const char *uri)
Callback function used to extract URIs from a builder.
static void cleanup_neighbours_reply(struct GDS_NeighboursReply *reply)
struct PeerInfo * GDS_NEIGHBOURS_lookup_peer(const struct GNUNET_PeerIdentity *target)
Lookup peer by peer's identity.
static void handle_find_my_hello(struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg, GNUNET_SCHEDULER_TaskCallback cb, void *cb_cls)
We have received a request for a HELLO.
static unsigned int newly_found_peers
How many peers have we added since we sent out our last find peer request?
static void send_done_cb(void *cls)
Function called whenever we finished sending to a target.
static struct PeerInfo * select_peer(const struct GNUNET_HashCode *key, const struct GNUNET_CONTAINER_BloomFilter *bloom, uint32_t hops)
Select a peer from the routing table that would be a good routing destination for sending a message f...
#define DEFAULT_BUCKET_SIZE
What is the maximum number of peers in a given bucket.
void GDS_NEIGHBOURS_done()
Shutdown neighbours subsystem.
void GDS_u_disconnect(void *ctx)
Function to call when we disconnected from a peer and can henceforth cannot transmit to that peer any...
static void handle_dht_p2p_hello(void *cls, const struct GNUNET_MessageHeader *hello)
Core handler for p2p HELLO messages.
static void cb_forwarded_dht_p2p_put(void *cls, enum GNUNET_GenericReturnValue forwarded)
static void handle_dht_p2p_get(void *cls, const struct PeerGetMessage *get)
Core handler for p2p get requests.
void GDS_NEIGHBOURS_broadcast(const struct GNUNET_MessageHeader *msg)
Send msg to all peers in our buckets.
#define FIND_PEER_REPLICATION_LEVEL
Desired replication level for FIND PEER requests.
static unsigned int get_forward_count(uint16_t hop_count, uint16_t target_replication)
To how many peers should we (on average) forward the request to obtain the desired target_replication...
static void do_send(struct PeerInfo *pi, const struct GNUNET_MessageHeader *msg)
Send msg to pi.
static int find_bucket(const struct GNUNET_HashCode *hc)
Find the optimal bucket for this key.
static enum GNUNET_GenericReturnValue check_dht_p2p_put(void *cls, const struct PeerPutMessage *put)
Check validity of a p2p put request.
static struct GNUNET_CONTAINER_MultiPeerMap * all_connected_peers
Hash map of all CORE-connected peers, for easy removal from k_buckets on disconnect.
static void handle_local_result(void *cls, const struct GNUNET_DATACACHE_Block *bd)
Handle an exact result from local datacache for a GET operation.
static void cb_handle_dht_p2p_get_my_hello(void *cls)
#define DHT_MINIMUM_FIND_PEER_INTERVAL
How long at least to wait before sending another find peer request.
static int cache_results
Do we cache all results that we are routing in the local datacache?
void GDS_u_connect(void *cls, struct GNUNET_DHTU_Target *target, const struct GNUNET_PeerIdentity *pid, void **ctx)
Function to call when we connect to a peer and can henceforth transmit to that peer.
static enum GNUNET_GenericReturnValue check_dht_p2p_result(void *cls, const struct PeerResultMessage *prm)
Check validity of p2p result message.
static struct GNUNET_SCHEDULER_Task * find_peer_task
Task that sends FIND PEER requests.
static bool cb_routing_put_message(void *cls, size_t msize, struct PeerPutMessage *ppm)
#define MAX_BUCKETS
How many buckets will we allow in total.
static enum GNUNET_GenericReturnValue check_dht_p2p_get(void *cls, const struct PeerGetMessage *get)
Check validity of p2p get request.
static enum GNUNET_GenericReturnValue check_dht_p2p_hello(void *cls, const struct GNUNET_MessageHeader *hello)
Check validity of a p2p hello message.
static void cb_handle_dht_p2p_get_local_hello(void *cls)
static unsigned int get_target_peers(const struct GNUNET_HashCode *key, struct GNUNET_CONTAINER_BloomFilter *bloom, uint16_t hop_count, uint16_t target_replication, struct PeerInfo ***targets)
Compute the set of peers that the given request should be forwarded to.
static void hello_check(const struct GNUNET_DATACACHE_Block *bd)
If we got a HELLO, consider it for our own routing table.
static void safe_neighbours_callback(void *cls, GNUNET_SCHEDULER_TaskCallback cb, bool success)
static enum GNUNET_GenericReturnValue add_known_to_bloom(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Add each of the peers we already know to the Bloom filter of the request so that we don't get duplica...
static void handle_find_local_hello(struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg, GNUNET_SCHEDULER_TaskCallback cb, void *cb_cls)
We have received a request for nearby HELLOs.
static unsigned int bucket_size
Maximum size for each bucket.
static void process_reply_with_path(const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path)
Process a reply, after the get_path has been updated.
enum GNUNET_GenericReturnValue GDS_am_closest_peer(const struct GNUNET_HashCode *key, const struct GNUNET_CONTAINER_BloomFilter *bloom)
Check whether my identity is closer than any known peers.
static unsigned int closest_bucket
One past the deepest currently used bucket, initially 0 (no peers at all).
static bool cb_path_signed(void *cls, const struct GNUNET_CRYPTO_EddsaSignature *sig)
static struct PeerBucket k_buckets[sizeof(struct GNUNET_HashCode) *8]
The buckets.
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_init()
Initialize neighbours subsystem.
static void cb_handle_dht_p2p_get_local_result(void *cls)
static void update_hold(struct PeerBucket *bucket)
The list of the first bucket_size peers of bucket changed.
void GDS_u_receive(void *cls, void **tctx, void **sctx, const void *message, size_t message_size)
Function to call when we receive a message.
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_handle_get(enum GNUNET_BLOCK_Type type, enum GNUNET_DHT_RouteOption options, uint16_t desired_replication_level, uint16_t hop_count, const struct GNUNET_HashCode *key, const void *xquery, size_t xquery_size, struct GNUNET_BLOCK_Group *bg, struct GNUNET_CONTAINER_BloomFilter *peer_bf)
Perform a GET operation.
void GDS_NEIGHBOURS_handle_put(const struct GNUNET_DATACACHE_Block *bd, uint16_t desired_replication_level, uint16_t hop_count, struct GNUNET_CONTAINER_BloomFilter *bf, GDS_PutOperationCallback cb, void *cb_cls)
Perform a PUT operation.
const struct GNUNET_PeerIdentity * GDS_NEIGHBOURS_get_id()
Get the ID of the local node.
static void handle_dht_p2p_put(void *cls, const struct PeerPutMessage *put)
Core handler for p2p put requests.
#define DHT_AVG_FIND_PEER_INTERVAL
How long to additionally wait on average per bucket_size to send out the FIND PEER requests if we did...
void(* GDS_PutOperationCallback)(void *cls, enum GNUNET_GenericReturnValue forwarded)
void GDS_ROUTING_add(const struct GNUNET_PeerIdentity *sender, enum GNUNET_BLOCK_Type type, struct GNUNET_BLOCK_Group *bg, enum GNUNET_DHT_RouteOption options, const struct GNUNET_HashCode *key, const void *xquery, size_t xquery_size)
Add a new entry to our routing table.
void GDS_ROUTING_process(const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path)
Handle a reply (route to origin).
static struct GNUNET_VPN_Handle * handle
Handle to vpn service.
Definition gnunet-vpn.c:35
GNUNET_BLOCK_Type
WARNING: This header is generated! In order to add DHT block types, you must register them in GANA,...
@ GNUNET_BLOCK_TYPE_ANY
Identifier for any block.
@ GNUNET_BLOCK_TYPE_DHT_HELLO
Type of a block that contains a DHT-NG HELLO for a peer.
const struct GNUNET_HashCode * GNUNET_PILS_get_identity_hash(const struct GNUNET_PILS_Handle *handle)
Return the hash of the current peer identity from a given handle.
Definition pils_api.c:884
const struct GNUNET_CRYPTO_EddsaPrivateKey * GNUNET_PILS_get_private_key(const struct GNUNET_PILS_Handle *handle)
Return the private key of the current peer identity.
Definition pils_api.c:943
const struct GNUNET_PeerIdentity * GNUNET_PILS_get_identity(const struct GNUNET_PILS_Handle *handle)
Return the current peer identity of a given handle.
Definition pils_api.c:875
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message,...
enum GNUNET_GenericReturnValue GNUNET_BLOCK_group_set_seen(struct GNUNET_BLOCK_Group *bg, const struct GNUNET_HashCode *seen_results, unsigned int seen_results_count)
Update block group to filter out the given results.
Definition block.c:365
enum GNUNET_BLOCK_ReplyEvaluationResult GNUNET_BLOCK_check_reply(struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, struct GNUNET_BLOCK_Group *group, const struct GNUNET_HashCode *query, const void *xquery, size_t xquery_size, const void *reply_block, size_t reply_block_size)
Function called to validate if a reply is good for a particular query.
Definition block.c:339
enum GNUNET_GenericReturnValue GNUNET_BLOCK_check_block(struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size)
Function called to validate a block.
Definition block.c:321
enum GNUNET_GenericReturnValue GNUNET_BLOCK_check_query(struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, const struct GNUNET_HashCode *query, const void *xquery, size_t xquery_size)
Function called to validate a request.
Definition block.c:298
GNUNET_BLOCK_ReplyEvaluationResult
Possible ways for how a block may relate to a query.
void GNUNET_BLOCK_group_destroy(struct GNUNET_BLOCK_Group *bg)
Destroy resources used by a block group.
Definition block.c:194
enum GNUNET_GenericReturnValue GNUNET_BLOCK_group_serialize(struct GNUNET_BLOCK_Group *bg, void **raw_data, size_t *raw_data_size)
Serialize state of a block group.
Definition block.c:177
struct GNUNET_BLOCK_Group * GNUNET_BLOCK_group_create(struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, const void *raw_data, size_t raw_data_size,...)
Create a new block group.
Definition block.c:249
enum GNUNET_GenericReturnValue GNUNET_BLOCK_get_key(struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, struct GNUNET_HashCode *key)
Function called to obtain the key for a block.
Definition block.c:278
@ GNUNET_BLOCK_REPLY_OK_MORE
Valid result, and there may be more.
@ GNUNET_BLOCK_REPLY_OK_LAST
Last possible valid result.
struct GNUNET_CONTAINER_BloomFilter * GNUNET_CONTAINER_bloomfilter_init(const char *data, size_t size, unsigned int k)
Create a Bloom filter from raw bits.
void GNUNET_CONTAINER_bloomfilter_add(struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_HashCode *e)
Add an element to the filter.
bool GNUNET_CONTAINER_bloomfilter_test(const struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_HashCode *e)
Test if an element is in the filter.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_bloomfilter_get_raw_data(const struct GNUNET_CONTAINER_BloomFilter *bf, char *data, size_t size)
Copy the raw data of this Bloom filter into the given data array.
void GNUNET_CONTAINER_bloomfilter_free(struct GNUNET_CONTAINER_BloomFilter *bf)
Free the space associated with a filter in memory, flush to drive if needed (do not free the space on...
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
#define GNUNET_CONSTANTS_BLOOMFILTER_K
K-value that must be used for the bloom filters in 'GET' queries.
uint64_t GNUNET_CRYPTO_random_u64(uint64_t max)
Generate a random unsigned 64-bit value.
uint32_t GNUNET_CRYPTO_random_u32(uint32_t i)
Produce a random value.
GNUNET_DHT_RouteOption
Options for routing.
#define GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL
Maximum allowed replication level for all requests.
unsigned int GNUNET_DHT_verify_path(const void *data, size_t data_size, struct GNUNET_TIME_Absolute exp_time, const struct GNUNET_PeerIdentity *trunc_peer, const struct GNUNET_DHT_PathElement *put_path, unsigned int put_path_len, const struct GNUNET_DHT_PathElement *get_path, unsigned int get_path_len, const struct GNUNET_PeerIdentity *me)
Verify signatures on a path consisting of put_path and get_path in reverse order (starting at the las...
Definition dht_api.c:1354
@ GNUNET_DHT_RO_TRUNCATED
Flag set if the path was truncated.
@ GNUNET_DHT_RO_RECORD_ROUTE
We should keep track of the route that the message took in the P2P network.
@ GNUNET_DHT_RO_LAST_HOP
Flag given to monitors if this was the last hop for a GET/PUT.
@ GNUNET_DHT_RO_FIND_APPROXIMATE
Approximate results are fine.
@ GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE
Each peer along the way should process the request (otherwise only peers locally closest to the key w...
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition crypto_hash.c:40
void GNUNET_CRYPTO_hash_xor(const struct GNUNET_HashCode *a, const struct GNUNET_HashCode *b, struct GNUNET_HashCode *result)
compute result = a ^ b
int GNUNET_CRYPTO_hash_xorcmp(const struct GNUNET_HashCode *h1, const struct GNUNET_HashCode *h2, const struct GNUNET_HashCode *target)
Find out which of the two GNUNET_CRYPTO_hash codes is closer to target in the XOR metric (Kademlia).
void * GNUNET_CONTAINER_multipeermap_get(const struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key)
Given a key find a value in the map matching the key.
void GNUNET_CONTAINER_multipeermap_destroy(struct GNUNET_CONTAINER_MultiPeerMap *map)
Destroy a hash map.
int GNUNET_CONTAINER_multipeermap_iterate(struct GNUNET_CONTAINER_MultiPeerMap *map, GNUNET_CONTAINER_PeerMapIterator it, void *it_cls)
Iterate over all entries in the map.
struct GNUNET_CONTAINER_MultiPeerMap * GNUNET_CONTAINER_multipeermap_create(unsigned int len, int do_not_copy_keys)
Create a multi peer map (hash map for public keys of peers).
unsigned int GNUNET_CONTAINER_multipeermap_size(const struct GNUNET_CONTAINER_MultiPeerMap *map)
Get the number of key-value pairs in the map.
int GNUNET_CONTAINER_multipeermap_put(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multipeermap_remove(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, const void *value)
Remove the given key-value pair from the map.
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY
There must only be one value per key; storing a value should fail if a value under the same key alrea...
void GNUNET_HELLO_parser_free(struct GNUNET_HELLO_Parser *parser)
Release resources of a builder.
Definition hello-uri.c:380
enum GNUNET_GenericReturnValue GNUNET_HELLO_dht_msg_to_block(const struct GNUNET_MessageHeader *hello, const struct GNUNET_PeerIdentity *pid, void **block, size_t *block_size, struct GNUNET_TIME_Absolute *block_expiration)
Convert a DHT hello message to a HELLO block.
Definition hello-uri.c:1061
const struct GNUNET_PeerIdentity * GNUNET_HELLO_parser_iterate(const struct GNUNET_HELLO_Parser *parser, GNUNET_HELLO_UriCallback uc, void *uc_cls)
Iterate over URIs in a parser.
Definition hello-uri.c:1039
#define GNUNET_HELLO_ADDRESS_EXPIRATION
For how long are HELLO signatures valid?
struct GNUNET_HELLO_Parser * GNUNET_HELLO_parser_from_block(const void *block, size_t block_size)
Parse block.
Definition hello-uri.c:569
unsigned int GNUNET_CRYPTO_hash_count_leading_zeros(const struct GNUNET_HashCode *h)
Count the number of leading 0 bits in h.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
#define GNUNET_B2S(obj)
Convert a fixed-sized object to a string using GNUNET_b2s().
#define GNUNET_MAX(a, b)
#define GNUNET_NZL(l)
Macro used to avoid using 0 for the length of a variable-size array (Non-Zero-Length).
#define GNUNET_NETWORK_STRUCT_END
Define as empty, GNUNET_PACKED should suffice, but this won't work on W32;.
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
#define GNUNET_ALIGN
gcc-ism to force alignment; we use this to align char-arrays that may then be cast to 'struct's.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
#define GNUNET_MIN(a, b)
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
#define GNUNET_PACKED
gcc-ism to get packed structs.
uint32_t bits[512/8/sizeof(uint32_t)]
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
enum GNUNET_GenericReturnValue GNUNET_MQ_handle_message(const struct GNUNET_MQ_MessageHandler *handlers, const struct GNUNET_MessageHeader *mh)
Call the message message handler that was registered for the type of the given message in the given h...
Definition mq.c:281
#define GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO
HELLO advertising a neighbours addresses.
#define GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT
Data is returned to peer from DHT.
#define GNUNET_MESSAGE_TYPE_DHT_P2P_GET
Peer tries to find data in DHT.
#define GNUNET_MESSAGE_TYPE_DHT_P2P_PUT
Peer is storing data in DHT.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition scheduler.c:1310
void(* GNUNET_SCHEDULER_TaskCallback)(void *cls)
Signature of the main function of a task.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition scheduler.c:1283
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration(struct GNUNET_TIME_Absolute whence)
Get the duration of an operation as the difference of the current time and the given start time "henc...
Definition time.c:438
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition time.c:111
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_ntoh(struct GNUNET_TIME_AbsoluteNBO a)
Convert absolute time from network byte order.
Definition time.c:737
struct GNUNET_TIME_Relative GNUNET_TIME_relative_add(struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative a2)
Add relative times together.
Definition time.c:583
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition time.c:316
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Multiply relative time by a given factor.
Definition time.c:486
struct GNUNET_TIME_Relative GNUNET_TIME_relative_divide(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Divide relative time by a given factor.
Definition time.c:548
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition time.c:636
bool GNUNET_TIME_absolute_is_past(struct GNUNET_TIME_Absolute abs)
Test if abs is truly in the past (excluding now).
Definition time.c:667
static struct GNUNET_TIME_Relative delta
Definition speedup.c:36
const struct GNUNET_HashCode * query_hash
struct GNUNET_BLOCK_Group * bg
struct GNUNET_DATACACHE_Block block
struct GNUNET_DHT_PathElement * put_path
struct GNUNET_DHT_PathElement * paths
struct GNUNET_PeerIdentity trunc_peer_id
struct PeerResultMessage * prm
GNUNET_SCHEDULER_TaskCallback cb
struct GNUNET_DHT_PathElement * put_path
struct GNUNET_DATACACHE_Block bd
Information we keep per underlay.
Internal representation of the hash map.
an ECC signature using EdDSA.
Information about a block stored in the datacache.
const struct GNUNET_DHT_PathElement * put_path
PUT path taken by the block, array of peer identities.
enum GNUNET_BLOCK_Type type
Type of the block.
const void * data
Actual block data.
enum GNUNET_DHT_RouteOption ro
Options for routing for the block.
struct GNUNET_PeerIdentity trunc_peer
If the path was truncated, this is the peer ID at which the path was truncated.
struct GNUNET_HashCode key
Key of the block.
size_t data_size
Number of bytes in data.
unsigned int put_path_length
Length of the put_path array.
struct GNUNET_TIME_Absolute expiration_time
When does the block expire?
Opaque handle expressing a preference of the DHT to keep a particular target connected.
Opaque handle that the underlay offers for the target peer when sending messages to another peer.
A (signed) path tracking a block's flow through the DHT is represented by an array of path elements,...
struct GNUNET_PeerIdentity pred
Previous peer on the path (matches "pred" in the signed field).
struct GNUNET_CRYPTO_EddsaSignature sig
Signature affirming the hop of type GNUNET_SIGNATURE_PURPOSE_DHT_HOP.
Context for parsing HELLOs.
Definition hello-uri.c:233
A 512-bit hashcode.
Message handler for a specific message type.
Header for all communications.
The identity of the host (wraps the signing key of the peer).
Entry in list of pending tasks.
Definition scheduler.c:141
struct GNUNET_SCHEDULER_Task * next
This is a linked list.
Definition scheduler.c:145
Time for absolute time used by GNUnet, in microseconds and in network byte order.
Time for absolute times used by GNUnet, in microseconds.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
struct GNUNET_CONTAINER_BloomFilter * peer_bf
struct GNUNET_BLOCK_Group * bg
enum GNUNET_BLOCK_ReplyEvaluationResult eval
Peers are grouped into buckets.
struct PeerInfo * head
Head of DLL.
struct PeerInfo * tail
Tail of DLL.
unsigned int peers_size
Number of peers in the bucket.
uint16_t result_filter_size
Size of the result filter.
char bloomfilter[128]
Bloomfilter (for peer identities) to stop circular routes.
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_DHT_P2P_GET.
uint16_t desired_replication_level
Desired replication level for this request.
uint16_t options
Processing options.
struct GNUNET_HashCode key
The key we are looking for.
uint32_t type
Desired content type.
Entry for a peer in a bucket.
struct GNUNET_TIME_Absolute hello_expiration
When does our HELLO from this peer expire?
size_t hello_size
Number of bytes in hello.
struct PeerInfo * next
Next peer entry (DLL)
struct GNUNET_PeerIdentity id
What is the identity of the peer?
struct Target * t_tail
Tail of DLL of targets for this peer.
struct PeerInfo * prev
Prev peer entry (DLL)
struct GNUNET_HashCode phash
Hash of id.
int peer_bucket
Which bucket is this peer in?
struct Target * t_head
Head of DLL of targets for this peer.
void * hello
Block with a HELLO of this peer.
P2P PUT message.
Definition dht.h:429
uint16_t desired_replication_level
Replication level for this message.
Definition dht.h:453
uint16_t hop_count
Hop count.
Definition dht.h:448
uint32_t type
Content type, must not be zero.
Definition dht.h:438
char bloomfilter[128]
Bloomfilter (for peer identities) to stop circular routes.
Definition dht.h:468
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_DHT_P2P_PUT.
Definition dht.h:433
struct GNUNET_HashCode key
The key we are storing under.
Definition dht.h:473
uint16_t options
Processing options.
Definition dht.h:443
struct GNUNET_TIME_AbsoluteNBO expiration_time
When does the content expire?
Definition dht.h:463
uint16_t put_path_length
Length of the PUT path that follows (if tracked).
Definition dht.h:458
uint16_t get_path_length
Length of the GET path that follows (if tracked).
uint16_t options
Message options, actually an 'enum GNUNET_DHT_RouteOption' value in NBO.
struct GNUNET_HashCode key
The key of the corresponding GET request.
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT.
uint16_t put_path_length
Length of the PUT path that follows (if tracked).
struct GNUNET_TIME_AbsoluteNBO expiration_time
When does the content expire?
List of targets that we can use to reach this peer.
struct Target * prev
Kept in a DLL.
struct PeerInfo * pi
Peer this is a target for.
struct Target * next
Kept in a DLL.
unsigned int load
Set to number of messages are waiting for the transmission to finish.
struct GNUNET_DHTU_PreferenceHandle * ph
Handle used to 'hold' the connection to this peer.
struct GDS_Underlay * u
Underlay providing this target.
struct GNUNET_DHTU_Target * utarget
Handle for sending messages to this peer.
bool dropped
Set to true if the target was dropped, but we could not clean up yet because busy was also true.

◆ SANITY_CHECKS

#define SANITY_CHECKS   2

Enable slow sanity checks to debug issues.

TODO: might want to eventually implement probabilistic load-based path verification, but for now it is all or nothing based on this define.

0: do not check – if signatures become performance critical 1: check all external inputs – normal production for now 2: check internal computations as well – for debugging

Definition at line 56 of file gnunet-service-dht_neighbours.c.

◆ MAX_BUCKETS

#define MAX_BUCKETS   sizeof(struct GNUNET_HashCode) * 8

How many buckets will we allow in total.

Definition at line 61 of file gnunet-service-dht_neighbours.c.

◆ DEFAULT_BUCKET_SIZE

#define DEFAULT_BUCKET_SIZE   8

What is the maximum number of peers in a given bucket.

Definition at line 66 of file gnunet-service-dht_neighbours.c.

◆ FIND_PEER_REPLICATION_LEVEL

#define FIND_PEER_REPLICATION_LEVEL   4

Desired replication level for FIND PEER requests.

Definition at line 71 of file gnunet-service-dht_neighbours.c.

◆ MAXIMUM_PENDING_PER_PEER

#define MAXIMUM_PENDING_PER_PEER   64

Maximum allowed number of pending messages per peer.

Definition at line 76 of file gnunet-service-dht_neighbours.c.

◆ DHT_MINIMUM_FIND_PEER_INTERVAL

#define DHT_MINIMUM_FIND_PEER_INTERVAL
Value:
#define GNUNET_TIME_UNIT_MINUTES
One minute.

How long at least to wait before sending another find peer request.

This is basically the frequency at which we will usually send out requests when we are 'perfectly' connected.

Definition at line 83 of file gnunet-service-dht_neighbours.c.

◆ DHT_AVG_FIND_PEER_INTERVAL

#define DHT_AVG_FIND_PEER_INTERVAL
Value:
#define GNUNET_TIME_UNIT_SECONDS
One second.

How long to additionally wait on average per bucket_size to send out the FIND PEER requests if we did successfully connect (!) to a a new peer and added it to a bucket (as counted in newly_found_peers).

This time is Multiplied by 100 * newly_found_peers / bucket_size to get the new delay for finding peers (the DHT_MINIMUM_FIND_PEER_INTERVAL is still added on top). Also the range in which we randomize, so the effective value is half of the number given here.

Definition at line 96 of file gnunet-service-dht_neighbours.c.

◆ GET_TIMEOUT

How long at most to wait for transmission of a GET request to another peer?

Definition at line 102 of file gnunet-service-dht_neighbours.c.

Function Documentation

◆ send_done_cb()

static void send_done_cb ( void *  cls)
static

Function called whenever we finished sending to a target.

Marks the transmission as finished (and the target as ready for the next message).

Parameters
clsa struct Target *

Definition at line 404 of file gnunet-service-dht_neighbours.c.

405{
406 struct Target *t = cls;
407 struct PeerInfo *pi = t->pi; /* NULL if t->dropped! */
408
409 GNUNET_assert (t->load > 0);
410 t->load--;
411 if (0 < t->load)
412 return;
413 if (t->dropped)
414 {
415 GNUNET_free (t);
416 return;
417 }
418 /* move target back to the front */
420 pi->t_tail,
421 t);
423 pi->t_tail,
424 t);
425}

References GNUNET_assert, GNUNET_CONTAINER_DLL_insert, GNUNET_CONTAINER_DLL_remove, GNUNET_free, t, PeerInfo::t_head, and PeerInfo::t_tail.

Referenced by do_send().

Here is the caller graph for this function:

◆ do_send()

static void do_send ( struct PeerInfo pi,
const struct GNUNET_MessageHeader msg 
)
static

Send msg to pi.

Parameters
piwhere to send the message
msgmessage to send

Definition at line 435 of file gnunet-service-dht_neighbours.c.

437{
438 struct Target *t;
439
440 for (t = pi->t_head;
441 NULL != t;
442 t = t->next)
443 if (t->load < MAXIMUM_PENDING_PER_PEER)
444 break;
445 if (NULL == t)
446 {
447 /* all targets busy, drop message */
449 "# messages dropped (underlays busy)",
450 1,
451 GNUNET_NO);
452 return;
453 }
454 t->load++;
455 /* rotate busy targets to the end */
456 if (MAXIMUM_PENDING_PER_PEER == t->load)
457 {
459 pi->t_tail,
460 t);
462 pi->t_tail,
463 t);
464 }
465 GDS_u_send (t->u,
466 t->utarget,
467 msg,
468 ntohs (msg->size),
470 t);
471}

References GDS_stats, GDS_u_send(), GNUNET_CONTAINER_DLL_insert_tail, GNUNET_CONTAINER_DLL_remove, GNUNET_NO, GNUNET_STATISTICS_update(), MAXIMUM_PENDING_PER_PEER, msg, GNUNET_SCHEDULER_Task::next, Target::pi, send_done_cb(), GNUNET_MessageHeader::size, t, PeerInfo::t_head, and PeerInfo::t_tail.

Referenced by cb_path_signed(), cb_routing_put_message(), GDS_NEIGHBOURS_broadcast(), GDS_NEIGHBOURS_handle_get(), and GDS_NEIGHBOURS_handle_reply().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_bucket()

static int find_bucket ( const struct GNUNET_HashCode hc)
static

Find the optimal bucket for this key.

Buckets are indexed by the number of leading bits hc shares with our own identity, so offset 0 holds the peers that differ from us in the very first bit (see k_buckets).

Parameters
hcthe hashcode to compare our identity to
Returns
the proper bucket index, or -1 on error (same hashcode)

Definition at line 485 of file gnunet-service-dht_neighbours.c.

486{
487 const struct GNUNET_HashCode *my_identity_hash;
488 struct GNUNET_HashCode xor;
489 unsigned int bits;
490
491 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
492 GNUNET_assert (NULL != my_identity_hash);
493
495 my_identity_hash,
496 &xor);
498 if (bits == MAX_BUCKETS)
499 {
500 /* How can all bits match? Got my own ID? */
501 GNUNET_break (0);
502 return -1;
503 }
504 return bits;
505}

References GNUNET_HashCode::bits, GDS_pils, GNUNET_assert, GNUNET_break, GNUNET_CRYPTO_hash_count_leading_zeros(), GNUNET_CRYPTO_hash_xor(), GNUNET_PILS_get_identity_hash(), and MAX_BUCKETS.

Referenced by GDS_am_closest_peer(), GDS_try_connect(), and GDS_u_connect().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ add_known_to_bloom()

static enum GNUNET_GenericReturnValue add_known_to_bloom ( void *  cls,
const struct GNUNET_PeerIdentity key,
void *  value 
)
static

Add each of the peers we already know to the Bloom filter of the request so that we don't get duplicate HELLOs.

Parameters
clsthe struct GNUNET_BLOCK_Group
keypeer identity to add to the bloom filter
valuethe peer information
Returns
GNUNET_YES (we should continue to iterate)

Definition at line 518 of file gnunet-service-dht_neighbours.c.

521{
522 struct GNUNET_BLOCK_Group *bg = cls;
523 struct PeerInfo *pi = value;
524
526 &pi->phash,
527 1);
529 "Adding known peer (%s) to Bloom filter for FIND PEER\n",
530 GNUNET_i2s (key));
531 return GNUNET_YES;
532}

References GNUNET_BLOCK_group_set_seen(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_YES, key, PeerInfo::phash, and value.

Referenced by send_find_peer_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ send_find_peer_message()

static void send_find_peer_message ( void *  cls)
static

Task to send a find peer message for our own peer identifier so that we can find the closest peers in the network to ourselves and attempt to connect to them.

Parameters
clsclosure for this task, NULL

Definition at line 543 of file gnunet-service-dht_neighbours.c.

544{
545 (void) cls;
546
547 /* Compute when to do this again (and if we should
548 even send a message right now) */
549 {
550 struct GNUNET_TIME_Relative next_send_time;
551 bool done_early;
552
553 find_peer_task = NULL;
554 done_early = (newly_found_peers > bucket_size);
555 /* schedule next round, taking longer if we found more peers
556 in the last round. */
557 next_send_time.rel_value_us =
562 1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
566 GNUNET_SCHEDULER_add_delayed (next_send_time,
568 NULL);
569 if (done_early)
570 return;
571 }
572
573 /* actually send 'find peer' request */
574 {
575 const struct GNUNET_HashCode *my_identity_hash;
576 struct GNUNET_BLOCK_Group *bg;
577 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
578
579 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
580 GNUNET_assert (NULL != my_identity_hash);
581
584 NULL,
585 0,
586 "seen-set-size",
589 NULL);
592 bg);
593 peer_bf
597 if (GNUNET_OK !=
602 0, /* hop count */
603 my_identity_hash,
604 NULL, 0, /* xquery */
605 bg,
606 peer_bf))
607 {
609 "# Failed to initiate FIND PEER lookup",
610 1,
611 GNUNET_NO);
612 }
613 else
614 {
616 "# FIND PEER messages initiated",
617 1,
618 GNUNET_NO);
619 }
622 }
623}

References add_known_to_bloom(), all_connected_peers, bucket_size, DHT_AVG_FIND_PEER_INTERVAL, DHT_BLOOM_SIZE, DHT_MINIMUM_FIND_PEER_INTERVAL, FIND_PEER_REPLICATION_LEVEL, find_peer_task, GDS_block_context, GDS_NEIGHBOURS_handle_get(), GDS_pils, GDS_stats, GNUNET_assert, GNUNET_BLOCK_group_create(), GNUNET_BLOCK_group_destroy(), GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_CONSTANTS_BLOOMFILTER_K, GNUNET_CONTAINER_bloomfilter_free(), GNUNET_CONTAINER_bloomfilter_init(), GNUNET_CONTAINER_multipeermap_iterate(), GNUNET_CONTAINER_multipeermap_size(), GNUNET_CRYPTO_random_u64(), GNUNET_DHT_RO_FIND_APPROXIMATE, GNUNET_DHT_RO_RECORD_ROUTE, GNUNET_NO, GNUNET_OK, GNUNET_PILS_get_identity_hash(), GNUNET_SCHEDULER_add_delayed(), GNUNET_STATISTICS_update(), GNUNET_TIME_relative_multiply(), newly_found_peers, GNUNET_TIME_Relative::rel_value_us, and send_find_peer_message().

Referenced by GDS_u_connect(), and send_find_peer_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_hold()

static void update_hold ( struct PeerBucket bucket)
static

The list of the first bucket_size peers of bucket changed.

We should thus make sure we have called 'hold' all of the first bucket_size peers!

Parameters
[in,out]bucketthe bucket where the peer set changed

Definition at line 634 of file gnunet-service-dht_neighbours.c.

635{
636 unsigned int off = 0;
637
638 /* find the peer -- we just go over all of them, should
639 be hardly any more expensive than just finding the 'right'
640 one. */
641 for (struct PeerInfo *pos = bucket->head;
642 NULL != pos;
643 pos = pos->next)
644 {
645 if (off > bucket_size)
646 break; /* We only hold up to #bucket_size peers per bucket */
647 off++;
648 for (struct Target *tp = pos->t_head;
649 NULL != tp;
650 tp = tp->next)
651 if (NULL == tp->ph)
652 tp->ph = GDS_u_hold (tp->u,
653 tp->utarget);
654 }
655}

References bucket_size, GDS_u_hold(), and PeerBucket::head.

Referenced by GDS_u_connect(), and GDS_u_disconnect().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GDS_u_connect()

void GDS_u_connect ( void *  cls,
struct GNUNET_DHTU_Target target,
const struct GNUNET_PeerIdentity pid,
void **  ctx 
)

Function to call when we connect to a peer and can henceforth transmit to that peer.

Parameters
clsthe closure, must be a struct GDS_Underlay
targethandle to the target, pointer will remain valid until disconnect_cb is called
pidpeer identity, pointer will remain valid until disconnect_cb is called
[out]ctxstorage space for DHT to use in association with this target

Definition at line 659 of file gnunet-service-dht_neighbours.c.

663{
664 const struct GNUNET_PeerIdentity *my_identity;
665 struct GDS_Underlay *u = cls;
666 struct PeerInfo *pi;
667 struct PeerBucket *bucket;
668 bool do_hold = false;
669
671 GNUNET_assert (NULL != my_identity);
672
673 /* Check for connect to self message */
674 if (0 == GNUNET_memcmp (my_identity, pid))
675 return;
677 "Connected to peer %s\n",
678 GNUNET_i2s (pid));
680 pid);
681 if (NULL == pi)
682 {
684 "# peers connected",
685 1,
686 GNUNET_NO);
687 pi = GNUNET_new (struct PeerInfo);
688 pi->id = *pid;
690 sizeof(*pid),
691 &pi->phash);
692 pi->peer_bucket = find_bucket (&pi->phash);
693 GNUNET_assert ( (pi->peer_bucket >= 0) &&
694 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
695 bucket = &k_buckets[pi->peer_bucket];
697 bucket->tail,
698 pi);
699 bucket->peers_size++;
701 (unsigned int) pi->peer_bucket + 1);
704 &pi->id,
705 pi,
707 if (bucket->peers_size <= bucket_size)
708 {
710 do_hold = true;
711 }
714 {
715 /* got a first connection, good time to start with FIND PEER requests... */
718 NULL);
719 }
720 /* A pending GET that found no route is sitting on an exponential
721 back-off of up to 15 minutes; now that we have somewhere to send
722 it, do so immediately. */
724 }
725 {
726 struct Target *t;
727
728 t = GNUNET_new (struct Target);
729 t->u = u;
730 t->utarget = target;
731 t->pi = pi;
733 pi->t_tail,
734 t);
735 *ctx = t;
736
737 }
738 if (do_hold)
739 update_hold (bucket);
740}

References all_connected_peers, bucket_size, closest_bucket, ctx, disable_try_connect, find_bucket(), find_peer_task, GDS_CLIENTS_retry_requests(), GDS_pils, GDS_stats, GNUNET_assert, GNUNET_CONTAINER_DLL_insert, GNUNET_CONTAINER_DLL_insert_tail, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CONTAINER_multipeermap_get(), GNUNET_CONTAINER_multipeermap_put(), GNUNET_CONTAINER_multipeermap_size(), GNUNET_CRYPTO_hash(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_MAX, GNUNET_memcmp, GNUNET_new, GNUNET_NO, GNUNET_OK, GNUNET_PILS_get_identity(), GNUNET_SCHEDULER_add_now(), GNUNET_STATISTICS_update(), GNUNET_YES, PeerBucket::head, PeerInfo::id, k_buckets, MAX_BUCKETS, my_identity, newly_found_peers, PeerInfo::peer_bucket, PeerBucket::peers_size, PeerInfo::phash, Target::pi, send_find_peer_message(), t, PeerInfo::t_head, PeerInfo::t_tail, PeerBucket::tail, u, and update_hold().

Referenced by load_underlay().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GDS_u_disconnect()

void GDS_u_disconnect ( void *  ctx)

Function to call when we disconnected from a peer and can henceforth cannot transmit to that peer anymore.

Parameters
[in]ctxstorage space used by the DHT in association with this target

Definition at line 744 of file gnunet-service-dht_neighbours.c.

745{
746 struct Target *t = ctx;
747 struct PeerInfo *pi;
748 struct PeerBucket *bucket;
749 bool was_held = false;
750
751 /* Check for disconnect from self message (on shutdown) */
752 if (NULL == t)
753 return;
754 pi = t->pi;
756 pi->t_tail,
757 t);
758 if (NULL != t->ph)
759 {
760 GDS_u_drop (t->u,
761 t->ph);
762 t->ph = NULL;
763 was_held = true;
764 }
765 if (t->load > 0)
766 {
767 t->dropped = true;
768 t->pi = NULL;
769 }
770 else
771 {
772 GNUNET_free (t);
773 }
774 if (NULL != pi->t_head)
775 return; /* got other connections still */
777 "Disconnected from peer %s\n",
778 GNUNET_i2s (&pi->id));
780 "# peers connected",
781 -1,
782 GNUNET_NO);
785 &pi->id,
786 pi));
789 {
791 find_peer_task = NULL;
792 }
793 GNUNET_assert (pi->peer_bucket >= 0);
794 bucket = &k_buckets[pi->peer_bucket];
796 bucket->tail,
797 pi);
798 GNUNET_assert (bucket->peers_size > 0);
799 bucket->peers_size--;
800 if ( (was_held) &&
801 (bucket->peers_size >= bucket_size - 1) )
802 update_hold (bucket);
803 while ( (closest_bucket > 0) &&
806 GNUNET_free (pi->hello);
807 GNUNET_free (pi);
808}

References all_connected_peers, bucket_size, closest_bucket, ctx, disable_try_connect, find_peer_task, GDS_stats, GDS_u_drop(), GNUNET_assert, GNUNET_CONTAINER_DLL_remove, GNUNET_CONTAINER_multipeermap_remove(), GNUNET_CONTAINER_multipeermap_size(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_SCHEDULER_cancel(), GNUNET_STATISTICS_update(), GNUNET_YES, PeerBucket::head, PeerInfo::hello, PeerInfo::id, k_buckets, PeerInfo::peer_bucket, PeerBucket::peers_size, t, PeerInfo::t_head, PeerInfo::t_tail, PeerBucket::tail, and update_hold().

Referenced by load_underlay().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_forward_count()

static unsigned int get_forward_count ( uint16_t  hop_count,
uint16_t  target_replication 
)
static

To how many peers should we (on average) forward the request to obtain the desired target_replication count (on average).

Parameters
hop_countnumber of hops the message has traversed
target_replicationthe number of total paths desired
Returns
Some number of peers to forward the message to

Definition at line 820 of file gnunet-service-dht_neighbours.c.

822{
823 uint32_t random_value;
824 uint32_t forward_count;
825 float target_value;
826 double rm1;
827 double nse = GDS_NSE_get ();
828
829 /* Guard the divisor below: an NSE of zero would make target_value
830 infinite (or NaN), and the conversion to uint32_t undefined. */
831 if (! (nse >= MINIMUM_LOG_NSE))
833 if (hop_count > nse * 4.0)
834 {
835 /* forcefully terminate */
837 "# requests TTL-dropped",
838 1,
839 GNUNET_NO);
840 return 0;
841 }
842 if (hop_count > nse * 2.0)
843 {
844 /* Once we have reached our ideal number of hops, only forward to 1 peer */
845 return 1;
846 }
847 /* bound by system-wide maximum and minimum */
848 if (0 == target_replication)
849 target_replication = 1; /* 0 is verboten */
850 target_replication =
852 target_replication);
853 rm1 = target_replication - 1.0;
854 target_value =
855 1 + (rm1) / (nse + (rm1 * hop_count));
856
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;
861 random_value = GNUNET_CRYPTO_random_u32 (UINT32_MAX);
862 if (random_value < (target_value * UINT32_MAX))
863 forward_count++;
864 return GNUNET_MIN (forward_count,
866}

References GDS_NSE_get(), GDS_stats, GNUNET_CRYPTO_random_u32(), GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL, GNUNET_MIN, GNUNET_NO, GNUNET_STATISTICS_update(), MINIMUM_LOG_NSE, and nse.

Referenced by get_target_peers().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GDS_am_closest_peer()

enum GNUNET_GenericReturnValue GDS_am_closest_peer ( const struct GNUNET_HashCode key,
const struct GNUNET_CONTAINER_BloomFilter bloom 
)

Check whether my identity is closer than any known peers.

If a non-null bloomfilter is given, check if this is the closest peer that hasn't already been routed to.

Parameters
keyhash code to check closeness to
bloombloomfilter, exclude these entries from the decision
Returns
GNUNET_YES if node location is closest, GNUNET_NO otherwise.

Definition at line 880 of file gnunet-service-dht_neighbours.c.

882{
883 const struct GNUNET_HashCode *my_identity_hash;
884 int delta;
885 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
886 GNUNET_assert (NULL != my_identity_hash);
887 if (0 == GNUNET_memcmp (my_identity_hash, key))
888 return GNUNET_YES;
889 for (int bucket_num = find_bucket (key);
890 bucket_num < closest_bucket;
891 bucket_num++)
892 {
893 unsigned int count = 0;
894 GNUNET_assert (bucket_num >= 0);
895 for (struct PeerInfo *pos = k_buckets[bucket_num].head;
896 NULL != pos;
897 pos = pos->next)
898 {
899 if (count >= bucket_size)
900 break; /* we only consider first #bucket_size entries per bucket */
901 count++;
902 if ( (NULL != bloom) &&
903 (GNUNET_YES ==
905 &pos->phash)) )
906 continue; /* Ignore filtered peers */
907 /* All peers in this bucket must be closer than us, as
908 they mismatch with our PID on the pivotal bit. So
909 because an unfiltered peer exists, we are not the
910 closest. */
911 delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
912 my_identity_hash,
913 key);
914 switch (delta)
915 {
916 case -1: /* pos closer */
917 return GNUNET_NO;
918 case 0: /* identical, impossible! */
919 GNUNET_assert (0);
920 break;
921 case 1: /* I am closer */
922 break;
923 }
924 }
925 }
926 /* No closer (unfiltered) peers found; we must be the closest! */
927 return GNUNET_YES;
928}

References bucket_size, closest_bucket, delta, find_bucket(), GDS_pils, GNUNET_assert, GNUNET_CONTAINER_bloomfilter_test(), GNUNET_CRYPTO_hash_xorcmp(), GNUNET_memcmp, GNUNET_NO, GNUNET_PILS_get_identity_hash(), GNUNET_YES, k_buckets, and key.

Referenced by handle_dht_local_put(), handle_dht_p2p_get(), and handle_dht_p2p_put().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_peer()

static struct PeerInfo * select_peer ( const struct GNUNET_HashCode key,
const struct GNUNET_CONTAINER_BloomFilter bloom,
uint32_t  hops 
)
static

Select a peer from the routing table that would be a good routing destination for sending a message for key.

The resulting peer must not be in the set of bloom blocked peers.

Note that we should not ALWAYS select the closest peer to the target, we do a "random" peer selection if the number of hops is below the logarithm of the network size estimate.

In all cases, we only consider at most the first bucket_size peers of any k_buckets. The other peers in the bucket are there because GNUnet doesn't really allow the DHT to "reject" connections, but we only use the first bucket_size, even if more exist. (The idea is to ensure that those connections are frequently used, and for others to be not used by the DHT, and thus possibly dropped by transport due to disuse).

Parameters
keythe key we are selecting a peer to route to
blooma Bloom filter containing entries this request has seen already
hopshow many hops has this message traversed thus far
Returns
Peer to route to, or NULL on error

Definition at line 953 of file gnunet-service-dht_neighbours.c.

956{
957 if (0 == closest_bucket)
958 {
960 "# Peer selection failed",
961 1,
962 GNUNET_NO);
963 return NULL; /* we have zero connections */
964 }
965 if (hops >= GDS_NSE_get ())
966 {
967 /* greedy selection (closest peer that is not in Bloom filter) */
968 struct PeerInfo *chosen = NULL;
969 int best_bucket;
970 int bucket_offset;
971
972 {
973 const struct GNUNET_HashCode *my_identity_hash;
974 struct GNUNET_HashCode xor;
975 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
976 GNUNET_assert (NULL != my_identity_hash);
978 my_identity_hash,
979 &xor);
980 best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
981 }
982 if (best_bucket >= closest_bucket)
983 bucket_offset = closest_bucket - 1;
984 else
985 bucket_offset = best_bucket;
986 while (-1 != bucket_offset)
987 {
988 struct PeerBucket *bucket = &k_buckets[bucket_offset];
989 unsigned int count = 0;
990
991 for (struct PeerInfo *pos = bucket->head;
992 NULL != pos;
993 pos = pos->next)
994 {
995 if (count >= bucket_size)
996 break; /* we only consider first #bucket_size entries per bucket */
997 count++;
998 if ( (NULL != bloom) &&
999 (GNUNET_YES ==
1001 &pos->phash)) )
1002 {
1004 "Excluded peer `%s' due to BF match in greedy routing for %s\n",
1005 GNUNET_i2s (&pos->id),
1006 GNUNET_h2s (key));
1007 continue;
1008 }
1009 if (NULL == chosen)
1010 {
1011 /* First candidate */
1012 chosen = pos;
1013 }
1014 else
1015 {
1016 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
1017 &chosen->phash,
1018 key);
1019 switch (delta)
1020 {
1021 case -1: /* pos closer */
1022 chosen = pos;
1023 break;
1024 case 0: /* identical, impossible! */
1025 GNUNET_assert (0);
1026 break;
1027 case 1: /* chosen closer */
1028 break;
1029 }
1030 }
1031 } /* for all (#bucket_size) peers in bucket */
1032 if (NULL != chosen)
1033 break;
1034
1035 /* If we chose nothing in first iteration, first go through deeper
1036 buckets (best chance to find a good match), and if we still found
1037 nothing, then to shallower buckets. Terminate on any match in the
1038 current bucket, as this search order guarantees that it can only get
1039 worse as we keep going. */
1040 /* Both upward steps must be bounded by #closest_bucket, and the test
1041 has to be `>=': stepping from #best_bucket to #best_bucket + 1
1042 below can jump straight over an `==' test, after which nothing
1043 stops the offset from running off the end of #k_buckets. */
1044 if (bucket_offset > best_bucket)
1045 {
1046 /* Go through more deeper buckets */
1047 bucket_offset++;
1048 if (bucket_offset >= closest_bucket)
1049 {
1050 /* Can't go any deeper, if nothing selected,
1051 go for shallower buckets */
1052 bucket_offset = best_bucket - 1;
1053 }
1054 }
1055 else
1056 {
1057 /* We're either at the 'best_bucket' or already moving
1058 on to shallower buckets. */
1059 if (bucket_offset == best_bucket)
1060 {
1061 bucket_offset++; /* go for deeper buckets */
1062 if (bucket_offset >= closest_bucket)
1063 bucket_offset = best_bucket - 1;
1064 }
1065 else
1066 bucket_offset--; /* go for shallower buckets */
1067 }
1068 } /* for applicable buckets (starting at best match) */
1069 if (NULL == chosen)
1070 {
1072 "# Peer selection failed",
1073 1,
1074 GNUNET_NO);
1075 return NULL;
1076 }
1078 "Selected peer `%s' in greedy routing for %s\n",
1079 GNUNET_i2s (&chosen->id),
1080 GNUNET_h2s (key));
1081 return chosen;
1082 } /* end of 'greedy' peer selection */
1083
1084 /* select "random" peer */
1085 /* count number of peers that are available and not filtered,
1086 but limit to at most #bucket_size peers, starting with
1087 those 'furthest' from us. */
1088 {
1089 unsigned int total = 0;
1090 unsigned int selected;
1091
1092 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1093 {
1094 struct PeerBucket *bucket = &k_buckets[bc];
1095 unsigned int count = 0;
1096
1097 for (struct PeerInfo *pos = bucket->head;
1098 NULL != pos;
1099 pos = pos->next)
1100 {
1101 count++;
1102 if (count > bucket_size)
1103 break; /* limits search to #bucket_size peers per bucket */
1104 if ( (NULL != bloom) &&
1105 (GNUNET_YES ==
1107 &pos->phash)) )
1108 {
1110 "Excluded peer `%s' due to BF match in random routing for %s\n",
1111 GNUNET_i2s (&pos->id),
1112 GNUNET_h2s (key));
1113 continue; /* Ignore filtered peers */
1114 }
1115 total++;
1116 } /* for all peers in bucket */
1117 } /* for all buckets */
1118 if (0 == total) /* No peers to select from! */
1119 {
1121 "# Peer selection failed",
1122 1,
1123 GNUNET_NO);
1124 return NULL;
1125 }
1126
1127 /* Now actually choose a peer */
1128 selected = GNUNET_CRYPTO_random_u32 (total);
1129 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1130 {
1131 unsigned int count = 0;
1132
1133 for (struct PeerInfo *pos = k_buckets[bc].head;
1134 pos != NULL;
1135 pos = pos->next)
1136 {
1137 count++;
1138 if (count > bucket_size)
1139 break; /* limits search to #bucket_size peers per bucket */
1140
1141 if ( (NULL != bloom) &&
1142 (GNUNET_YES ==
1144 &pos->phash)) )
1145 continue; /* Ignore bloomfiltered peers */
1146 if (0 == selected--)
1147 {
1149 "Selected peer `%s' in random routing for %s\n",
1150 GNUNET_i2s (&pos->id),
1151 GNUNET_h2s (key));
1152 return pos;
1153 }
1154 } /* for peers in bucket */
1155 } /* for all buckets */
1156 } /* random peer selection scope */
1157 GNUNET_break (0);
1158 return NULL;
1159}

References bucket_size, closest_bucket, delta, GDS_NSE_get(), GDS_pils, GDS_stats, GNUNET_assert, GNUNET_break, GNUNET_CONTAINER_bloomfilter_test(), GNUNET_CRYPTO_hash_count_leading_zeros(), GNUNET_CRYPTO_hash_xor(), GNUNET_CRYPTO_hash_xorcmp(), GNUNET_CRYPTO_random_u32(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_PILS_get_identity_hash(), GNUNET_STATISTICS_update(), GNUNET_YES, PeerBucket::head, PeerInfo::id, k_buckets, key, PeerInfo::next, and PeerInfo::phash.

Referenced by get_target_peers(), and handle_find_local_hello().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_target_peers()

static unsigned int get_target_peers ( const struct GNUNET_HashCode key,
struct GNUNET_CONTAINER_BloomFilter bloom,
uint16_t  hop_count,
uint16_t  target_replication,
struct PeerInfo ***  targets 
)
static

Compute the set of peers that the given request should be forwarded to.

Parameters
keyrouting key
[in,out]bloomBloom filter excluding peers as targets, all selected peers will be added to the Bloom filter
hop_countnumber of hops the request has traversed so far
target_replicationdesired number of replicas
[out]targetswhere to store an array of target peers (to be free()ed by the caller)
Returns
number of peers returned in targets.

Definition at line 1176 of file gnunet-service-dht_neighbours.c.

1181{
1182 unsigned int target;
1183 unsigned int off;
1184 struct PeerInfo **rtargets;
1185
1186 GNUNET_assert (NULL != bloom);
1187 target = get_forward_count (hop_count,
1188 target_replication);
1189 if (0 == target)
1190 {
1191 *targets = NULL;
1192 return 0;
1193 }
1194 rtargets = GNUNET_new_array (target,
1195 struct PeerInfo *);
1196 for (off = 0; off < target; off++)
1197 {
1198 struct PeerInfo *nxt;
1199
1200 nxt = select_peer (key,
1201 bloom,
1202 hop_count);
1203 if (NULL == nxt)
1204 break;
1205 rtargets[off] = nxt;
1206 /* Exclude the peer we just picked from the next round, or
1207 select_peer() would hand us the same peer again. */
1210 &nxt->phash));
1212 &nxt->phash);
1213 }
1215 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1216 off,
1218 (unsigned int) hop_count,
1219 GNUNET_h2s (key),
1220 target);
1221 if (0 == off)
1222 {
1223 GNUNET_free (rtargets);
1224 *targets = NULL;
1225 return 0;
1226 }
1227 *targets = rtargets;
1229 "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1230 GNUNET_h2s (key),
1231 off,
1232 target);
1233 return off;
1234}

References all_connected_peers, get_forward_count(), GNUNET_assert, GNUNET_break, GNUNET_CONTAINER_bloomfilter_add(), GNUNET_CONTAINER_bloomfilter_test(), GNUNET_CONTAINER_multipeermap_size(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_h2s(), GNUNET_log, GNUNET_new_array, GNUNET_NO, key, PeerInfo::phash, and select_peer().

Referenced by GDS_NEIGHBOURS_handle_get(), and GDS_NEIGHBOURS_handle_put().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hello_check()

static void hello_check ( const struct GNUNET_DATACACHE_Block bd)
static

If we got a HELLO, consider it for our own routing table.

Parameters
bdblock data we got

Definition at line 1243 of file gnunet-service-dht_neighbours.c.

1244{
1245 struct GNUNET_HELLO_Parser *b;
1246
1248 return;
1249
1251 bd->data_size);
1253 {
1256 NULL);
1257 }
1259}

References GNUNET_DATACACHE_Block::data, GNUNET_DATACACHE_Block::data_size, disable_try_connect, GDS_try_connect(), GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_HELLO_parser_free(), GNUNET_HELLO_parser_from_block(), GNUNET_HELLO_parser_iterate(), GNUNET_YES, and GNUNET_DATACACHE_Block::type.

Referenced by GDS_NEIGHBOURS_handle_put(), and handle_dht_p2p_result().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cb_routing_put_message()

static bool cb_routing_put_message ( void *  cls,
size_t  msize,
struct PeerPutMessage ppm 
)
static

Definition at line 1276 of file gnunet-service-dht_neighbours.c.

1279{
1280 struct GDS_RoutingPutCallbackData *gds_routing = cls;
1281 struct PeerInfo *target;
1282
1283 if (NULL == ppm)
1284 {
1285 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1286 if (*(gds_routing->queued) >= gds_routing->target_count)
1287 {
1288 if (gds_routing->cb)
1289 gds_routing->cb (gds_routing->cb_cls, GNUNET_SYSERR);
1290
1291 GNUNET_free (gds_routing->targets);
1292 GNUNET_free (gds_routing->queued);
1293 }
1294
1295 return true;
1296 }
1297
1298 target = gds_routing->targets[gds_routing->index];
1299
1301 "Routing PUT for %s after %u hops to %s\n",
1302 GNUNET_h2s (&(gds_routing->key)),
1303 (unsigned int) gds_routing->hop_count,
1304 GNUNET_i2s (&target->id));
1305 do_send (target,
1306 &ppm->header);
1307 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1308
1309 if (*(gds_routing->queued) >= gds_routing->target_count)
1310 {
1311 if (gds_routing->cb)
1312 gds_routing->cb (gds_routing->cb_cls, GNUNET_OK);
1313
1314 GNUNET_free (gds_routing->targets);
1316 "# PUT messages queued for transmission",
1317 gds_routing->target_count,
1318 GNUNET_NO);
1319 GNUNET_free (gds_routing->queued);
1320 }
1321
1322 return true;
1323}

References GDS_RoutingPutCallbackData::cb, GDS_RoutingPutCallbackData::cb_cls, do_send(), GDS_stats, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_OK, GNUNET_STATISTICS_update(), GNUNET_SYSERR, PeerPutMessage::header, GDS_RoutingPutCallbackData::hop_count, PeerInfo::id, GDS_RoutingPutCallbackData::index, GDS_RoutingPutCallbackData::key, GDS_RoutingPutCallbackData::queued, GDS_RoutingPutCallbackData::target_count, and GDS_RoutingPutCallbackData::targets.

Referenced by GDS_NEIGHBOURS_handle_put().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GDS_NEIGHBOURS_handle_put()

void GDS_NEIGHBOURS_handle_put ( const struct GNUNET_DATACACHE_Block bd,
uint16_t  desired_replication_level,
uint16_t  hop_count,
struct GNUNET_CONTAINER_BloomFilter bf,
GDS_PutOperationCallback  cb,
void *  cb_cls 
)

Perform a PUT operation.

Forwards the given request to other peers. Does not store the data locally. Does not give the data to local clients. May do nothing if this is the only peer in the network (or if we are the closest peer in the network).

Parameters
bddata about the block
desired_replication_leveldesired replication level
hop_counthow many hops has this message traversed so far
bfBloom filter of peers this PUT has already traversed
Returns
GNUNET_OK if the request was forwarded, GNUNET_NO if not

Definition at line 1327 of file gnunet-service-dht_neighbours.c.

1333{
1334 const struct GNUNET_PeerIdentity *my_identity;
1335 const struct GNUNET_HashCode *my_identity_hash;
1336 struct GDS_RoutingPutCallbackData gds_routing;
1337 size_t msize;
1338 enum GNUNET_DHT_RouteOption ro = bd->ro;
1339 unsigned int put_path_length = bd->put_path_length;
1340 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1341 bool truncated = (0 != (bd->ro & GNUNET_DHT_RO_TRUNCATED));
1342 const struct GNUNET_PeerIdentity *trunc_peer
1343 = truncated
1344 ? &bd->trunc_peer
1345 : NULL;
1346 struct GNUNET_PeerIdentity trunc_peer_out;
1348
1350 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1351 GNUNET_assert (NULL != my_identity);
1352
1355 bd->ro, &ro,
1356 bd->expiration_time,
1357 bd->data, bd->data_size,
1358 put_path, put_path_length,
1359 &put_path_length,
1360 trunc_peer,
1361 &trunc_peer_out,
1362 &truncated);
1363 if (truncated)
1364 trunc_peer = &trunc_peer_out;
1365 /* Path may have been truncated by the call above */
1367 "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1369 GNUNET_h2s (&bd->key),
1370 (bd->ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1371 (bd->ro & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1372
1373 /* if we got a HELLO, consider it for our own routing table */
1374 hello_check (bd);
1375 GNUNET_assert ((NULL != bf) && (NULL != my_identity_hash));
1376 GNUNET_CONTAINER_bloomfilter_add (bf, my_identity_hash);
1378 "# PUT requests routed",
1379 1,
1380 GNUNET_NO);
1381 if (GNUNET_OK != ret)
1382 {
1383 if (cb)
1384 cb (cb_cls, ret);
1385 return;
1386 }
1387 gds_routing.target_count
1388 = get_target_peers (&bd->key,
1389 bf,
1390 hop_count,
1391 desired_replication_level,
1392 &(gds_routing.targets));
1393 if (0 == gds_routing.target_count)
1394 {
1396 "Routing PUT for %s terminates after %u hops at %s\n",
1397 GNUNET_h2s (&bd->key),
1398 (unsigned int) hop_count,
1400 if (cb)
1401 cb (cb_cls, GNUNET_NO);
1402 if (gds_routing.targets)
1403 GNUNET_free (gds_routing.targets);
1404 return;
1405 }
1406 GNUNET_memcpy (&(gds_routing.key), &(bd->key),
1407 sizeof (gds_routing.key));
1408 /* targets were added to @a bf by get_target_peers() */
1409
1410 gds_routing.queued = GNUNET_new (unsigned int);
1411 *(gds_routing.queued) = 0;
1412
1413 gds_routing.cb = cb;
1414 gds_routing.cb_cls = cb_cls;
1415
1416 for (unsigned int i = 0; i < gds_routing.target_count; i++)
1417 {
1418 struct PeerInfo *target = gds_routing.targets[i];
1419 struct PeerPutMessage *ppm;
1420 char buf[msize] GNUNET_ALIGN;
1421
1422 gds_routing.index = i;
1423
1424 ppm = (struct PeerPutMessage *) buf;
1425 GDS_helper_make_put_message (ppm, msize,
1427 &target->id,
1428 &target->phash,
1429 bf,
1430 &bd->key,
1431 ro,
1432 bd->type,
1433 bd->expiration_time,
1434 bd->data, bd->data_size,
1435 put_path, put_path_length,
1436 hop_count,
1438 trunc_peer,
1440 sizeof (gds_routing),
1441 &gds_routing);
1442 }
1443}

References GDS_RoutingPutCallbackData::cb, GDS_RoutingPutCallbackData::cb_cls, cb_routing_put_message(), GNUNET_DATACACHE_Block::data, GNUNET_DATACACHE_Block::data_size, PeerPutMessage::desired_replication_level, GNUNET_DATACACHE_Block::expiration_time, GDS_helper_make_put_message(), GDS_helper_put_message_get_size(), GDS_pils, GDS_stats, get_target_peers(), GNUNET_ALIGN, GNUNET_assert, GNUNET_CONTAINER_bloomfilter_add(), GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, GNUNET_DHT_RO_RECORD_ROUTE, GNUNET_DHT_RO_TRUNCATED, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_memcpy, GNUNET_new, GNUNET_NO, GNUNET_OK, GNUNET_PILS_get_identity(), GNUNET_PILS_get_identity_hash(), GNUNET_PILS_get_private_key(), GNUNET_STATISTICS_update(), hello_check(), PeerPutMessage::hop_count, PeerInfo::id, GDS_RoutingPutCallbackData::index, GNUNET_DATACACHE_Block::key, GDS_RoutingPutCallbackData::key, my_identity, PeerInfo::phash, GNUNET_DATACACHE_Block::put_path, GNUNET_DATACACHE_Block::put_path_length, PeerPutMessage::put_path_length, GDS_RoutingPutCallbackData::queued, ret, GNUNET_DATACACHE_Block::ro, GDS_RoutingPutCallbackData::target_count, GDS_RoutingPutCallbackData::targets, GNUNET_DATACACHE_Block::trunc_peer, and GNUNET_DATACACHE_Block::type.

Referenced by handle_dht_local_put(), and handle_dht_p2p_put().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GDS_NEIGHBOURS_handle_get()

enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_handle_get ( enum GNUNET_BLOCK_Type  type,
enum GNUNET_DHT_RouteOption  options,
uint16_t  desired_replication_level,
uint16_t  hop_count,
const struct GNUNET_HashCode key,
const void *  xquery,
size_t  xquery_size,
struct GNUNET_BLOCK_Group bg,
struct GNUNET_CONTAINER_BloomFilter peer_bf 
)

Perform a GET operation.

Forwards the given request to other peers. Does not lookup the key locally. May do nothing if this is the only peer in the network (or if we are the closest peer in the network).

Parameters
typetype of the block
optionsrouting options
desired_replication_leveldesired replication count
hop_counthow many hops did this request traverse so far?
keykey for the content
xqueryextended query
xquery_sizenumber of bytes in xquery
bgblock group to filter replies
peer_bffilter for peers not to select (again, updated)
Returns
GNUNET_OK if the request was forwarded, GNUNET_NO if not

Definition at line 1447 of file gnunet-service-dht_neighbours.c.

1456{
1457 const struct GNUNET_PeerIdentity *my_identity;
1458 const struct GNUNET_HashCode *my_identity_hash;
1459 unsigned int target_count;
1460 struct PeerInfo **targets;
1461 size_t msize;
1462 size_t result_filter_size;
1463 void *result_filter;
1464
1466 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1467
1468 if (NULL == my_identity_hash)
1469 return GNUNET_NO;
1470
1471 GNUNET_assert (NULL != peer_bf);
1473 "# GET requests routed",
1474 1,
1475 GNUNET_NO);
1476 target_count = get_target_peers (key,
1477 peer_bf,
1478 hop_count,
1479 desired_replication_level,
1480 &targets);
1482 "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1484 GNUNET_h2s (key),
1486 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1487 GNUNET_assert (NULL != my_identity_hash);
1488 GNUNET_CONTAINER_bloomfilter_add (peer_bf, my_identity_hash);
1489 if (0 == target_count)
1490 {
1492 "Routing GET for %s terminates after %u hops at %s\n",
1493 GNUNET_h2s (key),
1494 (unsigned int) hop_count,
1496 return GNUNET_NO;
1497 }
1498 if (GNUNET_OK !=
1500 &result_filter,
1501 &result_filter_size))
1502 {
1503 result_filter = NULL;
1504 result_filter_size = 0;
1505 }
1506 msize = xquery_size + result_filter_size;
1507 if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1508 {
1509 GNUNET_break (0);
1510 GNUNET_free (result_filter);
1511 GNUNET_free (targets);
1512 return GNUNET_NO;
1513 }
1514 /* targets were added to @a peer_bf by get_target_peers() */
1515 /* forward request */
1516 for (unsigned int i = 0; i < target_count; i++)
1517 {
1518 struct PeerInfo *target = targets[i];
1519 struct PeerGetMessage *pgm;
1520 char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1521 char *rf;
1522
1524 "Routing GET for %s after %u hops to %s\n",
1525 GNUNET_h2s (key),
1526 (unsigned int) hop_count,
1527 GNUNET_i2s (&target->id));
1528 pgm = (struct PeerGetMessage *) buf;
1530 pgm->header.size = htons (sizeof (buf));
1531 pgm->type = htonl (type);
1532 pgm->options = htons (options);
1533 pgm->hop_count = htons (hop_count + 1);
1535 pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1538 pgm->bloomfilter,
1540 pgm->key = *key;
1541 rf = (char *) &pgm[1];
1542 GNUNET_memcpy (rf,
1543 result_filter,
1546 xquery,
1547 xquery_size);
1548 do_send (target,
1549 &pgm->header);
1550 }
1552 "# GET messages queued for transmission",
1553 target_count,
1554 GNUNET_NO);
1555 GNUNET_free (targets);
1556 GNUNET_free (result_filter);
1557 return (0 < target_count) ? GNUNET_OK : GNUNET_NO;
1558}

References PeerGetMessage::bloomfilter, PeerGetMessage::desired_replication_level, DHT_BLOOM_SIZE, do_send(), GDS_pils, GDS_stats, get_target_peers(), GNUNET_ALIGN, GNUNET_assert, GNUNET_BLOCK_group_serialize(), GNUNET_break, GNUNET_CONTAINER_bloomfilter_add(), GNUNET_CONTAINER_bloomfilter_get_raw_data(), GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, GNUNET_DHT_RO_RECORD_ROUTE, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_MAX_MESSAGE_SIZE, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_DHT_P2P_GET, GNUNET_NO, GNUNET_OK, GNUNET_PILS_get_identity(), GNUNET_PILS_get_identity_hash(), GNUNET_STATISTICS_update(), PeerGetMessage::header, PeerGetMessage::hop_count, PeerInfo::id, key, PeerGetMessage::key, my_identity, options, PeerGetMessage::options, PeerGetMessage::result_filter_size, GNUNET_MessageHeader::size, type, GNUNET_MessageHeader::type, and PeerGetMessage::type.

Referenced by cb_handle_dht_p2p_get_local_result(), send_find_peer_message(), and transmit_request().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GDS_NEIGHBOURS_lookup_peer()

struct PeerInfo * GDS_NEIGHBOURS_lookup_peer ( const struct GNUNET_PeerIdentity target)

Lookup peer by peer's identity.

Parameters
targetpeer to look up
Returns
NULL if we are not connected to target

Definition at line 1562 of file gnunet-service-dht_neighbours.c.

1563{
1565 target);
1566}

References all_connected_peers, and GNUNET_CONTAINER_multipeermap_get().

Referenced by process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cleanup_neighbours_reply()

static void cleanup_neighbours_reply ( struct GDS_NeighboursReply reply)
static

Definition at line 1587 of file gnunet-service-dht_neighbours.c.

1588{
1589 if (reply->block_data)
1590 GNUNET_free (reply->block_data);
1591 if ((reply->bd.put_path_length > 0) && (reply->put_path))
1592 GNUNET_free (reply->put_path);
1593 if (reply->buf)
1594 GNUNET_free (reply->buf);
1595}

References GDS_NeighboursReply::bd, GDS_NeighboursReply::block_data, GDS_NeighboursReply::buf, GNUNET_free, GDS_NeighboursReply::put_path, and GNUNET_DATACACHE_Block::put_path_length.

Referenced by cb_path_signed().

Here is the caller graph for this function:

◆ safe_neighbours_callback()

static void safe_neighbours_callback ( void *  cls,
GNUNET_SCHEDULER_TaskCallback  cb,
bool  success 
)
static

Definition at line 1599 of file gnunet-service-dht_neighbours.c.

1602{
1603 GNUNET_break (success);
1604 if (cb)
1605 cb (cls);
1606}

References GNUNET_break.

Referenced by cb_path_signed(), and GDS_NEIGHBOURS_handle_reply().

Here is the caller graph for this function:

◆ cb_path_signed()

static bool cb_path_signed ( void *  cls,
const struct GNUNET_CRYPTO_EddsaSignature sig 
)
static

Definition at line 1610 of file gnunet-service-dht_neighbours.c.

1612{
1613 struct GDS_NeighboursReply *reply = cls;
1614 struct PeerResultMessage *prm = reply->prm;
1615 struct GNUNET_DHT_PathElement *paths = reply->paths;
1616 unsigned int ppl = ntohs (prm->put_path_length);
1617 unsigned int get_path_length = ntohs (prm->get_path_length);
1618 void *tgt = &paths[get_path_length + ppl];
1619 void *data;
1620
1621 if (! sig)
1622 {
1624 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1625 return true;
1626 }
1627
1628 memcpy (tgt,
1629 sig,
1630 sizeof (*sig));
1631 data = tgt + sizeof (*sig);
1633 "Signing GET PATH %u/%u of %s => %s\n",
1634 ppl,
1635 get_path_length,
1636 GNUNET_h2s (&prm->key),
1637 GNUNET_B2S (sig));
1638#if SANITY_CHECKS > 1
1639 {
1640 const struct GNUNET_PeerIdentity *my_identity;
1641 struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
1642 const struct GNUNET_PeerIdentity *trunc_peer = reply->trunc_peer_is_null?
1643 NULL : &reply->trunc_peer_id;
1644
1646 GNUNET_assert (NULL != my_identity);
1647
1648 memcpy (xpaths,
1649 &paths[ppl],
1650 get_path_length * sizeof (struct GNUNET_DHT_PathElement));
1651 xpaths[get_path_length].sig = *sig;
1652 xpaths[get_path_length].pred = *my_identity;
1653 if (0 !=
1655 reply->bd.data_size,
1656 reply->bd.expiration_time,
1657 trunc_peer,
1658 paths,
1659 ppl,
1660 xpaths,
1661 get_path_length + 1,
1662 &reply->pi->id))
1663 {
1664 GNUNET_break (0);
1666 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1667 return true;
1668 }
1669 }
1670#endif
1672 reply->bd.data,
1673 reply->bd.data_size);
1674 do_send (reply->pi,
1675 &prm->header);
1677 safe_neighbours_callback (reply->cb_cls, reply->cb, true);
1678 return true;
1679}

References GDS_NeighboursReply::bd, GDS_NeighboursReply::cb, GDS_NeighboursReply::cb_cls, cleanup_neighbours_reply(), data, GNUNET_DATACACHE_Block::data, GNUNET_DATACACHE_Block::data_size, do_send(), GNUNET_DATACACHE_Block::expiration_time, GDS_pils, PeerResultMessage::get_path_length, GNUNET_assert, GNUNET_B2S, GNUNET_break, GNUNET_DHT_verify_path(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_h2s(), GNUNET_log, GNUNET_memcpy, GNUNET_PILS_get_identity(), PeerResultMessage::header, PeerInfo::id, PeerResultMessage::key, my_identity, GDS_NeighboursReply::paths, GDS_NeighboursReply::pi, GNUNET_DHT_PathElement::pred, GDS_NeighboursReply::prm, PeerResultMessage::put_path_length, safe_neighbours_callback(), GNUNET_DHT_PathElement::sig, GDS_NeighboursReply::trunc_peer_id, and GDS_NeighboursReply::trunc_peer_is_null.

Referenced by GDS_NEIGHBOURS_handle_reply().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GDS_NEIGHBOURS_handle_reply()

void GDS_NEIGHBOURS_handle_reply ( struct PeerInfo pi,
const struct GNUNET_DATACACHE_Block bd,
const struct GNUNET_HashCode query_hash,
unsigned int  get_path_length,
const struct GNUNET_DHT_PathElement get_path,
GNUNET_SCHEDULER_TaskCallback  cb,
void *  cb_cls 
)

Handle a reply (route to origin).

Only forwards the reply back to other peers waiting for it. Does not do local caching or forwarding to local clients.

Parameters
pineighbour that should receive the block
bddetails about the reply
query_hashquery that was used for the request
get_path_lengthnumber of entries in put_path
get_pathpeers this reply has traversed so far (if tracked)
Returns
true on success

Definition at line 1683 of file gnunet-service-dht_neighbours.c.

1690{
1691 struct GNUNET_DHT_PathElement *paths;
1692 size_t msize;
1693 unsigned int ppl = bd->put_path_length;
1694 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1695 enum GNUNET_DHT_RouteOption ro = bd->ro;
1696 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1697 const struct GNUNET_PeerIdentity *trunc_peer
1698 = truncated
1699 ? &bd->trunc_peer
1700 : NULL;
1701 bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1702#if SANITY_CHECKS > 1
1703 const struct GNUNET_PeerIdentity *my_identity;
1704 unsigned int failure_offset;
1705
1707 GNUNET_assert (NULL != my_identity);
1708
1709 failure_offset
1711 bd->data_size,
1712 bd->expiration_time,
1713 trunc_peer,
1714 put_path,
1715 ppl,
1716 get_path,
1717 get_path_length,
1718 my_identity);
1719 if (0 != failure_offset)
1720 {
1721 GNUNET_assert (failure_offset <= ppl + get_path_length);
1722 GNUNET_break_op (0);
1723 if (failure_offset < ppl)
1724 {
1725 trunc_peer = &put_path[failure_offset - 1].pred;
1726 put_path += failure_offset;
1727 ppl -= failure_offset;
1728 truncated = true;
1730 }
1731 else
1732 {
1733 failure_offset -= ppl;
1734 if (0 == failure_offset)
1735 trunc_peer = &put_path[ppl - 1].pred;
1736 else
1737 trunc_peer = &get_path[failure_offset - 1].pred;
1738 ppl = 0;
1739 put_path = NULL;
1740 truncated = true;
1742 get_path += failure_offset;
1743 get_path_length -= failure_offset;
1744 }
1745 }
1746#endif
1747 msize = bd->data_size + sizeof (struct PeerResultMessage);
1748 if (msize > GNUNET_MAX_MESSAGE_SIZE)
1749 {
1750 GNUNET_break_op (0);
1751 safe_neighbours_callback (cb_cls, cb, false);
1752 return;
1753 }
1754 if (truncated)
1755 msize += sizeof (struct GNUNET_PeerIdentity);
1756 if (tracking)
1757 msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
1758 if (msize < bd->data_size)
1759 {
1760 GNUNET_break_op (0);
1761 safe_neighbours_callback (cb_cls, cb, false);
1762 return;
1763 }
1764 if ( (GNUNET_MAX_MESSAGE_SIZE - msize)
1765 / sizeof(struct GNUNET_DHT_PathElement)
1766 < (get_path_length + ppl) )
1767 {
1768 get_path_length = 0;
1769 ppl = 0;
1770 }
1771 if ( (get_path_length > UINT16_MAX) ||
1772 (ppl > UINT16_MAX) )
1773 {
1774 GNUNET_break (0);
1775 get_path_length = 0;
1776 ppl = 0;
1777 }
1778 msize += (get_path_length + ppl)
1779 * sizeof(struct GNUNET_DHT_PathElement);
1781 "Forwarding reply for key %s to peer %s\n",
1782 GNUNET_h2s (query_hash),
1783 GNUNET_i2s (&pi->id));
1785 "# RESULT messages queued for transmission",
1786 1,
1787 GNUNET_NO);
1788 {
1789 struct PeerResultMessage *prm;
1790 char buf[msize] GNUNET_ALIGN;
1791
1792 prm = (struct PeerResultMessage *) buf;
1794 prm->header.size = htons (sizeof (buf));
1795 prm->type = htonl ((uint32_t) bd->type);
1796 prm->reserved = htons (0);
1797 prm->options = htons ((uint16_t) ro);
1798 prm->put_path_length = htons ((uint16_t) ppl);
1799 prm->get_path_length = htons ((uint16_t) get_path_length);
1801 prm->key = *query_hash;
1802 if (truncated)
1803 {
1804 void *tgt = &prm[1];
1805
1806 GNUNET_memcpy (tgt,
1807 trunc_peer,
1808 sizeof (struct GNUNET_PeerIdentity));
1809 paths = (struct GNUNET_DHT_PathElement *)
1810 (tgt + sizeof (struct GNUNET_PeerIdentity));
1811 }
1812 else
1813 {
1814 paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1815 }
1816 if (NULL != put_path)
1817 {
1818 GNUNET_memcpy (paths,
1819 put_path,
1820 ppl * sizeof(struct GNUNET_DHT_PathElement));
1821 }
1822 else
1823 {
1824 GNUNET_assert (0 == ppl);
1825 }
1826 if (NULL != get_path)
1827 {
1828 GNUNET_memcpy (&paths[ppl],
1829 get_path,
1830 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1831 }
1832 else
1833 {
1834 GNUNET_assert (0 == get_path_length);
1835 }
1836 if (tracking)
1837 {
1838 struct GDS_NeighboursReply reply;
1839 const struct GNUNET_PeerIdentity *pred;
1840
1841 reply.pi = pi;
1842 GNUNET_memcpy (&reply.bd, bd, sizeof (reply.bd));
1843 reply.block_data = GNUNET_memdup (bd->data, bd->data_size);
1844 reply.put_path = GNUNET_memdup (bd->put_path,
1845 sizeof (struct GNUNET_DHT_PathElement)
1846 * bd->put_path_length);
1847
1848 reply.bd.data = reply.block_data;
1849 reply.bd.put_path = reply.put_path;
1850
1851 reply.buf = GNUNET_memdup (buf, msize);
1852 reply.prm = (struct PeerResultMessage*) reply.buf;
1853 reply.paths = (struct GNUNET_DHT_PathElement*)
1854 (reply.buf + ((const char *) paths - buf));
1855
1856 if (trunc_peer)
1857 {
1858 reply.trunc_peer_is_null = false;
1859 GNUNET_memcpy (&reply.trunc_peer_id, trunc_peer,
1860 sizeof (reply.trunc_peer_id));
1861 }
1862 else
1863 {
1864 reply.trunc_peer_is_null = true;
1865 }
1866
1867 reply.cb = cb;
1868 reply.cb_cls = cb_cls;
1869
1870 if (ppl + get_path_length > 0)
1871 pred = &paths[ppl + get_path_length - 1].pred;
1872 else if (truncated)
1873 pred = trunc_peer;
1874 else
1875 pred = NULL; /* we are first! */
1876 /* Note that the last signature in 'paths' was not initialized before,
1877 so this is crucial to avoid sending garbage. */
1879 bd->data_size,
1881 bd->expiration_time,
1882 pred,
1883 &pi->id,
1885 sizeof (reply),
1886 &reply);
1887 }
1888 else
1889 {
1890 void *data;
1891 data = &prm[1];
1893 bd->data,
1894 bd->data_size);
1895 do_send (pi,
1896 &prm->header);
1897 safe_neighbours_callback (cb_cls, cb, true);
1898 return;
1899 }
1900 }
1901}

References GDS_NeighboursReply::bd, GDS_NeighboursReply::block_data, GDS_NeighboursReply::buf, GDS_NeighboursReply::cb, GDS_NeighboursReply::cb_cls, cb_path_signed(), data, GNUNET_DATACACHE_Block::data, data_size, GNUNET_DATACACHE_Block::data_size, do_send(), GNUNET_DATACACHE_Block::expiration_time, PeerResultMessage::expiration_time, GDS_helper_sign_path(), GDS_pils, GDS_stats, PeerResultMessage::get_path_length, GNUNET_ALIGN, GNUNET_assert, GNUNET_break, GNUNET_break_op, GNUNET_DHT_RO_RECORD_ROUTE, GNUNET_DHT_RO_TRUNCATED, GNUNET_DHT_verify_path(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_MAX_MESSAGE_SIZE, GNUNET_memcpy, GNUNET_memdup, GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT, GNUNET_NO, GNUNET_PILS_get_identity(), GNUNET_PILS_get_private_key(), GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_hton(), PeerResultMessage::header, PeerInfo::id, PeerResultMessage::key, my_identity, PeerResultMessage::options, GDS_NeighboursReply::paths, GDS_NeighboursReply::pi, GNUNET_DHT_PathElement::pred, GDS_NeighboursReply::prm, GNUNET_DATACACHE_Block::put_path, GDS_NeighboursReply::put_path, GNUNET_DATACACHE_Block::put_path_length, PeerResultMessage::put_path_length, PeerResultMessage::reserved, GNUNET_DATACACHE_Block::ro, safe_neighbours_callback(), GNUNET_MessageHeader::size, GNUNET_DATACACHE_Block::trunc_peer, GDS_NeighboursReply::trunc_peer_id, GDS_NeighboursReply::trunc_peer_is_null, GNUNET_MessageHeader::type, GNUNET_DATACACHE_Block::type, and PeerResultMessage::type.

Referenced by handle_find_local_hello(), handle_find_my_hello(), handle_local_result(), and process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_dht_p2p_put()

static enum GNUNET_GenericReturnValue check_dht_p2p_put ( void *  cls,
const struct PeerPutMessage put 
)
static

Check validity of a p2p put request.

Parameters
clsclosure with the struct PeerInfo of the sender
putmessage
Returns
GNUNET_OK if the message is valid

Definition at line 1912 of file gnunet-service-dht_neighbours.c.

1914{
1915 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1916 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1917 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1918 uint16_t msize = ntohs (put->header.size);
1919 uint16_t putlen = ntohs (put->put_path_length);
1920 size_t xsize = (has_path
1921 ? sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1922 : 0)
1923 + (truncated
1924 ? sizeof (struct GNUNET_PeerIdentity)
1925 : 0);
1926 size_t var_meta_size
1927 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1928 + xsize;
1929
1930 (void) cls;
1931 if ( (msize <
1932 sizeof (struct PeerPutMessage) + var_meta_size) ||
1933 (putlen >
1934 (GNUNET_MAX_MESSAGE_SIZE
1935 - sizeof (struct PeerPutMessage)
1936 - xsize)
1937 / sizeof(struct GNUNET_DHT_PathElement)) )
1938 {
1939 GNUNET_break_op (0);
1940 return GNUNET_SYSERR;
1941 }
1942 if (GNUNET_BLOCK_TYPE_ANY == htonl (put->type))
1943 {
1944 GNUNET_break_op (0);
1945 return GNUNET_SYSERR;
1946 }
1947 return GNUNET_OK;
1948}

References GNUNET_BLOCK_TYPE_ANY, GNUNET_break_op, GNUNET_DHT_RO_RECORD_ROUTE, GNUNET_DHT_RO_TRUNCATED, GNUNET_OK, GNUNET_SYSERR, PeerPutMessage::header, PeerPutMessage::options, PeerPutMessage::put_path_length, GNUNET_MessageHeader::size, and PeerPutMessage::type.

◆ cb_forwarded_dht_p2p_put()

static void cb_forwarded_dht_p2p_put ( void *  cls,
enum GNUNET_GenericReturnValue  forwarded 
)
static

Definition at line 1964 of file gnunet-service-dht_neighbours.c.

1966{
1967 struct ForwardedDHTPut *put = cls;
1968
1969 /* notify monitoring clients */
1970 put->block.ro |= ((GNUNET_OK == forwarded)
1972 : 0);
1974 put->hop_count,
1976
1977 if (put->put_path)
1978 GNUNET_free (put->put_path);
1979 GNUNET_free (put->data);
1980 GNUNET_free (put);
1981}

References ForwardedDHTPut::block, ForwardedDHTPut::data, ForwardedDHTPut::desired_replication_level, GDS_CLIENTS_process_put(), GNUNET_DHT_RO_LAST_HOP, GNUNET_free, GNUNET_OK, ForwardedDHTPut::hop_count, ForwardedDHTPut::put_path, and GNUNET_DATACACHE_Block::ro.

Referenced by handle_dht_p2p_put().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_dht_p2p_put()

static void handle_dht_p2p_put ( void *  cls,
const struct PeerPutMessage put 
)
static

Core handler for p2p put requests.

Parameters
clsclosure with the struct Target of the sender
putmessage

Definition at line 1991 of file gnunet-service-dht_neighbours.c.

1993{
1994 struct Target *t = cls;
1995 struct PeerInfo *peer = t->pi;
1996 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1997 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1998 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1999 uint16_t msize = ntohs (put->header.size);
2000 uint16_t putlen = ntohs (put->put_path_length);
2001 const struct GNUNET_PeerIdentity *trunc_peer
2002 = truncated
2003 ? (const struct GNUNET_PeerIdentity *) &put[1]
2004 : NULL;
2005 const struct GNUNET_DHT_PathElement *put_path
2006 = truncated
2007 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2008 : (const struct GNUNET_DHT_PathElement *) &put[1];
2009 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2010 = has_path
2011 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &put_path[putlen]
2012 : NULL;
2013 const char *data
2014 = has_path
2015 ? (const char *) &last_sig[1]
2016 : (const char *) &put_path[putlen];
2017 size_t var_meta_size
2018 = putlen * sizeof(struct GNUNET_DHT_PathElement)
2019 + (has_path ? sizeof (*last_sig) : 0)
2020 + (truncated ? sizeof (*trunc_peer) : 0);
2021 struct GNUNET_DATACACHE_Block bd = {
2022 .key = put->key,
2023 .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
2024 .type = ntohl (put->type),
2025 .ro = ro,
2026 .data_size = msize - sizeof(*put) - var_meta_size,
2027 .data = data
2028 };
2029
2030 if (NULL != trunc_peer)
2031 bd.trunc_peer = *trunc_peer;
2033 "PUT for `%s' from %s with RO (%s/%s)\n",
2034 GNUNET_h2s (&put->key),
2035 GNUNET_i2s (&peer->id),
2036 (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
2037 has_path ? "R" : "-");
2039 {
2041 "# Expired PUTs discarded",
2042 1,
2043 GNUNET_NO);
2044 return;
2045 }
2046 {
2047 /* Only call 'check_block' if that keeps our CPU load (from
2048 the cryptography) below 50% on average */
2049 static struct GNUNET_TIME_Relative avg_latency;
2050 static struct GNUNET_TIME_Absolute next_time;
2051
2052 if (GNUNET_TIME_absolute_is_past (next_time))
2053 {
2054 struct GNUNET_TIME_Absolute now
2056 struct GNUNET_TIME_Relative latency;
2058
2059 if (GNUNET_NO ==
2061 bd.type,
2062 bd.data,
2063 bd.data_size))
2064 {
2065 GNUNET_break_op (0);
2066 return;
2067 }
2068 latency = GNUNET_TIME_absolute_get_duration (now);
2069 /* Use *moving average* to estimate check_block latency */
2070 avg_latency
2073 GNUNET_TIME_relative_multiply (avg_latency,
2074 7),
2075 latency),
2076 8);
2077 /* average delay = 50% of avg_latency => 50% CPU load from crypto (at most) */
2079 = GNUNET_CRYPTO_random_u64 (avg_latency.rel_value_us > 0
2080 ? avg_latency.rel_value_us
2081 : 1LLU);
2083 }
2084 }
2085 if (! has_path)
2086 putlen = 0;
2088 "# P2P PUT requests received",
2089 1,
2090 GNUNET_NO);
2092 "# P2P PUT bytes received",
2093 msize,
2094 GNUNET_NO);
2095 {
2096 struct GNUNET_HashCode test_key;
2098
2100 bd.type,
2101 bd.data,
2102 bd.data_size,
2103 &test_key);
2104 switch (ret)
2105 {
2106 case GNUNET_YES:
2107 if (0 != GNUNET_memcmp (&test_key,
2108 &bd.key))
2109 {
2110 GNUNET_break_op (0);
2111 return;
2112 }
2113 break;
2114 case GNUNET_NO:
2115 /* cannot verify, good luck */
2116 break;
2117 case GNUNET_SYSERR:
2118 /* block type not supported, good luck */
2119 break;
2120 }
2121 }
2122
2123 {
2125 struct GNUNET_DHT_PathElement pp[putlen + 1];
2126
2132 &peer->phash));
2133 /* extend 'put path' by sender */
2134 bd.put_path = pp;
2135 bd.put_path_length = putlen + 1;
2136 if (has_path)
2137 {
2138 unsigned int failure_offset;
2139
2140 GNUNET_memcpy (pp,
2141 put_path,
2142 putlen * sizeof(struct GNUNET_DHT_PathElement));
2143 pp[putlen].pred = peer->id;
2144 pp[putlen].sig = *last_sig;
2145#if SANITY_CHECKS
2146 {
2147 const struct GNUNET_PeerIdentity *my_identity;
2149 GNUNET_assert (NULL != my_identity);
2150 /* TODO: might want to eventually implement probabilistic
2151 load-based path verification, but for now it is all or nothing */
2152 failure_offset
2154 bd.data_size,
2155 bd.expiration_time,
2156 trunc_peer,
2157 pp,
2158 putlen + 1,
2159 NULL, 0, /* get_path */
2160 my_identity);
2161 }
2162#else
2163 failure_offset = 0;
2164#endif
2165 if (0 != failure_offset)
2166 {
2167 GNUNET_break_op (0);
2169 "Recorded put path invalid at offset %u, truncating\n",
2170 failure_offset);
2171 GNUNET_assert (failure_offset <= putlen + 1);
2172 bd.put_path = &pp[failure_offset];
2173 bd.put_path_length = (putlen + 1) - failure_offset;
2175 bd.trunc_peer = pp[failure_offset - 1].pred;
2176 }
2177 }
2178 else
2179 {
2180 bd.put_path_length = 0;
2181 }
2182
2183 /* give to local clients */
2185 &bd.key,
2186 0, NULL /* get path */));
2187
2188 /* store locally */
2189 if ( (0 != (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2190 (GDS_am_closest_peer (&put->key,
2191 bf)) )
2193
2194 {
2196 GNUNET_memcpy (&forward->block, &bd, sizeof (bd));
2197
2198 if (bd.put_path_length > 0)
2199 {
2200 forward->put_path = GNUNET_memdup (
2201 bd.put_path,
2202 sizeof (struct GNUNET_DHT_PathElement) * bd.put_path_length);
2203 forward->block.put_path = forward->put_path;
2204 }
2205
2206 forward->data = GNUNET_memdup (bd.data, bd.data_size);
2207 forward->block.data = forward->data;
2208
2209 forward->desired_replication_level = ntohs (put->desired_replication_level
2210 );
2211 forward->hop_count = ntohs (put->hop_count);
2212
2213 /* route to other peers */
2215 forward->desired_replication_level,
2216 forward->hop_count,
2217 bf,
2219 forward);
2220 }
2222 }
2223}

References PeerPutMessage::bloomfilter, cb_forwarded_dht_p2p_put(), data, GNUNET_DATACACHE_Block::data, GNUNET_DATACACHE_Block::data_size, delta, PeerPutMessage::desired_replication_level, DHT_BLOOM_SIZE, GNUNET_DATACACHE_Block::expiration_time, PeerPutMessage::expiration_time, forward, GDS_am_closest_peer(), GDS_block_context, GDS_CLIENTS_handle_reply(), GDS_DATACACHE_handle_put(), GDS_NEIGHBOURS_handle_put(), GDS_pils, GDS_stats, GNUNET_assert, GNUNET_BLOCK_check_block(), GNUNET_BLOCK_get_key(), GNUNET_break, GNUNET_break_op, GNUNET_CONSTANTS_BLOOMFILTER_K, GNUNET_CONTAINER_bloomfilter_free(), GNUNET_CONTAINER_bloomfilter_init(), GNUNET_CONTAINER_bloomfilter_test(), GNUNET_CRYPTO_random_u64(), GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, GNUNET_DHT_RO_RECORD_ROUTE, GNUNET_DHT_RO_TRUNCATED, GNUNET_DHT_verify_path(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_memcmp, GNUNET_memcpy, GNUNET_memdup, GNUNET_new, GNUNET_NO, GNUNET_PILS_get_identity(), GNUNET_STATISTICS_update(), GNUNET_SYSERR, GNUNET_TIME_absolute_get(), GNUNET_TIME_absolute_get_duration(), GNUNET_TIME_absolute_is_past(), GNUNET_TIME_absolute_ntoh(), GNUNET_TIME_relative_add(), GNUNET_TIME_relative_divide(), GNUNET_TIME_relative_multiply(), GNUNET_TIME_relative_to_absolute(), GNUNET_YES, PeerPutMessage::header, PeerPutMessage::hop_count, PeerInfo::id, GNUNET_DATACACHE_Block::key, PeerPutMessage::key, my_identity, PeerPutMessage::options, PeerInfo::phash, GNUNET_DHT_PathElement::pred, GNUNET_DATACACHE_Block::put_path, GNUNET_DATACACHE_Block::put_path_length, PeerPutMessage::put_path_length, GNUNET_TIME_Relative::rel_value_us, ret, GNUNET_DATACACHE_Block::ro, GNUNET_DHT_PathElement::sig, GNUNET_MessageHeader::size, t, GNUNET_DATACACHE_Block::trunc_peer, GNUNET_DATACACHE_Block::type, and PeerPutMessage::type.

Here is the call graph for this function:

◆ handle_find_my_hello()

static void handle_find_my_hello ( struct PeerInfo pi,
const struct GNUNET_HashCode query_hash,
struct GNUNET_BLOCK_Group bg,
GNUNET_SCHEDULER_TaskCallback  cb,
void *  cb_cls 
)
static

We have received a request for a HELLO.

Sends our HELLO back.

Parameters
pisender of the request
keypeers close to this key are desired
bggroup for filtering peers

Definition at line 2243 of file gnunet-service-dht_neighbours.c.

2248{
2249 const struct GNUNET_HashCode *my_identity_hash;
2250 const struct GNUNET_PeerIdentity *my_identity;
2251 struct GNUNET_TIME_Absolute block_expiration;
2252 size_t block_size;
2253 void *block;
2254
2255 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
2258 "Handle finding my own HELLO %s\n",
2259 GNUNET_h2s (my_identity_hash));
2260 if (NULL == GDS_my_hello)
2261 {
2263 "# FIND PEER requests ignored due to lack of HELLO",
2264 1,
2265 GNUNET_NO);
2266 if (cb)
2267 cb (cb_cls);
2268 return;
2269 }
2270
2273 &block,
2274 &block_size,
2275 &block_expiration))
2276 {
2277 if (cb)
2278 cb (cb_cls);
2279 return;
2280 }
2281
2285 bg,
2286 my_identity_hash,
2287 NULL, 0,
2288 block,
2289 block_size))
2290 {
2291 struct GNUNET_DATACACHE_Block bd = {
2293 .expiration_time
2296 .key = *my_identity_hash,
2297 .data = block,
2298 .data_size = block_size
2299 };
2300
2302 &bd,
2303 query_hash,
2304 0, NULL /* get path */,
2305 cb,
2306 cb_cls);
2307 }
2308 else
2309 {
2311 "# FIND PEER requests ignored due to Bloomfilter",
2312 1,
2313 GNUNET_NO);
2314 if (cb)
2315 cb (cb_cls);
2316 }
2317
2318 GNUNET_free (block);
2319}

References GDS_block_context, GDS_my_hello, GDS_NEIGHBOURS_handle_reply(), GDS_pils, GDS_stats, GNUNET_BLOCK_check_reply(), GNUNET_BLOCK_REPLY_OK_MORE, GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_h2s(), GNUNET_HELLO_ADDRESS_EXPIRATION, GNUNET_HELLO_dht_msg_to_block(), GNUNET_log, GNUNET_NO, GNUNET_PILS_get_identity(), GNUNET_PILS_get_identity_hash(), GNUNET_STATISTICS_update(), GNUNET_SYSERR, GNUNET_TIME_relative_to_absolute(), my_identity, and GNUNET_DATACACHE_Block::type.

Referenced by handle_dht_p2p_get().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_find_local_hello()

static void handle_find_local_hello ( struct PeerInfo pi,
const struct GNUNET_HashCode query_hash,
struct GNUNET_BLOCK_Group bg,
GNUNET_SCHEDULER_TaskCallback  cb,
void *  cb_cls 
)
static

We have received a request for nearby HELLOs.

Sends matching HELLOs back.

Parameters
pisender of the request
keypeers close to this key are desired
bggroup for filtering peers

Definition at line 2331 of file gnunet-service-dht_neighbours.c.

2336{
2337 /* Force non-random selection by hop count */
2338 struct PeerInfo *peer;
2339
2340 peer = select_peer (query_hash,
2341 NULL,
2342 GDS_NSE_get () + 1);
2343 if (NULL == peer)
2344 {
2345 /* no neighbour at all, nothing to answer with */
2346 if (cb)
2347 cb (cb_cls);
2348 return;
2349 }
2351 "Handle finding local HELLO %s\n",
2352 GNUNET_h2s (&peer->phash));
2353 if ( (NULL != peer->hello) &&
2359 bg,
2360 &peer->phash,
2361 NULL, 0, /* xquery */
2362 peer->hello,
2363 peer->hello_size)) )
2364 {
2365 struct GNUNET_DATACACHE_Block bd = {
2367 .expiration_time = peer->hello_expiration,
2368 .key = peer->phash,
2369 .data = peer->hello,
2370 .data_size = peer->hello_size
2371 };
2372
2374 &bd,
2375 query_hash,
2376 0, NULL /* get path */,
2377 cb,
2378 cb_cls);
2379 }
2380 else if (cb)
2381 cb (cb_cls);
2382}

References GDS_block_context, GDS_NEIGHBOURS_handle_reply(), GDS_NSE_get(), GNUNET_BLOCK_check_reply(), GNUNET_BLOCK_REPLY_OK_MORE, GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_ERROR_TYPE_DEBUG, GNUNET_h2s(), GNUNET_log, GNUNET_TIME_absolute_is_past(), PeerInfo::hello, PeerInfo::hello_expiration, PeerInfo::hello_size, PeerInfo::phash, select_peer(), and GNUNET_DATACACHE_Block::type.

Referenced by cb_handle_dht_p2p_get_my_hello().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_local_result()

static void handle_local_result ( void *  cls,
const struct GNUNET_DATACACHE_Block bd 
)
static

Handle an exact result from local datacache for a GET operation.

Parameters
clsthe struct PeerInfo for which this is a reply
bddetails about the block we found locally

Definition at line 2392 of file gnunet-service-dht_neighbours.c.

2394{
2395 struct PeerInfo *peer = cls;
2396
2398 bd,
2399 &bd->key,
2400 0, NULL /* get path */,
2401 NULL,
2402 NULL);
2403}

References GDS_NEIGHBOURS_handle_reply(), and GNUNET_DATACACHE_Block::key.

Referenced by cb_handle_dht_p2p_get_local_hello().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_dht_p2p_get()

static enum GNUNET_GenericReturnValue check_dht_p2p_get ( void *  cls,
const struct PeerGetMessage get 
)
static

Check validity of p2p get request.

Parameters
clsclosure with the struct Target of the sender
getthe message
Returns
GNUNET_OK if the message is well-formed

Definition at line 2414 of file gnunet-service-dht_neighbours.c.

2416{
2417 uint16_t msize = ntohs (get->header.size);
2418 uint16_t result_filter_size = ntohs (get->result_filter_size);
2419
2420 (void) cls;
2421 if (msize < sizeof(*get) + result_filter_size)
2422 {
2423 GNUNET_break_op (0);
2424 return GNUNET_SYSERR;
2425 }
2426 return GNUNET_OK;
2427}

References get, GNUNET_break_op, GNUNET_OK, and GNUNET_SYSERR.

◆ cb_handle_dht_p2p_get_local_result()

static void cb_handle_dht_p2p_get_local_result ( void *  cls)
static

Definition at line 2441 of file gnunet-service-dht_neighbours.c.

2442{
2443 struct HandleCallbackGet *handle = cls;
2444 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2445 enum GNUNET_BLOCK_Type type = ntohl (handle->get->type);
2446 const void *result_filter = (const void *) &handle->get[1];
2447 uint16_t msize = ntohs (handle->get->header.size);
2448 uint16_t result_filter_size = ntohs (handle->get->result_filter_size);
2449 const void *xquery = result_filter + result_filter_size;
2450 size_t xquery_size = msize - sizeof (*handle->get) - result_filter_size;
2451
2452 /* remember request for routing replies
2453 TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2454 */
2455 GDS_ROUTING_add (&handle->t->pi->id,
2456 type,
2457 handle->bg, /* bg now owned by routing, but valid at least until end of this function! */
2458 options,
2459 &handle->get->key,
2460 xquery,
2461 xquery_size);
2462
2463 /* P2P forwarding */
2464 {
2465 bool forwarded = false;
2466 uint16_t desired_replication_level = ntohs (
2467 handle->get->desired_replication_level);
2468 uint16_t hop_count = ntohs (handle->get->hop_count);
2469
2471 forwarded = (GNUNET_OK ==
2473 options,
2474 desired_replication_level,
2475 hop_count,
2476 &handle->get->key,
2477 xquery,
2478 xquery_size,
2479 handle->bg,
2480 handle->peer_bf));
2482 options
2483 | (forwarded
2484 ? 0
2486 type,
2487 hop_count,
2488 desired_replication_level,
2489 &handle->get->key);
2490 }
2491 /* clean up; note that 'bg' is owned by routing now! */
2493
2494 GNUNET_free (handle->get);
2496}

References GDS_CLIENTS_process_get(), GDS_NEIGHBOURS_handle_get(), GDS_ROUTING_add(), GNUNET_BLOCK_REPLY_OK_LAST, GNUNET_CONTAINER_bloomfilter_free(), GNUNET_DHT_RO_LAST_HOP, GNUNET_free, GNUNET_OK, handle, options, and type.

Referenced by cb_handle_dht_p2p_get_local_hello(), and handle_dht_p2p_get().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cb_handle_dht_p2p_get_local_hello()

static void cb_handle_dht_p2p_get_local_hello ( void *  cls)
static

Definition at line 2500 of file gnunet-service-dht_neighbours.c.

2501{
2502 struct HandleCallbackGet *handle = cls;
2503 enum GNUNET_BLOCK_Type type = ntohl (handle->get->type);
2504
2506 "Handle getting local HELLO %s of type %u\n",
2507 GNUNET_h2s (&handle->get->key),
2508 type);
2509
2511 {
2512 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2513 const void *result_filter = (const void *) &handle->get[1];
2514 uint16_t msize = ntohs (handle->get->header.size);
2515 uint16_t result_filter_size = ntohs (handle->get->result_filter_size);
2516 const void *xquery = result_filter + result_filter_size;
2517 size_t xquery_size = msize - sizeof (*handle->get) - result_filter_size;
2518 /* The datacache callback runs once per *result*, never on completion,
2519 so it must not carry the continuation: no result would drop the
2520 request, several would run the continuation several times. Both
2521 lookups below are synchronous. */
2523 handle->eval = GDS_DATACACHE_get_closest (&handle->get->key,
2524 type,
2525 xquery,
2526 xquery_size,
2527 handle->bg,
2529 handle->t->pi);
2530 else
2531 handle->eval = GDS_DATACACHE_handle_get (&handle->get->key,
2532 type,
2533 xquery,
2534 xquery_size,
2535 handle->bg,
2537 handle->t->pi);
2538 }
2540}

References cb_handle_dht_p2p_get_local_result(), GDS_DATACACHE_get_closest(), GDS_DATACACHE_handle_get(), GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_DHT_RO_FIND_APPROXIMATE, GNUNET_ERROR_TYPE_DEBUG, GNUNET_h2s(), GNUNET_log, handle, handle_local_result(), options, and type.

Referenced by cb_handle_dht_p2p_get_my_hello(), and handle_dht_p2p_get().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cb_handle_dht_p2p_get_my_hello()

static void cb_handle_dht_p2p_get_my_hello ( void *  cls)
static

Definition at line 2544 of file gnunet-service-dht_neighbours.c.

2545{
2546 struct HandleCallbackGet *handle = cls;
2547 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2548
2551 &handle->get->key,
2552 handle->bg,
2554 handle);
2555 else
2557}

References cb_handle_dht_p2p_get_local_hello(), GNUNET_DHT_RO_FIND_APPROXIMATE, handle, handle_find_local_hello(), and options.

Referenced by handle_dht_p2p_get().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_dht_p2p_get()

static void handle_dht_p2p_get ( void *  cls,
const struct PeerGetMessage get 
)
static

Core handler for p2p get requests.

Parameters
clsclosure with the struct Target of the sender
getthe message

Definition at line 2567 of file gnunet-service-dht_neighbours.c.

2569{
2570 struct Target *t = cls;
2571 struct PeerInfo *peer = t->pi;
2572 uint16_t msize = ntohs (get->header.size);
2573 uint16_t result_filter_size = ntohs (get->result_filter_size);
2574 uint16_t hop_count = ntohs (get->hop_count);
2575 enum GNUNET_BLOCK_Type type = ntohl (get->type);
2576 enum GNUNET_DHT_RouteOption options = ntohs (get->options);
2577 const void *result_filter = (const void *) &get[1];
2578 const void *xquery = result_filter + result_filter_size;
2579 size_t xquery_size = msize - sizeof (*get) - result_filter_size;
2580
2581 /* parse and validate message */
2583 "# P2P GET requests received",
2584 1,
2585 GNUNET_NO);
2587 "# P2P GET bytes received",
2588 msize,
2589 GNUNET_NO);
2590 if (GNUNET_NO ==
2592 type,
2593 &get->key,
2594 xquery,
2595 xquery_size))
2596 {
2597 /* request invalid */
2598 GNUNET_break_op (0);
2599 return;
2600 }
2601
2602 {
2603 const struct GNUNET_PeerIdentity *my_identity;
2604 struct HandleCallbackGet *handle;
2605
2607 handle->t = t;
2608 handle->get = GNUNET_memdup (get, msize);
2610
2612 GNUNET_assert (NULL != my_identity);
2613
2614 handle->peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2619 &peer->phash));
2621 type,
2622 result_filter,
2623 result_filter_size,
2624 "filter-size",
2625 result_filter_size,
2626 NULL);
2628 "GET for %s at %s after %u hops\n",
2629 GNUNET_h2s (&get->key),
2631 (unsigned int) hop_count);
2632 /* local lookup (this may update the bg) */
2634 (GDS_am_closest_peer (&get->key,
2635 handle->peer_bf)) )
2636 {
2639 {
2641 "# P2P HELLO lookup requests processed",
2642 1,
2643 GNUNET_NO);
2645 &get->key,
2646 handle->bg,
2648 handle);
2649 }
2650 else
2652 }
2653 else
2654 {
2656 "# P2P GET requests ONLY routed",
2657 1,
2658 GNUNET_NO);
2660 }
2661 }
2662}

References cb_handle_dht_p2p_get_local_hello(), cb_handle_dht_p2p_get_local_result(), cb_handle_dht_p2p_get_my_hello(), DHT_BLOOM_SIZE, GDS_am_closest_peer(), GDS_block_context, GDS_pils, GDS_stats, get, GNUNET_assert, GNUNET_BLOCK_check_query(), GNUNET_BLOCK_group_create(), GNUNET_BLOCK_REPLY_OK_MORE, GNUNET_BLOCK_TYPE_ANY, GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_break_op, GNUNET_CONSTANTS_BLOOMFILTER_K, GNUNET_CONTAINER_bloomfilter_init(), GNUNET_CONTAINER_bloomfilter_test(), GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, GNUNET_ERROR_TYPE_DEBUG, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_memdup, GNUNET_new, GNUNET_NO, GNUNET_PILS_get_identity(), GNUNET_STATISTICS_update(), GNUNET_YES, handle, handle_find_my_hello(), my_identity, options, PeerInfo::phash, t, and type.

Here is the call graph for this function:

◆ process_reply_with_path()

static void process_reply_with_path ( const struct GNUNET_DATACACHE_Block bd,
const struct GNUNET_HashCode query_hash,
unsigned int  get_path_length,
const struct GNUNET_DHT_PathElement get_path 
)
static

Process a reply, after the get_path has been updated.

Parameters
bdblock details
query_hashhash of the original query, might not match key in bd
get_path_lengthnumber of entries in get_path
get_pathpath the reply has taken

Definition at line 2674 of file gnunet-service-dht_neighbours.c.

2678{
2679 /* forward to local clients */
2681 "Forwarding reply to local clients\n");
2682 if (! GDS_CLIENTS_handle_reply (bd,
2683 query_hash,
2684 get_path_length,
2685 get_path))
2686 {
2687 GNUNET_break (0);
2688 return;
2689 }
2691 get_path,
2692 get_path_length);
2694 {
2695 struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2696 + bd->put_path_length)];
2697 struct GNUNET_DATACACHE_Block bdx = *bd;
2698
2699 if (NULL != bd->put_path)
2700 GNUNET_memcpy (xput_path,
2701 bd->put_path,
2702 bd->put_path_length * sizeof(struct
2704 GNUNET_memcpy (&xput_path[bd->put_path_length],
2705 get_path,
2706 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2707 bdx.put_path = xput_path;
2708 bdx.put_path_length += get_path_length;
2710 }
2711 /* forward to other peers */
2713 query_hash,
2714 get_path_length,
2715 get_path);
2716}

References cache_results, GDS_CLIENTS_handle_reply(), GDS_CLIENTS_process_get_resp(), GDS_DATACACHE_handle_put(), GDS_ROUTING_process(), GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_NZL, GNUNET_YES, GNUNET_DATACACHE_Block::put_path, and GNUNET_DATACACHE_Block::put_path_length.

Referenced by handle_dht_p2p_result().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_dht_p2p_result()

static enum GNUNET_GenericReturnValue check_dht_p2p_result ( void *  cls,
const struct PeerResultMessage prm 
)
static

Check validity of p2p result message.

Parameters
clsclosure
prmmessage
Returns
GNUNET_YES if the message is well-formed

Definition at line 2727 of file gnunet-service-dht_neighbours.c.

2729{
2730 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2731 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2732 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2733 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2734
2735 uint16_t get_path_length = ntohs (prm->get_path_length);
2736 uint16_t put_path_length = ntohs (prm->put_path_length);
2737 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2738 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2739
2740 (void) cls;
2741 if ( (msize < vsize) ||
2742 (msize - vsize <
2743 (get_path_length + put_path_length)
2744 * sizeof(struct GNUNET_DHT_PathElement)) ||
2745 (get_path_length >
2746 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2747 (put_path_length >
2748 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2749 {
2750 GNUNET_break_op (0);
2751 return GNUNET_SYSERR;
2752 }
2753 return GNUNET_OK;
2754}

References PeerResultMessage::get_path_length, GNUNET_break_op, GNUNET_DHT_RO_RECORD_ROUTE, GNUNET_DHT_RO_TRUNCATED, GNUNET_OK, GNUNET_SYSERR, PeerResultMessage::header, PeerResultMessage::options, GNUNET_DATACACHE_Block::put_path_length, PeerResultMessage::put_path_length, GNUNET_DATACACHE_Block::ro, and GNUNET_MessageHeader::size.

◆ handle_dht_p2p_result()

static void handle_dht_p2p_result ( void *  cls,
const struct PeerResultMessage prm 
)
static

Core handler for p2p result messages.

Parameters
clsclosure
prmmessage

Definition at line 2764 of file gnunet-service-dht_neighbours.c.

2766{
2767 struct Target *t = cls;
2768 struct PeerInfo *peer = t->pi;
2769 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2770 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2771 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2772 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2773 uint16_t get_path_length = ntohs (prm->get_path_length);
2774 uint16_t put_path_length = ntohs (prm->put_path_length);
2775 const struct GNUNET_PeerIdentity *trunc_peer
2776 = truncated
2777 ? (const struct GNUNET_PeerIdentity *) &prm[1]
2778 : NULL;
2779 const struct GNUNET_DHT_PathElement *put_path
2780 = truncated
2781 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2782 : (const struct GNUNET_DHT_PathElement *) &prm[1];
2783 const struct GNUNET_DHT_PathElement *get_path
2784 = &put_path[put_path_length];
2785 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2786 = tracked
2787 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &get_path[get_path_length]
2788 : NULL;
2789 const void *data
2790 = tracked
2791 ? (const void *) &last_sig[1]
2792 : (const void *) &get_path[get_path_length];
2793 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2794 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2795 struct GNUNET_DATACACHE_Block bd = {
2797 .put_path = put_path,
2798 .put_path_length = put_path_length,
2799 .key = prm->key,
2800 .type = ntohl (prm->type),
2801 .ro = ro,
2802 .data = data,
2803 .data_size = msize - vsize - (get_path_length + put_path_length)
2804 * sizeof(struct GNUNET_DHT_PathElement)
2805 };
2806
2807 /* parse and validate message */
2808 if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
2809 {
2811 "# Expired results discarded",
2812 1,
2813 GNUNET_NO);
2814 return;
2815 }
2816 if (GNUNET_OK !=
2818 bd.type,
2819 bd.data,
2820 bd.data_size))
2821 {
2822 GNUNET_break_op (0);
2823 return;
2824 }
2826 "# P2P RESULTS received",
2827 1,
2828 GNUNET_NO);
2830 "# P2P RESULT bytes received",
2831 msize,
2832 GNUNET_NO);
2833 {
2835
2837 bd.type,
2838 bd.data,
2839 bd.data_size,
2840 &bd.key);
2841 if (GNUNET_NO == ret)
2842 bd.key = prm->key;
2843 }
2844
2845 /* if we got a HELLO, consider it for our own routing table */
2846 hello_check (&bd);
2847
2848 /* Need to append 'peer' to 'get_path' */
2849 if (tracked)
2850 {
2851 struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2852 struct GNUNET_DHT_PathElement *gp = xget_path;
2853 unsigned int failure_offset;
2854
2855 GNUNET_memcpy (xget_path,
2856 get_path,
2857 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2858 xget_path[get_path_length].pred = peer->id;
2859 /* use memcpy(), as last_sig may not be aligned */
2860 memcpy (&xget_path[get_path_length].sig,
2861 last_sig,
2862 sizeof (*last_sig));
2863#if SANITY_CHECKS
2864 {
2865 const struct GNUNET_PeerIdentity *my_identity;
2867 GNUNET_assert (NULL != my_identity);
2868 /* TODO: might want to eventually implement probabilistic
2869 load-based path verification, but for now it is all or nothing */
2870 failure_offset
2871 = GNUNET_DHT_verify_path (bd.data,
2872 bd.data_size,
2873 bd.expiration_time,
2874 trunc_peer,
2875 put_path,
2876 put_path_length,
2877 gp,
2878 get_path_length + 1,
2879 my_identity);
2880 }
2881#else
2882 failure_offset = 0;
2883#endif
2884 if (0 != failure_offset)
2885 {
2887 "Recorded path invalid at offset %u, truncating\n",
2888 failure_offset);
2889 GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length
2890 + 1);
2891 if (failure_offset < bd.put_path_length)
2892 {
2893 /* failure on put path */
2894 trunc_peer = &bd.put_path[failure_offset - 1].pred;
2895 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2896 bd.put_path = &bd.put_path[failure_offset];
2897 bd.put_path_length -= failure_offset;
2898 truncated = true;
2899 }
2900 else
2901 {
2902 /* failure on get path */
2903 failure_offset -= bd.put_path_length;
2904 if (0 == failure_offset)
2905 trunc_peer = &bd.put_path[bd.put_path_length - 1].pred;
2906 else
2907 trunc_peer = &gp[failure_offset - 1].pred;
2908 get_path_length -= failure_offset;
2909 gp = &gp[failure_offset];
2910 bd.put_path_length = 0;
2911 bd.put_path = NULL;
2912 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2913 truncated = true;
2914 }
2915 }
2917 "Extending GET path of length %u with %s\n",
2918 get_path_length,
2919 GNUNET_i2s (&peer->id));
2920 if (truncated)
2921 {
2922 GNUNET_assert (NULL != trunc_peer);
2923 bd.trunc_peer = *trunc_peer;
2924 }
2926 &prm->key,
2927 get_path_length + 1,
2928 gp);
2929 }
2930 else
2931 {
2932 if (truncated)
2933 {
2934 GNUNET_assert (NULL != trunc_peer);
2935 bd.trunc_peer = *trunc_peer;
2936 }
2938 &prm->key,
2939 0,
2940 NULL);
2941 }
2942}

References data, GNUNET_DATACACHE_Block::expiration_time, PeerResultMessage::expiration_time, GDS_block_context, GDS_pils, GDS_stats, PeerResultMessage::get_path_length, GNUNET_assert, GNUNET_BLOCK_check_block(), GNUNET_BLOCK_get_key(), GNUNET_break_op, GNUNET_DHT_RO_RECORD_ROUTE, GNUNET_DHT_RO_TRUNCATED, GNUNET_DHT_verify_path(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_i2s(), GNUNET_log, GNUNET_memcpy, GNUNET_NO, GNUNET_OK, GNUNET_PILS_get_identity(), GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_is_past(), GNUNET_TIME_absolute_ntoh(), PeerResultMessage::header, hello_check(), PeerInfo::id, PeerResultMessage::key, my_identity, PeerResultMessage::options, GNUNET_DHT_PathElement::pred, process_reply_with_path(), PeerResultMessage::put_path_length, ret, GNUNET_DHT_PathElement::sig, GNUNET_MessageHeader::size, t, and PeerResultMessage::type.

Here is the call graph for this function:

◆ check_dht_p2p_hello()

static enum GNUNET_GenericReturnValue check_dht_p2p_hello ( void *  cls,
const struct GNUNET_MessageHeader hello 
)
static

Check validity of a p2p hello message.

Parameters
clsclosure
hellomessage
Returns
GNUNET_YES if the message is well-formed

Definition at line 2953 of file gnunet-service-dht_neighbours.c.

2955{
2956 struct Target *t = cls;
2957 struct PeerInfo *peer = t->pi;
2959 size_t hellob_size;
2960 void *hellob;
2962
2964 &peer->id,
2965 &hellob,
2966 &hellob_size,
2967 &expiration);
2968 GNUNET_free (hellob);
2969 return ret;
2970}

References expiration, GNUNET_free, GNUNET_HELLO_dht_msg_to_block(), PeerInfo::id, ret, and t.

Here is the call graph for this function:

◆ handle_dht_p2p_hello()

static void handle_dht_p2p_hello ( void *  cls,
const struct GNUNET_MessageHeader hello 
)
static

Core handler for p2p HELLO messages.

Parameters
clsclosure
hellomessage

Definition at line 2980 of file gnunet-service-dht_neighbours.c.

2982{
2983 struct Target *t = cls;
2984 struct PeerInfo *peer = t->pi;
2985
2986 GNUNET_free (peer->hello);
2987 peer->hello_size = 0;
2990 &peer->id,
2991 &peer->hello,
2992 &peer->hello_size,
2993 &peer->hello_expiration));
2994}

References GNUNET_break, GNUNET_free, GNUNET_HELLO_dht_msg_to_block(), GNUNET_OK, PeerInfo::hello, PeerInfo::hello_expiration, PeerInfo::hello_size, PeerInfo::id, and t.

Here is the call graph for this function:

◆ GDS_u_receive()

void GDS_u_receive ( void *  cls,
void **  tctx,
void **  sctx,
const void *  message,
size_t  message_size 
)

Function to call when we receive a message.

Parameters
clsthe closure
[in,out]tctxctx of target address where we received the message from
[in,out]sctxctx of our own source address at which we received the message
messagethe message we received
message_sizenumber of bytes in message

Definition at line 2998 of file gnunet-service-dht_neighbours.c.

3003{
3004 struct Target *t = *tctx;
3005 struct GNUNET_MQ_MessageHandler core_handlers[] = {
3006 GNUNET_MQ_hd_var_size (dht_p2p_get,
3008 struct PeerGetMessage,
3009 t),
3010 GNUNET_MQ_hd_var_size (dht_p2p_put,
3012 struct PeerPutMessage,
3013 t),
3014 GNUNET_MQ_hd_var_size (dht_p2p_result,
3016 struct PeerResultMessage,
3017 t),
3018 GNUNET_MQ_hd_var_size (dht_p2p_hello,
3020 struct GNUNET_MessageHeader,
3021 t),
3023 };
3024 const struct GNUNET_MessageHeader *mh = message;
3025
3026 (void) cls; /* the 'struct GDS_Underlay' */
3027 (void) sctx; /* our receiver address */
3028 if (NULL == t)
3029 {
3030 /* Received message claiming to originate from myself?
3031 Ignore! */
3032 GNUNET_break_op (0);
3033 return;
3034 }
3035 if (message_size < sizeof (*mh))
3036 {
3037 GNUNET_break_op (0);
3038 return;
3039 }
3040 if (message_size != ntohs (mh->size))
3041 {
3042 GNUNET_break_op (0);
3043 return;
3044 }
3046 "Handling message of type %u from peer %s\n",
3047 ntohs (mh->type),
3048 GNUNET_i2s (&t->pi->id));
3049 if (GNUNET_OK !=
3050 GNUNET_MQ_handle_message (core_handlers,
3051 mh))
3052 {
3053 GNUNET_break_op (0);
3054 return;
3055 }
3056}

References GNUNET_break_op, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_MESSAGE_TYPE_DHT_P2P_GET, GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO, GNUNET_MESSAGE_TYPE_DHT_P2P_PUT, GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT, GNUNET_MQ_handle_message(), GNUNET_MQ_handler_end, GNUNET_MQ_hd_var_size, GNUNET_OK, mh, and t.

Referenced by load_underlay().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GDS_try_connect()

void GDS_try_connect ( void *  cls,
const struct GNUNET_PeerIdentity pid,
const char *  uri 
)

Callback function used to extract URIs from a builder.

Called when we should consider connecting to a peer.

Parameters
clsclosure pointing to a struct GNUNET_PeerIdentity *
urione of the URIs

Definition at line 3067 of file gnunet-service-dht_neighbours.c.

3070{
3071 const struct GNUNET_PeerIdentity *my_identity;
3072 struct GNUNET_HashCode phash;
3073 int peer_bucket;
3074 struct PeerBucket *bucket;
3075 (void) cls;
3076
3078 GNUNET_assert (NULL != my_identity);
3079
3080 if (0 == GNUNET_memcmp (my_identity, pid))
3081 {
3083 "Got a HELLO for my own PID, ignoring it\n");
3084 return; /* that's us! */
3085 }
3086 GNUNET_CRYPTO_hash (pid,
3087 sizeof(*pid),
3088 &phash);
3089 peer_bucket = find_bucket (&phash);
3090 GNUNET_assert ( (peer_bucket >= 0) &&
3091 ((unsigned int) peer_bucket < MAX_BUCKETS));
3092 bucket = &k_buckets[peer_bucket];
3093 for (struct PeerInfo *pi = bucket->head;
3094 NULL != pi;
3095 pi = pi->next)
3096 if (0 ==
3097 GNUNET_memcmp (&pi->id,
3098 pid))
3099 {
3100 /* already connected */
3101 GDS_u_try_connect (pid,
3102 uri);
3103 return;
3104 }
3105 if (bucket->peers_size >= bucket_size)
3106 return; /* do not care */
3108 "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
3109 GNUNET_i2s (pid),
3110 uri,
3111 peer_bucket,
3112 bucket->peers_size,
3113 bucket_size);
3114 /* new peer that we like! */
3115 GDS_u_try_connect (pid,
3116 uri);
3117}

References bucket_size, find_bucket(), GDS_pils, GDS_u_try_connect(), GNUNET_assert, GNUNET_CRYPTO_hash(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_i2s(), GNUNET_log, GNUNET_memcmp, GNUNET_PILS_get_identity(), PeerBucket::head, k_buckets, MAX_BUCKETS, my_identity, PeerBucket::peers_size, and uri.

Referenced by handle_dht_local_hello_offer(), and hello_check().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GDS_NEIGHBOURS_broadcast()

void GDS_NEIGHBOURS_broadcast ( const struct GNUNET_MessageHeader msg)

Send msg to all peers in our buckets.

Parameters
msgmessage to broadcast

Definition at line 3126 of file gnunet-service-dht_neighbours.c.

3127{
3128 for (unsigned int bc = 0; bc<closest_bucket; bc++)
3129 {
3130 struct PeerBucket *bucket = &k_buckets[bc];
3131 unsigned int count = 0;
3132
3133 for (struct PeerInfo *pos = bucket->head;
3134 NULL != pos;
3135 pos = pos->next)
3136 {
3137 if (count >= bucket_size)
3138 break; /* we only consider first #bucket_size entries per bucket */
3139 count++;
3140 do_send (pos,
3141 msg);
3142 }
3143 }
3144}

References bucket_size, closest_bucket, do_send(), PeerBucket::head, k_buckets, and msg.

Referenced by pid_change_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GDS_NEIGHBOURS_init()

enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_init ( void  )

Initialize neighbours subsystem.

Returns
GNUNET_OK on success, GNUNET_SYSERR on error

Definition at line 3148 of file gnunet-service-dht_neighbours.c.

3149{
3150
3151 unsigned long long temp_config_num;
3152
3155 "DHT",
3156 "DISABLE_TRY_CONNECT");
3157 if (GNUNET_OK ==
3159 "DHT",
3160 "bucket_size",
3161 &temp_config_num))
3162 bucket_size = (unsigned int) temp_config_num;
3165 "DHT",
3166 "CACHE_RESULTS");
3168 GNUNET_YES);
3169 return GNUNET_OK;
3170}

References all_connected_peers, bucket_size, cache_results, disable_try_connect, GDS_cfg, GNUNET_CONFIGURATION_get_value_number(), GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_CONTAINER_multipeermap_create(), GNUNET_OK, and GNUNET_YES.

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GDS_NEIGHBOURS_done()

void GDS_NEIGHBOURS_done ( void  )

Shutdown neighbours subsystem.

Definition at line 3174 of file gnunet-service-dht_neighbours.c.

References all_connected_peers, find_peer_task, GNUNET_assert, GNUNET_CONTAINER_multipeermap_destroy(), and GNUNET_CONTAINER_multipeermap_size().

Referenced by shutdown_task().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GDS_NEIGHBOURS_get_id()

const struct GNUNET_PeerIdentity * GDS_NEIGHBOURS_get_id ( void  )

Get the ID of the local node.

Returns
identity of the local node

Definition at line 3187 of file gnunet-service-dht_neighbours.c.

3188{
3190}

References GDS_pils, and GNUNET_PILS_get_identity().

Here is the call graph for this function:

Variable Documentation

◆ cache_results

int cache_results
static

Do we cache all results that we are routing in the local datacache?

Definition at line 355 of file gnunet-service-dht_neighbours.c.

Referenced by GDS_NEIGHBOURS_init(), and process_reply_with_path().

◆ closest_bucket

unsigned int closest_bucket
static

One past the deepest currently used bucket, initially 0 (no peers at all).

Buckets at or beyond this offset are known to be empty.

Definition at line 361 of file gnunet-service-dht_neighbours.c.

Referenced by GDS_am_closest_peer(), GDS_NEIGHBOURS_broadcast(), GDS_u_connect(), GDS_u_disconnect(), and select_peer().

◆ newly_found_peers

unsigned int newly_found_peers
static

How many peers have we added since we sent out our last find peer request?

Definition at line 367 of file gnunet-service-dht_neighbours.c.

Referenced by GDS_u_connect(), and send_find_peer_message().

◆ disable_try_connect

int disable_try_connect
static

Option for testing that disables the 'connect' function of the DHT.

Definition at line 372 of file gnunet-service-dht_neighbours.c.

Referenced by GDS_NEIGHBOURS_init(), GDS_u_connect(), GDS_u_disconnect(), and hello_check().

◆ k_buckets

struct PeerBucket k_buckets[sizeof(struct GNUNET_HashCode) *8]
static

The buckets.

Array of size MAX_BUCKETS. Offset 0 means 0 bits matching.

Definition at line 377 of file gnunet-service-dht_neighbours.c.

Referenced by GDS_am_closest_peer(), GDS_NEIGHBOURS_broadcast(), GDS_try_connect(), GDS_u_connect(), GDS_u_disconnect(), and select_peer().

◆ all_connected_peers

struct GNUNET_CONTAINER_MultiPeerMap* all_connected_peers
static

Hash map of all CORE-connected peers, for easy removal from k_buckets on disconnect.

Values are of type struct PeerInfo.

Definition at line 383 of file gnunet-service-dht_neighbours.c.

Referenced by GDS_NEIGHBOURS_done(), GDS_NEIGHBOURS_init(), GDS_NEIGHBOURS_lookup_peer(), GDS_u_connect(), GDS_u_disconnect(), get_target_peers(), and send_find_peer_message().

◆ bucket_size

◆ find_peer_task

struct GNUNET_SCHEDULER_Task* find_peer_task
static

Task that sends FIND PEER requests.

Definition at line 393 of file gnunet-service-dht_neighbours.c.

Referenced by GDS_NEIGHBOURS_done(), GDS_u_connect(), GDS_u_disconnect(), and send_find_peer_message().