GNUnet 0.28.0-dev.2-27-gc87478450
 
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  HandleCallbackLocal
 
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
 The lowest currently used bucket, initially 0 (for 0-bits matching bucket).
 
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
359static unsigned int closest_bucket;
360
365static unsigned int newly_found_peers;
366
370static int disable_try_connect;
371
375static struct PeerBucket k_buckets[MAX_BUCKETS];
376
382
386static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
387
392
393
401static void
402send_done_cb (void *cls)
403{
404 struct Target *t = cls;
405 struct PeerInfo *pi = t->pi; /* NULL if t->dropped! */
406
407 GNUNET_assert (t->load > 0);
408 t->load--;
409 if (0 < t->load)
410 return;
411 if (t->dropped)
412 {
413 GNUNET_free (t);
414 return;
415 }
416 /* move target back to the front */
418 pi->t_tail,
419 t);
421 pi->t_tail,
422 t);
423}
424
425
432static void
433do_send (struct PeerInfo *pi,
434 const struct GNUNET_MessageHeader *msg)
435{
436 struct Target *t;
437
438 for (t = pi->t_head;
439 NULL != t;
440 t = t->next)
441 if (t->load < MAXIMUM_PENDING_PER_PEER)
442 break;
443 if (NULL == t)
444 {
445 /* all targets busy, drop message */
447 "# messages dropped (underlays busy)",
448 1,
449 GNUNET_NO);
450 return;
451 }
452 t->load++;
453 /* rotate busy targets to the end */
454 if (MAXIMUM_PENDING_PER_PEER == t->load)
455 {
457 pi->t_tail,
458 t);
460 pi->t_tail,
461 t);
462 }
463 GDS_u_send (t->u,
464 t->utarget,
465 msg,
466 ntohs (msg->size),
468 t);
469}
470
471
479static int
480find_bucket (const struct GNUNET_HashCode *hc)
481{
482 const struct GNUNET_HashCode *my_identity_hash;
483 struct GNUNET_HashCode xor;
484 unsigned int bits;
485
486 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
487 GNUNET_assert (NULL != my_identity_hash);
488
490 my_identity_hash,
491 &xor);
493 if (bits == MAX_BUCKETS)
494 {
495 /* How can all bits match? Got my own ID? */
496 GNUNET_break (0);
497 return -1;
498 }
499 return MAX_BUCKETS - bits - 1;
500}
501
502
513add_known_to_bloom (void *cls,
514 const struct GNUNET_PeerIdentity *key,
515 void *value)
516{
517 struct GNUNET_BLOCK_Group *bg = cls;
518 struct PeerInfo *pi = value;
519
521 &pi->phash,
522 1);
524 "Adding known peer (%s) to Bloom filter for FIND PEER\n",
525 GNUNET_i2s (key));
526 return GNUNET_YES;
527}
528
529
537static void
538send_find_peer_message (void *cls)
539{
540 (void) cls;
541
542 /* Compute when to do this again (and if we should
543 even send a message right now) */
544 {
545 struct GNUNET_TIME_Relative next_send_time;
546 bool done_early;
547
548 find_peer_task = NULL;
549 done_early = (newly_found_peers > bucket_size);
550 /* schedule next round, taking longer if we found more peers
551 in the last round. */
552 next_send_time.rel_value_us =
557 1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
561 GNUNET_SCHEDULER_add_delayed (next_send_time,
563 NULL);
564 if (done_early)
565 return;
566 }
567
568 /* actually send 'find peer' request */
569 {
570 const struct GNUNET_HashCode *my_identity_hash;
571 struct GNUNET_BLOCK_Group *bg;
572 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
573
574 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
575 GNUNET_assert (NULL != my_identity_hash);
576
579 NULL,
580 0,
581 "seen-set-size",
584 NULL);
587 bg);
588 peer_bf
592 if (GNUNET_OK !=
597 0, /* hop count */
598 my_identity_hash,
599 NULL, 0, /* xquery */
600 bg,
601 peer_bf))
602 {
604 "# Failed to initiate FIND PEER lookup",
605 1,
606 GNUNET_NO);
607 }
608 else
609 {
611 "# FIND PEER messages initiated",
612 1,
613 GNUNET_NO);
614 }
617 }
618}
619
620
628static void
629update_hold (struct PeerBucket *bucket)
630{
631 unsigned int off = 0;
632
633 /* find the peer -- we just go over all of them, should
634 be hardly any more expensive than just finding the 'right'
635 one. */
636 for (struct PeerInfo *pos = bucket->head;
637 NULL != pos;
638 pos = pos->next)
639 {
640 if (off > bucket_size)
641 break; /* We only hold up to #bucket_size peers per bucket */
642 off++;
643 for (struct Target *tp = pos->t_head;
644 NULL != tp;
645 tp = tp->next)
646 if (NULL == tp->ph)
647 tp->ph = GDS_u_hold (tp->u,
648 tp->utarget);
649 }
650}
651
652
653void
654GDS_u_connect (void *cls,
655 struct GNUNET_DHTU_Target *target,
656 const struct GNUNET_PeerIdentity *pid,
657 void **ctx)
658{
659 const struct GNUNET_PeerIdentity *my_identity;
660 struct GDS_Underlay *u = cls;
661 struct PeerInfo *pi;
662 struct PeerBucket *bucket;
663 bool do_hold = false;
664
666 GNUNET_assert (NULL != my_identity);
667
668 /* Check for connect to self message */
669 if (0 == GNUNET_memcmp (my_identity, pid))
670 return;
672 "Connected to peer %s\n",
673 GNUNET_i2s (pid));
675 pid);
676 if (NULL == pi)
677 {
679 "# peers connected",
680 1,
681 GNUNET_NO);
682 pi = GNUNET_new (struct PeerInfo);
683 pi->id = *pid;
685 sizeof(*pid),
686 &pi->phash);
687 pi->peer_bucket = find_bucket (&pi->phash);
688 GNUNET_assert ( (pi->peer_bucket >= 0) &&
689 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
690 bucket = &k_buckets[pi->peer_bucket];
692 bucket->tail,
693 pi);
694 bucket->peers_size++;
696 (unsigned int) pi->peer_bucket + 1);
699 &pi->id,
700 pi,
702 if (bucket->peers_size <= bucket_size)
703 {
705 do_hold = true;
706 }
709 {
710 /* got a first connection, good time to start with FIND PEER requests... */
713 NULL);
714 }
715 }
716 {
717 struct Target *t;
718
719 t = GNUNET_new (struct Target);
720 t->u = u;
721 t->utarget = target;
722 t->pi = pi;
724 pi->t_tail,
725 t);
726 *ctx = t;
727
728 }
729 if (do_hold)
730 update_hold (bucket);
731}
732
733
734void
735GDS_u_disconnect (void *ctx)
736{
737 struct Target *t = ctx;
738 struct PeerInfo *pi;
739 struct PeerBucket *bucket;
740 bool was_held = false;
741
742 /* Check for disconnect from self message (on shutdown) */
743 if (NULL == t)
744 return;
745 pi = t->pi;
747 pi->t_tail,
748 t);
749 if (NULL != t->ph)
750 {
751 GDS_u_drop (t->u,
752 t->ph);
753 t->ph = NULL;
754 was_held = true;
755 }
756 if (t->load > 0)
757 {
758 t->dropped = true;
759 t->pi = NULL;
760 }
761 else
762 {
763 GNUNET_free (t);
764 }
765 if (NULL != pi->t_head)
766 return; /* got other connections still */
768 "Disconnected from peer %s\n",
769 GNUNET_i2s (&pi->id));
771 "# peers connected",
772 -1,
773 GNUNET_NO);
776 &pi->id,
777 pi));
780 {
782 find_peer_task = NULL;
783 }
784 GNUNET_assert (pi->peer_bucket >= 0);
785 bucket = &k_buckets[pi->peer_bucket];
787 bucket->tail,
788 pi);
789 GNUNET_assert (bucket->peers_size > 0);
790 bucket->peers_size--;
791 if ( (was_held) &&
792 (bucket->peers_size >= bucket_size - 1) )
793 update_hold (bucket);
794 while ( (closest_bucket > 0) &&
797 GNUNET_free (pi->hello);
798 GNUNET_free (pi);
799}
800
801
810static unsigned int
811get_forward_count (uint16_t hop_count,
812 uint16_t target_replication)
813{
814 uint32_t random_value;
815 uint32_t forward_count;
816 float target_value;
817 double rm1;
818
819 if (hop_count > GDS_NSE_get () * 4.0)
820 {
821 /* forcefully terminate */
823 "# requests TTL-dropped",
824 1,
825 GNUNET_NO);
826 return 0;
827 }
828 if (hop_count > GDS_NSE_get () * 2.0)
829 {
830 /* Once we have reached our ideal number of hops, only forward to 1 peer */
831 return 1;
832 }
833 /* bound by system-wide maximum and minimum */
834 if (0 == target_replication)
835 target_replication = 1; /* 0 is verboten */
836 target_replication =
838 target_replication);
839 rm1 = target_replication - 1.0;
840 target_value =
841 1 + (rm1) / (GDS_NSE_get () + (rm1 * hop_count));
842
843 /* Set forward count to floor of target_value */
844 forward_count = (uint32_t) target_value;
845 /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
846 target_value = target_value - forward_count;
847 random_value = GNUNET_CRYPTO_random_u32 (UINT32_MAX);
848 if (random_value < (target_value * UINT32_MAX))
849 forward_count++;
850 return GNUNET_MIN (forward_count,
852}
853
854
867 const struct GNUNET_CONTAINER_BloomFilter *bloom)
868{
869 const struct GNUNET_HashCode *my_identity_hash;
870 int delta;
871 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
872 GNUNET_assert (NULL != my_identity_hash);
873 if (0 == GNUNET_memcmp (my_identity_hash, key))
874 return GNUNET_YES;
875 for (int bucket_num = find_bucket (key);
876 bucket_num < closest_bucket;
877 bucket_num++)
878 {
879 unsigned int count = 0;
880 GNUNET_assert (bucket_num >= 0);
881 for (struct PeerInfo *pos = k_buckets[bucket_num].head;
882 NULL != pos;
883 pos = pos->next)
884 {
885 if (count >= bucket_size)
886 break; /* we only consider first #bucket_size entries per bucket */
887 count++;
888 if ( (NULL != bloom) &&
889 (GNUNET_YES ==
891 &pos->phash)) )
892 continue; /* Ignore filtered peers */
893 /* All peers in this bucket must be closer than us, as
894 they mismatch with our PID on the pivotal bit. So
895 because an unfiltered peer exists, we are not the
896 closest. */
897 delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
898 my_identity_hash,
899 key);
900 switch (delta)
901 {
902 case -1: /* pos closer */
903 return GNUNET_NO;
904 case 0: /* identical, impossible! */
905 GNUNET_assert (0);
906 break;
907 case 1: /* I am closer */
908 break;
909 }
910 }
911 }
912 /* No closer (unfiltered) peers found; we must be the closest! */
913 return GNUNET_YES;
914}
915
916
938static struct PeerInfo *
939select_peer (const struct GNUNET_HashCode *key,
940 const struct GNUNET_CONTAINER_BloomFilter *bloom,
941 uint32_t hops)
942{
943 if (0 == closest_bucket)
944 {
946 "# Peer selection failed",
947 1,
948 GNUNET_NO);
949 return NULL; /* we have zero connections */
950 }
951 if (hops >= GDS_NSE_get ())
952 {
953 /* greedy selection (closest peer that is not in Bloom filter) */
954 struct PeerInfo *chosen = NULL;
955 int best_bucket;
956 int bucket_offset;
957
958 {
959 const struct GNUNET_HashCode *my_identity_hash;
960 struct GNUNET_HashCode xor;
961 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
962 GNUNET_assert (NULL != my_identity_hash);
964 my_identity_hash,
965 &xor);
966 best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
967 }
968 if (best_bucket >= closest_bucket)
969 bucket_offset = closest_bucket - 1;
970 else
971 bucket_offset = best_bucket;
972 while (-1 != bucket_offset)
973 {
974 struct PeerBucket *bucket = &k_buckets[bucket_offset];
975 unsigned int count = 0;
976
977 for (struct PeerInfo *pos = bucket->head;
978 NULL != pos;
979 pos = pos->next)
980 {
981 if (count >= bucket_size)
982 break; /* we only consider first #bucket_size entries per bucket */
983 count++;
984 if ( (NULL != bloom) &&
985 (GNUNET_YES ==
987 &pos->phash)) )
988 {
990 "Excluded peer `%s' due to BF match in greedy routing for %s\n",
991 GNUNET_i2s (&pos->id),
992 GNUNET_h2s (key));
993 continue;
994 }
995 if (NULL == chosen)
996 {
997 /* First candidate */
998 chosen = pos;
999 }
1000 else
1001 {
1002 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
1003 &chosen->phash,
1004 key);
1005 switch (delta)
1006 {
1007 case -1: /* pos closer */
1008 chosen = pos;
1009 break;
1010 case 0: /* identical, impossible! */
1011 GNUNET_assert (0);
1012 break;
1013 case 1: /* chosen closer */
1014 break;
1015 }
1016 }
1017 count++;
1018 } /* for all (#bucket_size) peers in bucket */
1019 if (NULL != chosen)
1020 break;
1021
1022 /* If we chose nothing in first iteration, first go through deeper
1023 buckets (best chance to find a good match), and if we still found
1024 nothing, then to shallower buckets. Terminate on any match in the
1025 current bucket, as this search order guarantees that it can only get
1026 worse as we keep going. */
1027 if (bucket_offset > best_bucket)
1028 {
1029 /* Go through more deeper buckets */
1030 bucket_offset++;
1031 if (bucket_offset == closest_bucket)
1032 {
1033 /* Can't go any deeper, if nothing selected,
1034 go for shallower buckets */
1035 bucket_offset = best_bucket - 1;
1036 }
1037 }
1038 else
1039 {
1040 /* We're either at the 'best_bucket' or already moving
1041 on to shallower buckets. */
1042 if (bucket_offset == best_bucket)
1043 bucket_offset++; /* go for deeper buckets */
1044 else
1045 bucket_offset--; /* go for shallower buckets */
1046 }
1047 } /* for applicable buckets (starting at best match) */
1048 if (NULL == chosen)
1049 {
1051 "# Peer selection failed",
1052 1,
1053 GNUNET_NO);
1054 return NULL;
1055 }
1057 "Selected peer `%s' in greedy routing for %s\n",
1058 GNUNET_i2s (&chosen->id),
1059 GNUNET_h2s (key));
1060 return chosen;
1061 } /* end of 'greedy' peer selection */
1062
1063 /* select "random" peer */
1064 /* count number of peers that are available and not filtered,
1065 but limit to at most #bucket_size peers, starting with
1066 those 'furthest' from us. */
1067 {
1068 unsigned int total = 0;
1069 unsigned int selected;
1070
1071 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1072 {
1073 struct PeerBucket *bucket = &k_buckets[bc];
1074 unsigned int count = 0;
1075
1076 for (struct PeerInfo *pos = bucket->head;
1077 NULL != pos;
1078 pos = pos->next)
1079 {
1080 count++;
1081 if (count > bucket_size)
1082 break; /* limits search to #bucket_size peers per bucket */
1083 if ( (NULL != bloom) &&
1084 (GNUNET_YES ==
1086 &pos->phash)) )
1087 {
1089 "Excluded peer `%s' due to BF match in random routing for %s\n",
1090 GNUNET_i2s (&pos->id),
1091 GNUNET_h2s (key));
1092 continue; /* Ignore filtered peers */
1093 }
1094 total++;
1095 } /* for all peers in bucket */
1096 } /* for all buckets */
1097 if (0 == total) /* No peers to select from! */
1098 {
1100 "# Peer selection failed",
1101 1,
1102 GNUNET_NO);
1103 return NULL;
1104 }
1105
1106 /* Now actually choose a peer */
1107 selected = GNUNET_CRYPTO_random_u32 (total);
1108 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1109 {
1110 unsigned int count = 0;
1111
1112 for (struct PeerInfo *pos = k_buckets[bc].head;
1113 pos != NULL;
1114 pos = pos->next)
1115 {
1116 count++;
1117 if (count > bucket_size)
1118 break; /* limits search to #bucket_size peers per bucket */
1119
1120 if ( (NULL != bloom) &&
1121 (GNUNET_YES ==
1123 &pos->phash)) )
1124 continue; /* Ignore bloomfiltered peers */
1125 if (0 == selected--)
1126 {
1128 "Selected peer `%s' in random routing for %s\n",
1129 GNUNET_i2s (&pos->id),
1130 GNUNET_h2s (key));
1131 return pos;
1132 }
1133 } /* for peers in bucket */
1134 } /* for all buckets */
1135 } /* random peer selection scope */
1136 GNUNET_break (0);
1137 return NULL;
1138}
1139
1140
1154static unsigned int
1155get_target_peers (const struct GNUNET_HashCode *key,
1156 struct GNUNET_CONTAINER_BloomFilter *bloom,
1157 uint16_t hop_count,
1158 uint16_t target_replication,
1159 struct PeerInfo ***targets)
1160{
1161 unsigned int target;
1162 unsigned int off;
1163 struct PeerInfo **rtargets;
1164
1165 GNUNET_assert (NULL != bloom);
1166 target = get_forward_count (hop_count,
1167 target_replication);
1168 if (0 == target)
1169 {
1170 *targets = NULL;
1171 return 0;
1172 }
1173 rtargets = GNUNET_new_array (target,
1174 struct PeerInfo *);
1175 for (off = 0; off < target; off++)
1176 {
1177 struct PeerInfo *nxt;
1178
1179 nxt = select_peer (key,
1180 bloom,
1181 hop_count);
1182 if (NULL == nxt)
1183 break;
1184 rtargets[off] = nxt;
1185 }
1187 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1188 off,
1190 (unsigned int) hop_count,
1191 GNUNET_h2s (key),
1192 target);
1193 if (0 == off)
1194 {
1195 GNUNET_free (rtargets);
1196 *targets = NULL;
1197 return 0;
1198 }
1199 *targets = rtargets;
1201 "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1202 GNUNET_h2s (key),
1203 off,
1204 target);
1205 return off;
1206}
1207
1208
1214static void
1215hello_check (const struct GNUNET_DATACACHE_Block *bd)
1216{
1217 struct GNUNET_HELLO_Parser *b;
1218
1220 return;
1221
1223 bd->data_size);
1225 {
1228 NULL);
1229 }
1231}
1232
1233
1235{
1236 unsigned int hop_count;
1237 unsigned int target_count;
1238 struct PeerInfo **targets;
1239 struct GNUNET_HashCode key;
1240 unsigned int index;
1241 unsigned int *queued;
1243 void *cb_cls;
1244};
1245
1246
1247static bool
1248cb_routing_put_message (void *cls,
1249 size_t msize,
1250 struct PeerPutMessage *ppm)
1251{
1252 struct GDS_RoutingPutCallbackData *gds_routing = cls;
1253 struct PeerInfo *target;
1254
1255 if (NULL == ppm)
1256 {
1257 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1258 if (*(gds_routing->queued) >= gds_routing->target_count)
1259 {
1260 if (gds_routing->cb)
1261 gds_routing->cb (gds_routing->cb_cls, GNUNET_SYSERR);
1262
1263 GNUNET_free (gds_routing->targets);
1264 GNUNET_free (gds_routing->queued);
1265 }
1266
1267 return true;
1268 }
1269
1270 target = gds_routing->targets[gds_routing->index];
1271
1273 "Routing PUT for %s after %u hops to %s\n",
1274 GNUNET_h2s (&(gds_routing->key)),
1275 (unsigned int) gds_routing->hop_count,
1276 GNUNET_i2s (&target->id));
1277 do_send (target,
1278 &ppm->header);
1279 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1280
1281 if (*(gds_routing->queued) >= gds_routing->target_count)
1282 {
1283 if (gds_routing->cb)
1284 gds_routing->cb (gds_routing->cb_cls, GNUNET_OK);
1285
1286 GNUNET_free (gds_routing->targets);
1288 "# PUT messages queued for transmission",
1289 gds_routing->target_count,
1290 GNUNET_NO);
1291 GNUNET_free (gds_routing->queued);
1292 }
1293
1294 return true;
1295}
1296
1297
1298void
1300 uint16_t desired_replication_level,
1301 uint16_t hop_count,
1304 void *cb_cls)
1305{
1306 const struct GNUNET_PeerIdentity *my_identity;
1307 const struct GNUNET_HashCode *my_identity_hash;
1308 struct GDS_RoutingPutCallbackData gds_routing;
1309 size_t msize;
1310 enum GNUNET_DHT_RouteOption ro = bd->ro;
1311 unsigned int put_path_length = bd->put_path_length;
1312 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1313 bool truncated = (0 != (bd->ro & GNUNET_DHT_RO_TRUNCATED));
1314 const struct GNUNET_PeerIdentity *trunc_peer
1315 = truncated
1316 ? &bd->trunc_peer
1317 : NULL;
1318 struct GNUNET_PeerIdentity trunc_peer_out;
1320
1322 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1323 GNUNET_assert (NULL != my_identity);
1324
1327 bd->ro, &ro,
1328 bd->expiration_time,
1329 bd->data, bd->data_size,
1330 put_path, put_path_length,
1331 &put_path_length,
1332 trunc_peer,
1333 &trunc_peer_out,
1334 &truncated);
1335 if (truncated)
1336 trunc_peer = &trunc_peer_out;
1337 /* Path may have been truncated by the call above */
1339 "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1341 GNUNET_h2s (&bd->key),
1342 (bd->ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1343 (bd->ro & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1344
1345 /* if we got a HELLO, consider it for our own routing table */
1346 hello_check (bd);
1347 GNUNET_assert ((NULL != bf) && (NULL != my_identity_hash));
1348 GNUNET_CONTAINER_bloomfilter_add (bf, my_identity_hash);
1350 "# PUT requests routed",
1351 1,
1352 GNUNET_NO);
1353 if (GNUNET_OK != ret)
1354 {
1355 if (cb)
1356 cb (cb_cls, ret);
1357 return;
1358 }
1359 gds_routing.target_count
1360 = get_target_peers (&bd->key,
1361 bf,
1362 hop_count,
1363 desired_replication_level,
1364 &(gds_routing.targets));
1365 if (0 == gds_routing.target_count)
1366 {
1368 "Routing PUT for %s terminates after %u hops at %s\n",
1369 GNUNET_h2s (&bd->key),
1370 (unsigned int) hop_count,
1372 if (cb)
1373 cb (cb_cls, GNUNET_NO);
1374 if (gds_routing.targets)
1375 GNUNET_free (gds_routing.targets);
1376 return;
1377 }
1378 GNUNET_memcpy (&(gds_routing.key), &(bd->key),
1379 sizeof (gds_routing.key));
1380 for (unsigned int i = 0; i < gds_routing.target_count; i++)
1381 {
1382 struct PeerInfo *target = gds_routing.targets[i];
1383
1385 &target->phash);
1386 }
1387
1388 gds_routing.queued = GNUNET_new (unsigned int);
1389 *(gds_routing.queued) = 0;
1390
1391 gds_routing.cb = cb;
1392 gds_routing.cb_cls = cb_cls;
1393
1394 for (unsigned int i = 0; i < gds_routing.target_count; i++)
1395 {
1396 struct PeerInfo *target = gds_routing.targets[i];
1397 struct PeerPutMessage *ppm;
1398 char buf[msize] GNUNET_ALIGN;
1399
1400 gds_routing.index = i;
1401
1402 ppm = (struct PeerPutMessage *) buf;
1403 GDS_helper_make_put_message (ppm, msize,
1404 NULL,
1405 &target->id,
1406 &target->phash,
1407 bf,
1408 &bd->key,
1409 ro,
1410 bd->type,
1411 bd->expiration_time,
1412 bd->data, bd->data_size,
1413 put_path, put_path_length,
1414 hop_count,
1416 trunc_peer,
1418 sizeof (gds_routing),
1419 &gds_routing);
1420 }
1421}
1422
1423
1428 uint16_t hop_count,
1429 const struct GNUNET_HashCode *key,
1430 const void *xquery,
1431 size_t xquery_size,
1432 struct GNUNET_BLOCK_Group *bg,
1433 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
1434{
1435 const struct GNUNET_PeerIdentity *my_identity;
1436 const struct GNUNET_HashCode *my_identity_hash;
1437 unsigned int target_count;
1438 struct PeerInfo **targets;
1439 size_t msize;
1440 size_t result_filter_size;
1441 void *result_filter;
1442
1444 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1445
1446 if (NULL == my_identity_hash)
1447 return GNUNET_NO;
1448
1449 GNUNET_assert (NULL != peer_bf);
1451 "# GET requests routed",
1452 1,
1453 GNUNET_NO);
1454 target_count = get_target_peers (key,
1455 peer_bf,
1456 hop_count,
1457 desired_replication_level,
1458 &targets);
1460 "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1462 GNUNET_h2s (key),
1464 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1465 GNUNET_assert (NULL != my_identity_hash);
1466 GNUNET_CONTAINER_bloomfilter_add (peer_bf, my_identity_hash);
1467 if (0 == target_count)
1468 {
1470 "Routing GET for %s terminates after %u hops at %s\n",
1471 GNUNET_h2s (key),
1472 (unsigned int) hop_count,
1474 return GNUNET_NO;
1475 }
1476 if (GNUNET_OK !=
1478 &result_filter,
1479 &result_filter_size))
1480 {
1481 result_filter = NULL;
1482 result_filter_size = 0;
1483 }
1484 msize = xquery_size + result_filter_size;
1485 if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1486 {
1487 GNUNET_break (0);
1488 GNUNET_free (result_filter);
1489 GNUNET_free (targets);
1490 return GNUNET_NO;
1491 }
1492 /* update BF */
1493 for (unsigned int i = 0; i < target_count; i++)
1494 {
1495 struct PeerInfo *target = targets[i];
1496
1498 &target->phash);
1499 }
1500 /* forward request */
1501 for (unsigned int i = 0; i < target_count; i++)
1502 {
1503 struct PeerInfo *target = targets[i];
1504 struct PeerGetMessage *pgm;
1505 char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1506 char *rf;
1507
1509 "Routing GET for %s after %u hops to %s\n",
1510 GNUNET_h2s (key),
1511 (unsigned int) hop_count,
1512 GNUNET_i2s (&target->id));
1513 pgm = (struct PeerGetMessage *) buf;
1515 pgm->header.size = htons (sizeof (buf));
1516 pgm->type = htonl (type);
1517 pgm->options = htons (options);
1518 pgm->hop_count = htons (hop_count + 1);
1520 pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1523 pgm->bloomfilter,
1525 pgm->key = *key;
1526 rf = (char *) &pgm[1];
1527 GNUNET_memcpy (rf,
1528 result_filter,
1531 xquery,
1532 xquery_size);
1533 do_send (target,
1534 &pgm->header);
1535 }
1537 "# GET messages queued for transmission",
1538 target_count,
1539 GNUNET_NO);
1540 GNUNET_free (targets);
1541 GNUNET_free (result_filter);
1542 return (0 < target_count) ? GNUNET_OK : GNUNET_NO;
1543}
1544
1545
1546struct PeerInfo *
1548{
1550 target);
1551}
1552
1553
1555{
1556 struct PeerInfo *pi;
1557 struct PeerResultMessage *prm;
1560 void *block_data;
1563 bool trunc_peer_is_null;
1564 char *buf;
1565
1567 void *cb_cls;
1568};
1569
1570
1571static void
1573{
1574 if (reply->block_data)
1575 GNUNET_free (reply->block_data);
1576 if ((reply->bd.put_path_length > 0) && (reply->put_path))
1577 GNUNET_free (reply->put_path);
1578 if (reply->buf)
1579 GNUNET_free (reply->buf);
1580}
1581
1582
1583static void
1584safe_neighbours_callback (void *cls,
1586 bool success)
1587{
1588 GNUNET_break (success);
1589 if (cb)
1590 cb (cls);
1591}
1592
1593
1594static bool
1595cb_path_signed (void *cls,
1596 const struct GNUNET_CRYPTO_EddsaSignature *sig)
1597{
1598 struct GDS_NeighboursReply *reply = cls;
1599 struct PeerResultMessage *prm = reply->prm;
1600 struct GNUNET_DHT_PathElement *paths = reply->paths;
1601 unsigned int ppl = ntohs (prm->put_path_length);
1602 unsigned int get_path_length = ntohs (prm->get_path_length);
1603 void *tgt = &paths[get_path_length + ppl];
1604 void *data;
1605
1606 if (! sig)
1607 {
1609 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1610 return true;
1611 }
1612
1613 memcpy (tgt,
1614 sig,
1615 sizeof (*sig));
1616 data = tgt + sizeof (*sig);
1618 "Signing GET PATH %u/%u of %s => %s\n",
1619 ppl,
1620 get_path_length,
1621 GNUNET_h2s (&prm->key),
1622 GNUNET_B2S (sig));
1623#if SANITY_CHECKS > 1
1624 {
1625 const struct GNUNET_PeerIdentity *my_identity;
1626 struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
1627 const struct GNUNET_PeerIdentity *trunc_peer = reply->trunc_peer_is_null?
1628 NULL : &reply->trunc_peer_id;
1629
1631 GNUNET_assert (NULL != my_identity);
1632
1633 memcpy (xpaths,
1634 &paths[ppl],
1635 get_path_length * sizeof (struct GNUNET_DHT_PathElement));
1636 xpaths[get_path_length].sig = *sig;
1637 xpaths[get_path_length].pred = *my_identity;
1638 if (0 !=
1640 reply->bd.data_size,
1641 reply->bd.expiration_time,
1642 trunc_peer,
1643 paths,
1644 ppl,
1645 xpaths,
1646 get_path_length + 1,
1647 &reply->pi->id))
1648 {
1649 GNUNET_break (0);
1651 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1652 return true;
1653 }
1654 }
1655#endif
1657 reply->bd.data,
1658 reply->bd.data_size);
1659 do_send (reply->pi,
1660 &prm->header);
1662 safe_neighbours_callback (reply->cb_cls, reply->cb, true);
1663 return true;
1664}
1665
1666
1667void
1669 const struct GNUNET_DATACACHE_Block *bd,
1670 const struct GNUNET_HashCode *query_hash,
1671 unsigned int get_path_length,
1672 const struct GNUNET_DHT_PathElement *get_path,
1674 void *cb_cls)
1675{
1676 struct GNUNET_DHT_PathElement *paths;
1677 size_t msize;
1678 unsigned int ppl = bd->put_path_length;
1679 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1680 enum GNUNET_DHT_RouteOption ro = bd->ro;
1681 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1682 const struct GNUNET_PeerIdentity *trunc_peer
1683 = truncated
1684 ? &bd->trunc_peer
1685 : NULL;
1686 bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1687#if SANITY_CHECKS > 1
1688 const struct GNUNET_PeerIdentity *my_identity;
1689 unsigned int failure_offset;
1690
1692 GNUNET_assert (NULL != my_identity);
1693
1694 failure_offset
1696 bd->data_size,
1697 bd->expiration_time,
1698 trunc_peer,
1699 put_path,
1700 ppl,
1701 get_path,
1702 get_path_length,
1703 my_identity);
1704 if (0 != failure_offset)
1705 {
1706 GNUNET_assert (failure_offset <= ppl + get_path_length);
1707 GNUNET_break_op (0);
1708 if (failure_offset < ppl)
1709 {
1710 trunc_peer = &put_path[failure_offset - 1].pred;
1711 put_path += failure_offset;
1712 ppl -= failure_offset;
1713 truncated = true;
1715 }
1716 else
1717 {
1718 failure_offset -= ppl;
1719 if (0 == failure_offset)
1720 trunc_peer = &put_path[ppl - 1].pred;
1721 else
1722 trunc_peer = &get_path[failure_offset - 1].pred;
1723 ppl = 0;
1724 put_path = NULL;
1725 truncated = true;
1727 get_path += failure_offset;
1728 get_path_length -= failure_offset;
1729 }
1730 }
1731#endif
1732 msize = bd->data_size + sizeof (struct PeerResultMessage);
1733 if (msize > GNUNET_MAX_MESSAGE_SIZE)
1734 {
1735 GNUNET_break_op (0);
1736 safe_neighbours_callback (cb_cls, cb, false);
1737 return;
1738 }
1739 if (truncated)
1740 msize += sizeof (struct GNUNET_PeerIdentity);
1741 if (tracking)
1742 msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
1743 if (msize < bd->data_size)
1744 {
1745 GNUNET_break_op (0);
1746 safe_neighbours_callback (cb_cls, cb, false);
1747 return;
1748 }
1749 if ( (GNUNET_MAX_MESSAGE_SIZE - msize)
1750 / sizeof(struct GNUNET_DHT_PathElement)
1751 < (get_path_length + ppl) )
1752 {
1753 get_path_length = 0;
1754 ppl = 0;
1755 }
1756 if ( (get_path_length > UINT16_MAX) ||
1757 (ppl > UINT16_MAX) )
1758 {
1759 GNUNET_break (0);
1760 get_path_length = 0;
1761 ppl = 0;
1762 }
1763 msize += (get_path_length + ppl)
1764 * sizeof(struct GNUNET_DHT_PathElement);
1766 "Forwarding reply for key %s to peer %s\n",
1767 GNUNET_h2s (query_hash),
1768 GNUNET_i2s (&pi->id));
1770 "# RESULT messages queued for transmission",
1771 1,
1772 GNUNET_NO);
1773 {
1774 struct PeerResultMessage *prm;
1775 char buf[msize] GNUNET_ALIGN;
1776
1777 prm = (struct PeerResultMessage *) buf;
1779 prm->header.size = htons (sizeof (buf));
1780 prm->type = htonl ((uint32_t) bd->type);
1781 prm->reserved = htons (0);
1782 prm->options = htons ((uint16_t) ro);
1783 prm->put_path_length = htons ((uint16_t) ppl);
1784 prm->get_path_length = htons ((uint16_t) get_path_length);
1786 prm->key = *query_hash;
1787 if (truncated)
1788 {
1789 void *tgt = &prm[1];
1790
1791 GNUNET_memcpy (tgt,
1792 trunc_peer,
1793 sizeof (struct GNUNET_PeerIdentity));
1794 paths = (struct GNUNET_DHT_PathElement *)
1795 (tgt + sizeof (struct GNUNET_PeerIdentity));
1796 }
1797 else
1798 {
1799 paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1800 }
1801 if (NULL != put_path)
1802 {
1803 GNUNET_memcpy (paths,
1804 put_path,
1805 ppl * sizeof(struct GNUNET_DHT_PathElement));
1806 }
1807 else
1808 {
1809 GNUNET_assert (0 == ppl);
1810 }
1811 if (NULL != get_path)
1812 {
1813 GNUNET_memcpy (&paths[ppl],
1814 get_path,
1815 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1816 }
1817 else
1818 {
1819 GNUNET_assert (0 == get_path_length);
1820 }
1821 if (tracking)
1822 {
1823 struct GDS_NeighboursReply reply;
1824 const struct GNUNET_PeerIdentity *pred;
1825
1826 reply.pi = pi;
1827 GNUNET_memcpy (&reply.bd, bd, sizeof (reply.bd));
1828 reply.block_data = GNUNET_memdup (bd->data, bd->data_size);
1829 reply.put_path = GNUNET_memdup (bd->put_path,
1830 sizeof (struct GNUNET_DHT_PathElement)
1831 * bd->put_path_length);
1832
1833 reply.bd.data = reply.block_data;
1834 reply.bd.put_path = reply.put_path;
1835
1836 reply.buf = GNUNET_memdup (buf, msize);
1837 reply.prm = (struct PeerResultMessage*) reply.buf;
1838 reply.paths = (struct GNUNET_DHT_PathElement*) (reply.buf + (buf - (const
1839 char*)
1840 paths));
1841
1842 if (trunc_peer)
1843 {
1844 reply.trunc_peer_is_null = false;
1845 GNUNET_memcpy (&reply.trunc_peer_id, trunc_peer,
1846 sizeof (reply.trunc_peer_id));
1847 }
1848 else
1849 {
1850 reply.trunc_peer_is_null = true;
1851 }
1852
1853 reply.cb = cb;
1854 reply.cb_cls = cb_cls;
1855
1856 if (ppl + get_path_length > 0)
1857 pred = &paths[ppl + get_path_length - 1].pred;
1858 else if (truncated)
1859 pred = trunc_peer;
1860 else
1861 pred = NULL; /* we are first! */
1862 /* Note that the last signature in 'paths' was not initialized before,
1863 so this is crucial to avoid sending garbage. */
1865 bd->data_size,
1866 NULL,
1867 bd->expiration_time,
1868 pred,
1869 &pi->id,
1871 sizeof (reply),
1872 &reply);
1873 }
1874 else
1875 {
1876 void *data;
1877 data = &prm[1];
1879 bd->data,
1880 bd->data_size);
1881 do_send (pi,
1882 &prm->header);
1883 safe_neighbours_callback (cb_cls, cb, true);
1884 return;
1885 }
1886 }
1887}
1888
1889
1897static enum GNUNET_GenericReturnValue
1898check_dht_p2p_put (void *cls,
1899 const struct PeerPutMessage *put)
1900{
1901 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1902 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1903 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1904 uint16_t msize = ntohs (put->header.size);
1905 uint16_t putlen = ntohs (put->put_path_length);
1906 size_t xsize = (has_path
1907 ? sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1908 : 0)
1909 + (truncated
1910 ? sizeof (struct GNUNET_PeerIdentity)
1911 : 0);
1912 size_t var_meta_size
1913 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1914 + xsize;
1915
1916 (void) cls;
1917 if ( (msize <
1918 sizeof (struct PeerPutMessage) + var_meta_size) ||
1919 (putlen >
1920 (GNUNET_MAX_MESSAGE_SIZE
1921 - sizeof (struct PeerPutMessage)
1922 - xsize)
1923 / sizeof(struct GNUNET_DHT_PathElement)) )
1924 {
1925 GNUNET_break_op (0);
1926 return GNUNET_SYSERR;
1927 }
1928 if (GNUNET_BLOCK_TYPE_ANY == htonl (put->type))
1929 {
1930 GNUNET_break_op (0);
1931 return GNUNET_SYSERR;
1932 }
1933 return GNUNET_OK;
1934}
1935
1936
1937struct ForwardedDHTPut
1938{
1940
1942 void *data;
1943
1944 uint32_t hop_count;
1946};
1947
1948
1949static void
1950cb_forwarded_dht_p2p_put (void *cls,
1951 enum GNUNET_GenericReturnValue forwarded)
1952{
1953 struct ForwardedDHTPut *put = cls;
1954
1955 /* notify monitoring clients */
1956 put->block.ro |= ((GNUNET_OK == forwarded)
1958 : 0);
1960 put->hop_count,
1962
1963 if (put->put_path)
1964 GNUNET_free (put->put_path);
1965 GNUNET_free (put->data);
1966 GNUNET_free (put);
1967}
1968
1969
1976static void
1977handle_dht_p2p_put (void *cls,
1978 const struct PeerPutMessage *put)
1979{
1980 struct Target *t = cls;
1981 struct PeerInfo *peer = t->pi;
1982 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1983 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1984 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1985 uint16_t msize = ntohs (put->header.size);
1986 uint16_t putlen = ntohs (put->put_path_length);
1987 const struct GNUNET_PeerIdentity *trunc_peer
1988 = truncated
1989 ? (const struct GNUNET_PeerIdentity *) &put[1]
1990 : NULL;
1991 const struct GNUNET_DHT_PathElement *put_path
1992 = truncated
1993 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
1994 : (const struct GNUNET_DHT_PathElement *) &put[1];
1995 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
1996 = has_path
1997 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &put_path[putlen]
1998 : NULL;
1999 const char *data
2000 = has_path
2001 ? (const char *) &last_sig[1]
2002 : (const char *) &put_path[putlen];
2003 size_t var_meta_size
2004 = putlen * sizeof(struct GNUNET_DHT_PathElement)
2005 + (has_path ? sizeof (*last_sig) : 0)
2006 + (truncated ? sizeof (*trunc_peer) : 0);
2007 struct GNUNET_DATACACHE_Block bd = {
2008 .key = put->key,
2009 .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
2010 .type = ntohl (put->type),
2011 .ro = ro,
2012 .data_size = msize - sizeof(*put) - var_meta_size,
2013 .data = data
2014 };
2015
2016 if (NULL != trunc_peer)
2017 bd.trunc_peer = *trunc_peer;
2019 "PUT for `%s' from %s with RO (%s/%s)\n",
2020 GNUNET_h2s (&put->key),
2021 GNUNET_i2s (&peer->id),
2022 (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
2023 has_path ? "R" : "-");
2025 {
2027 "# Expired PUTs discarded",
2028 1,
2029 GNUNET_NO);
2030 return;
2031 }
2032 {
2033 /* Only call 'check_block' if that keeps our CPU load (from
2034 the cryptography) below 50% on average */
2035 static struct GNUNET_TIME_Relative avg_latency;
2036 static struct GNUNET_TIME_Absolute next_time;
2037
2038 if (GNUNET_TIME_absolute_is_past (next_time))
2039 {
2040 struct GNUNET_TIME_Absolute now
2042 struct GNUNET_TIME_Relative latency;
2044
2045 if (GNUNET_NO ==
2047 bd.type,
2048 bd.data,
2049 bd.data_size))
2050 {
2051 GNUNET_break_op (0);
2052 return;
2053 }
2054 latency = GNUNET_TIME_absolute_get_duration (now);
2055 /* Use *moving average* to estimate check_block latency */
2056 avg_latency
2059 GNUNET_TIME_relative_multiply (avg_latency,
2060 7),
2061 latency),
2062 8);
2063 /* average delay = 50% of avg_latency => 50% CPU load from crypto (at most) */
2065 = GNUNET_CRYPTO_random_u64 (avg_latency.rel_value_us > 0
2066 ? avg_latency.rel_value_us
2067 : 1LLU);
2069 }
2070 }
2071 if (! has_path)
2072 putlen = 0;
2074 "# P2P PUT requests received",
2075 1,
2076 GNUNET_NO);
2078 "# P2P PUT bytes received",
2079 msize,
2080 GNUNET_NO);
2081 {
2082 struct GNUNET_HashCode test_key;
2084
2086 bd.type,
2087 bd.data,
2088 bd.data_size,
2089 &test_key);
2090 switch (ret)
2091 {
2092 case GNUNET_YES:
2093 if (0 != GNUNET_memcmp (&test_key,
2094 &bd.key))
2095 {
2096 GNUNET_break_op (0);
2097 return;
2098 }
2099 break;
2100 case GNUNET_NO:
2101 /* cannot verify, good luck */
2102 break;
2103 case GNUNET_SYSERR:
2104 /* block type not supported, good luck */
2105 break;
2106 }
2107 }
2108
2109 {
2111 struct GNUNET_DHT_PathElement pp[putlen + 1];
2112
2118 &peer->phash));
2119 /* extend 'put path' by sender */
2120 bd.put_path = pp;
2121 bd.put_path_length = putlen + 1;
2122 if (has_path)
2123 {
2124 unsigned int failure_offset;
2125
2126 GNUNET_memcpy (pp,
2127 put_path,
2128 putlen * sizeof(struct GNUNET_DHT_PathElement));
2129 pp[putlen].pred = peer->id;
2130 pp[putlen].sig = *last_sig;
2131#if SANITY_CHECKS
2132 {
2133 const struct GNUNET_PeerIdentity *my_identity;
2135 GNUNET_assert (NULL != my_identity);
2136 /* TODO: might want to eventually implement probabilistic
2137 load-based path verification, but for now it is all or nothing */
2138 failure_offset
2140 bd.data_size,
2141 bd.expiration_time,
2142 trunc_peer,
2143 pp,
2144 putlen + 1,
2145 NULL, 0, /* get_path */
2146 my_identity);
2147 }
2148#else
2149 failure_offset = 0;
2150#endif
2151 if (0 != failure_offset)
2152 {
2153 GNUNET_break_op (0);
2155 "Recorded put path invalid at offset %u, truncating\n",
2156 failure_offset);
2157 GNUNET_assert (failure_offset <= putlen + 1);
2158 bd.put_path = &pp[failure_offset];
2159 bd.put_path_length = (putlen + 1) - failure_offset;
2161 bd.trunc_peer = pp[failure_offset - 1].pred;
2162 }
2163 }
2164 else
2165 {
2166 bd.put_path_length = 0;
2167 }
2168
2169 /* give to local clients */
2171 &bd.key,
2172 0, NULL /* get path */));
2173
2174 /* store locally */
2175 if ( (0 != (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2176 (GDS_am_closest_peer (&put->key,
2177 bf)) )
2179
2180 {
2182 GNUNET_memcpy (&forward->block, &bd, sizeof (bd));
2183
2184 if (bd.put_path_length > 0)
2185 {
2186 forward->put_path = GNUNET_memdup (
2187 bd.put_path,
2188 sizeof (struct GNUNET_DHT_PathElement) * bd.put_path_length);
2189 forward->block.put_path = forward->put_path;
2190 }
2191
2192 forward->data = GNUNET_memdup (bd.data, bd.data_size);
2193 forward->block.data = forward->data;
2194
2195 forward->desired_replication_level = ntohs (put->desired_replication_level
2196 );
2197 forward->hop_count = ntohs (put->hop_count);
2198
2199 /* route to other peers */
2201 forward->desired_replication_level,
2202 forward->hop_count,
2203 bf,
2205 forward);
2206 }
2208 }
2209}
2210
2211
2212struct BlockCls
2213{
2214 struct PeerInfo *pi;
2215 const struct GNUNET_HashCode *query_hash;
2216 struct GNUNET_BLOCK_Group *bg;
2217};
2218
2219
2228static void
2229handle_find_my_hello (struct PeerInfo *pi,
2230 const struct GNUNET_HashCode *query_hash,
2231 struct GNUNET_BLOCK_Group *bg,
2233 void *cb_cls)
2234{
2235 const struct GNUNET_HashCode *my_identity_hash;
2236 const struct GNUNET_PeerIdentity *my_identity;
2237 struct GNUNET_TIME_Absolute block_expiration;
2238 size_t block_size;
2239 void *block;
2240
2241 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
2244 "Handle finding my own HELLO %s\n",
2245 GNUNET_h2s (my_identity_hash));
2246 if (NULL == GDS_my_hello)
2247 {
2249 "# FIND PEER requests ignored due to lack of HELLO",
2250 1,
2251 GNUNET_NO);
2252 if (cb)
2253 cb (cb_cls);
2254 return;
2255 }
2256
2259 &block,
2260 &block_size,
2261 &block_expiration))
2262 {
2263 if (cb)
2264 cb (cb_cls);
2265 return;
2266 }
2267
2271 bg,
2272 my_identity_hash,
2273 NULL, 0,
2274 block,
2275 block_size))
2276 {
2277 struct GNUNET_DATACACHE_Block bd = {
2279 .expiration_time
2282 .key = *my_identity_hash,
2283 .data = block,
2284 .data_size = block_size
2285 };
2286
2288 &bd,
2289 query_hash,
2290 0, NULL /* get path */,
2291 cb,
2292 cb_cls);
2293 }
2294 else
2295 {
2297 "# FIND PEER requests ignored due to Bloomfilter",
2298 1,
2299 GNUNET_NO);
2300 if (cb)
2301 cb (cb_cls);
2302 }
2303
2304 GNUNET_free (block);
2305}
2306
2307
2316static void
2318 const struct GNUNET_HashCode *query_hash,
2319 struct GNUNET_BLOCK_Group *bg,
2321 void *cb_cls)
2322{
2323 /* Force non-random selection by hop count */
2324 struct PeerInfo *peer;
2325
2326 peer = select_peer (query_hash,
2327 NULL,
2328 GDS_NSE_get () + 1);
2330 "Handle finding local HELLO %s\n",
2331 GNUNET_h2s (&peer->phash));
2332 if ( (NULL != peer->hello) &&
2338 bg,
2339 &peer->phash,
2340 NULL, 0, /* xquery */
2341 peer->hello,
2342 peer->hello_size)) )
2343 {
2344 struct GNUNET_DATACACHE_Block bd = {
2346 .expiration_time = peer->hello_expiration,
2347 .key = peer->phash,
2348 .data = peer->hello,
2349 .data_size = peer->hello_size
2350 };
2351
2353 &bd,
2354 query_hash,
2355 0, NULL /* get path */,
2356 cb,
2357 cb_cls);
2358 }
2359 else if (cb)
2360 cb (cb_cls);
2361}
2362
2363
2365{
2366 struct PeerInfo *peer;
2368 void *cb_cls;
2369};
2370
2371
2378static void
2379handle_local_result (void *cls,
2380 const struct GNUNET_DATACACHE_Block *bd)
2381{
2382 struct HandleCallbackLocal *local = cls;
2383
2385 bd,
2386 &bd->key,
2387 0, NULL /* get path */,
2388 local->cb,
2389 local->cb_cls);
2390}
2391
2392
2400static enum GNUNET_GenericReturnValue
2401check_dht_p2p_get (void *cls,
2402 const struct PeerGetMessage *get)
2403{
2404 uint16_t msize = ntohs (get->header.size);
2405 uint16_t result_filter_size = ntohs (get->result_filter_size);
2406
2407 (void) cls;
2408 if (msize < sizeof(*get) + result_filter_size)
2409 {
2410 GNUNET_break_op (0);
2411 return GNUNET_SYSERR;
2412 }
2413 return GNUNET_OK;
2414}
2415
2416
2417struct HandleCallbackGet
2418{
2419 struct Target *t;
2420 struct PeerGetMessage *get;
2422 struct GNUNET_BLOCK_Group *bg;
2424};
2425
2426
2427static void
2429{
2430 struct HandleCallbackGet *handle = cls;
2431 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2432 enum GNUNET_BLOCK_Type type = ntohl (handle->get->type);
2433 const void *result_filter = (const void *) &handle->get[1];
2434 uint16_t msize = ntohs (handle->get->header.size);
2435 uint16_t result_filter_size = ntohs (handle->get->result_filter_size);
2436 const void *xquery = result_filter + result_filter_size;
2437 size_t xquery_size = msize - sizeof (*handle->get) - result_filter_size;
2438
2439 /* remember request for routing replies
2440 TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2441 */
2442 GDS_ROUTING_add (&handle->t->pi->id,
2443 type,
2444 handle->bg, /* bg now owned by routing, but valid at least until end of this function! */
2445 options,
2446 &handle->get->key,
2447 xquery,
2448 xquery_size);
2449
2450 /* P2P forwarding */
2451 {
2452 bool forwarded = false;
2453 uint16_t desired_replication_level = ntohs (
2454 handle->get->desired_replication_level);
2455 uint16_t hop_count = ntohs (handle->get->hop_count);
2456
2458 forwarded = (GNUNET_OK ==
2460 options,
2461 desired_replication_level,
2462 hop_count,
2463 &handle->get->key,
2464 xquery,
2465 xquery_size,
2466 handle->bg,
2467 handle->peer_bf));
2469 options
2470 | (forwarded
2471 ? 0
2473 type,
2474 hop_count,
2475 desired_replication_level,
2476 &handle->get->key);
2477 }
2478 /* clean up; note that 'bg' is owned by routing now! */
2480
2481 GNUNET_free (handle->get);
2483}
2484
2485
2486static void
2488{
2489 struct HandleCallbackGet *handle = cls;
2490 enum GNUNET_BLOCK_Type type = ntohl (handle->get->type);
2491
2493 "Handle getting local HELLO %s of type %u\n",
2494 GNUNET_h2s (&handle->get->key),
2495 type);
2496
2498 {
2499 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2500 const void *result_filter = (const void *) &handle->get[1];
2501 uint16_t msize = ntohs (handle->get->header.size);
2502 uint16_t result_filter_size = ntohs (handle->get->result_filter_size);
2503 const void *xquery = result_filter + result_filter_size;
2504 size_t xquery_size = msize - sizeof (*handle->get) - result_filter_size;
2505 struct HandleCallbackLocal local;
2506 local.peer = handle->t->pi;
2508 local.cb_cls = handle;
2509
2511 handle->eval = GDS_DATACACHE_get_closest (&handle->get->key,
2512 type,
2513 xquery,
2514 xquery_size,
2515 handle->bg,
2517 &local);
2518 else
2519 handle->eval = GDS_DATACACHE_handle_get (&handle->get->key,
2520 type,
2521 xquery,
2522 xquery_size,
2523 handle->bg,
2525 &local);
2526 }
2527 else
2529}
2530
2531
2532static void
2534{
2535 struct HandleCallbackGet *handle = cls;
2536 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2537
2540 &handle->get->key,
2541 handle->bg,
2543 handle);
2544 else
2546}
2547
2548
2555static void
2556handle_dht_p2p_get (void *cls,
2557 const struct PeerGetMessage *get)
2558{
2559 struct Target *t = cls;
2560 struct PeerInfo *peer = t->pi;
2561 uint16_t msize = ntohs (get->header.size);
2562 uint16_t result_filter_size = ntohs (get->result_filter_size);
2563 uint16_t hop_count = ntohs (get->hop_count);
2564 enum GNUNET_BLOCK_Type type = ntohl (get->type);
2565 enum GNUNET_DHT_RouteOption options = ntohs (get->options);
2566 const void *result_filter = (const void *) &get[1];
2567 const void *xquery = result_filter + result_filter_size;
2568 size_t xquery_size = msize - sizeof (*get) - result_filter_size;
2569
2570 /* parse and validate message */
2572 "# P2P GET requests received",
2573 1,
2574 GNUNET_NO);
2576 "# P2P GET bytes received",
2577 msize,
2578 GNUNET_NO);
2579 if (GNUNET_NO ==
2581 type,
2582 &get->key,
2583 xquery,
2584 xquery_size))
2585 {
2586 /* request invalid */
2587 GNUNET_break_op (0);
2588 return;
2589 }
2590
2591 {
2592 const struct GNUNET_PeerIdentity *my_identity;
2593 struct HandleCallbackGet *handle;
2594
2596 handle->t = t;
2597 handle->get = GNUNET_memdup (get, msize);
2599
2601 GNUNET_assert (NULL != my_identity);
2602
2603 handle->peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2608 &peer->phash));
2610 type,
2611 result_filter,
2612 result_filter_size,
2613 "filter-size",
2614 result_filter_size,
2615 NULL);
2617 "GET for %s at %s after %u hops\n",
2618 GNUNET_h2s (&get->key),
2620 (unsigned int) hop_count);
2621 /* local lookup (this may update the bg) */
2623 (GDS_am_closest_peer (&get->key,
2624 handle->peer_bf)) )
2625 {
2628 {
2630 "# P2P HELLO lookup requests processed",
2631 1,
2632 GNUNET_NO);
2634 &get->key,
2635 handle->bg,
2637 handle);
2638 }
2639 else
2641 }
2642 else
2643 {
2645 "# P2P GET requests ONLY routed",
2646 1,
2647 GNUNET_NO);
2649 }
2650 }
2651}
2652
2653
2662static void
2664 const struct GNUNET_HashCode *query_hash,
2665 unsigned int get_path_length,
2666 const struct GNUNET_DHT_PathElement *get_path)
2667{
2668 /* forward to local clients */
2670 "Forwarding reply to local clients\n");
2671 if (! GDS_CLIENTS_handle_reply (bd,
2672 query_hash,
2673 get_path_length,
2674 get_path))
2675 {
2676 GNUNET_break (0);
2677 return;
2678 }
2680 get_path,
2681 get_path_length);
2683 {
2684 struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2685 + bd->put_path_length)];
2686 struct GNUNET_DATACACHE_Block bdx = *bd;
2687
2688 if (NULL != bd->put_path)
2689 GNUNET_memcpy (xput_path,
2690 bd->put_path,
2691 bd->put_path_length * sizeof(struct
2693 GNUNET_memcpy (&xput_path[bd->put_path_length],
2694 get_path,
2695 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2696 bdx.put_path = xput_path;
2697 bdx.put_path_length += get_path_length;
2699 }
2700 /* forward to other peers */
2702 query_hash,
2703 get_path_length,
2704 get_path);
2705}
2706
2707
2715static enum GNUNET_GenericReturnValue
2716check_dht_p2p_result (void *cls,
2717 const struct PeerResultMessage *prm)
2718{
2719 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2720 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2721 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2722 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2723
2724 uint16_t get_path_length = ntohs (prm->get_path_length);
2725 uint16_t put_path_length = ntohs (prm->put_path_length);
2726 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2727 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2728
2729 (void) cls;
2730 if ( (msize < vsize) ||
2731 (msize - vsize <
2732 (get_path_length + put_path_length)
2733 * sizeof(struct GNUNET_DHT_PathElement)) ||
2734 (get_path_length >
2735 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2736 (put_path_length >
2737 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2738 {
2739 GNUNET_break_op (0);
2740 return GNUNET_SYSERR;
2741 }
2742 return GNUNET_OK;
2743}
2744
2745
2752static void
2753handle_dht_p2p_result (void *cls,
2754 const struct PeerResultMessage *prm)
2755{
2756 struct Target *t = cls;
2757 struct PeerInfo *peer = t->pi;
2758 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2759 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2760 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2761 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2762 uint16_t get_path_length = ntohs (prm->get_path_length);
2763 uint16_t put_path_length = ntohs (prm->put_path_length);
2764 const struct GNUNET_PeerIdentity *trunc_peer
2765 = truncated
2766 ? (const struct GNUNET_PeerIdentity *) &prm[1]
2767 : NULL;
2768 const struct GNUNET_DHT_PathElement *put_path
2769 = truncated
2770 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2771 : (const struct GNUNET_DHT_PathElement *) &prm[1];
2772 const struct GNUNET_DHT_PathElement *get_path
2773 = &put_path[put_path_length];
2774 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2775 = tracked
2776 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &get_path[get_path_length]
2777 : NULL;
2778 const void *data
2779 = tracked
2780 ? (const void *) &last_sig[1]
2781 : (const void *) &get_path[get_path_length];
2782 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2783 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2784 struct GNUNET_DATACACHE_Block bd = {
2786 .put_path = put_path,
2787 .put_path_length = put_path_length,
2788 .key = prm->key,
2789 .type = ntohl (prm->type),
2790 .ro = ro,
2791 .data = data,
2792 .data_size = msize - vsize - (get_path_length + put_path_length)
2793 * sizeof(struct GNUNET_DHT_PathElement)
2794 };
2795
2796 /* parse and validate message */
2798 {
2800 "# Expired results discarded",
2801 1,
2802 GNUNET_NO);
2803 return;
2804 }
2805 if (GNUNET_OK !=
2807 bd.type,
2808 bd.data,
2809 bd.data_size))
2810 {
2811 GNUNET_break_op (0);
2812 return;
2813 }
2815 "# P2P RESULTS received",
2816 1,
2817 GNUNET_NO);
2819 "# P2P RESULT bytes received",
2820 msize,
2821 GNUNET_NO);
2822 {
2824
2826 bd.type,
2827 bd.data,
2828 bd.data_size,
2829 &bd.key);
2830 if (GNUNET_NO == ret)
2831 bd.key = prm->key;
2832 }
2833
2834 /* if we got a HELLO, consider it for our own routing table */
2835 hello_check (&bd);
2836
2837 /* Need to append 'peer' to 'get_path' */
2838 if (tracked)
2839 {
2840 struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2841 struct GNUNET_DHT_PathElement *gp = xget_path;
2842 unsigned int failure_offset;
2843
2844 GNUNET_memcpy (xget_path,
2845 get_path,
2846 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2847 xget_path[get_path_length].pred = peer->id;
2848 /* use memcpy(), as last_sig may not be aligned */
2849 memcpy (&xget_path[get_path_length].sig,
2850 last_sig,
2851 sizeof (*last_sig));
2852#if SANITY_CHECKS
2853 {
2854 const struct GNUNET_PeerIdentity *my_identity;
2856 GNUNET_assert (NULL != my_identity);
2857 /* TODO: might want to eventually implement probabilistic
2858 load-based path verification, but for now it is all or nothing */
2859 failure_offset
2861 bd.data_size,
2862 bd.expiration_time,
2863 trunc_peer,
2864 put_path,
2865 put_path_length,
2866 gp,
2867 get_path_length + 1,
2868 my_identity);
2869 }
2870#else
2871 failure_offset = 0;
2872#endif
2873 if (0 != failure_offset)
2874 {
2876 "Recorded path invalid at offset %u, truncating\n",
2877 failure_offset);
2878 GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length
2879 + 1);
2880 if (failure_offset < bd.put_path_length)
2881 {
2882 /* failure on put path */
2883 trunc_peer = &bd.put_path[failure_offset - 1].pred;
2885 bd.put_path = &bd.put_path[failure_offset];
2886 bd.put_path_length -= failure_offset;
2887 truncated = true;
2888 }
2889 else
2890 {
2891 /* failure on get path */
2892 failure_offset -= bd.put_path_length;
2893 if (0 == failure_offset)
2894 trunc_peer = &bd.put_path[bd.put_path_length - 1].pred;
2895 else
2896 trunc_peer = &gp[failure_offset - 1].pred;
2897 get_path_length -= failure_offset;
2898 gp = &gp[failure_offset];
2899 bd.put_path_length = 0;
2900 bd.put_path = NULL;
2902 truncated = true;
2903 }
2904 }
2906 "Extending GET path of length %u with %s\n",
2907 get_path_length,
2908 GNUNET_i2s (&peer->id));
2909 if (truncated)
2910 {
2911 GNUNET_assert (NULL != trunc_peer);
2912 bd.trunc_peer = *trunc_peer;
2913 }
2915 &prm->key,
2916 get_path_length + 1,
2917 gp);
2918 }
2919 else
2920 {
2921 if (truncated)
2922 {
2923 GNUNET_assert (NULL != trunc_peer);
2924 bd.trunc_peer = *trunc_peer;
2925 }
2927 &prm->key,
2928 0,
2929 NULL);
2930 }
2931}
2932
2933
2941static enum GNUNET_GenericReturnValue
2942check_dht_p2p_hello (void *cls,
2943 const struct GNUNET_MessageHeader *hello)
2944{
2945 struct Target *t = cls;
2946 struct PeerInfo *peer = t->pi;
2948 size_t hellob_size;
2949 void *hellob;
2951
2953 &peer->id,
2954 &hellob,
2955 &hellob_size,
2956 &expiration);
2957 GNUNET_free (hellob);
2958 return ret;
2959}
2960
2961
2968static void
2969handle_dht_p2p_hello (void *cls,
2970 const struct GNUNET_MessageHeader *hello)
2971{
2972 struct Target *t = cls;
2973 struct PeerInfo *peer = t->pi;
2974
2975 GNUNET_free (peer->hello);
2976 peer->hello_size = 0;
2979 &peer->id,
2980 &peer->hello,
2981 &peer->hello_size,
2982 &peer->hello_expiration));
2983}
2984
2985
2986void
2987GDS_u_receive (void *cls,
2988 void **tctx,
2989 void **sctx,
2990 const void *message,
2991 size_t message_size)
2992{
2993 struct Target *t = *tctx;
2994 struct GNUNET_MQ_MessageHandler core_handlers[] = {
2995 GNUNET_MQ_hd_var_size (dht_p2p_get,
2997 struct PeerGetMessage,
2998 t),
2999 GNUNET_MQ_hd_var_size (dht_p2p_put,
3001 struct PeerPutMessage,
3002 t),
3003 GNUNET_MQ_hd_var_size (dht_p2p_result,
3005 struct PeerResultMessage,
3006 t),
3007 GNUNET_MQ_hd_var_size (dht_p2p_hello,
3009 struct GNUNET_MessageHeader,
3010 t),
3012 };
3013 const struct GNUNET_MessageHeader *mh = message;
3014
3015 (void) cls; /* the 'struct GDS_Underlay' */
3016 (void) sctx; /* our receiver address */
3017 if (NULL == t)
3018 {
3019 /* Received message claiming to originate from myself?
3020 Ignore! */
3021 GNUNET_break_op (0);
3022 return;
3023 }
3024 if (message_size < sizeof (*mh))
3025 {
3026 GNUNET_break_op (0);
3027 return;
3028 }
3029 if (message_size != ntohs (mh->size))
3030 {
3031 GNUNET_break_op (0);
3032 return;
3033 }
3035 "Handling message of type %u from peer %s\n",
3036 ntohs (mh->type),
3037 GNUNET_i2s (&t->pi->id));
3038 if (GNUNET_OK !=
3039 GNUNET_MQ_handle_message (core_handlers,
3040 mh))
3041 {
3042 GNUNET_break_op (0);
3043 return;
3044 }
3045}
3046
3047
3055void
3056GDS_try_connect (void *cls,
3057 const struct GNUNET_PeerIdentity *pid,
3058 const char *uri)
3059{
3060 const struct GNUNET_PeerIdentity *my_identity;
3061 struct GNUNET_HashCode phash;
3062 int peer_bucket;
3063 struct PeerBucket *bucket;
3064 (void) cls;
3065
3067 GNUNET_assert (NULL != my_identity);
3068
3069 if (0 == GNUNET_memcmp (my_identity, pid))
3070 {
3072 "Got a HELLO for my own PID, ignoring it\n");
3073 return; /* that's us! */
3074 }
3076 sizeof(*pid),
3077 &phash);
3078 peer_bucket = find_bucket (&phash);
3079 GNUNET_assert ( (peer_bucket >= 0) &&
3080 ((unsigned int) peer_bucket < MAX_BUCKETS));
3081 bucket = &k_buckets[peer_bucket];
3082 for (struct PeerInfo *pi = bucket->head;
3083 NULL != pi;
3084 pi = pi->next)
3085 if (0 ==
3086 GNUNET_memcmp (&pi->id,
3087 pid))
3088 {
3089 /* already connected */
3091 uri);
3092 return;
3093 }
3094 if (bucket->peers_size >= bucket_size)
3095 return; /* do not care */
3097 "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
3098 GNUNET_i2s (pid),
3099 uri,
3100 peer_bucket,
3101 bucket->peers_size,
3102 bucket_size);
3103 /* new peer that we like! */
3105 uri);
3106}
3107
3108
3114void
3116{
3117 for (unsigned int bc = 0; bc<closest_bucket; bc++)
3118 {
3119 struct PeerBucket *bucket = &k_buckets[bc];
3120 unsigned int count = 0;
3121
3122 for (struct PeerInfo *pos = bucket->head;
3123 NULL != pos;
3124 pos = pos->next)
3125 {
3126 if (count >= bucket_size)
3127 break; /* we only consider first #bucket_size entries per bucket */
3128 count++;
3129 do_send (pos,
3130 msg);
3131 }
3132 }
3133}
3134
3135
3138{
3139
3140 unsigned long long temp_config_num;
3141
3144 "DHT",
3145 "DISABLE_TRY_CONNECT");
3146 if (GNUNET_OK ==
3148 "DHT",
3149 "bucket_size",
3150 &temp_config_num))
3151 bucket_size = (unsigned int) temp_config_num;
3154 "DHT",
3155 "CACHE_RESULTS");
3157 GNUNET_YES);
3158 return GNUNET_OK;
3159}
3160
3161
3162void
3164{
3165 if (NULL == all_connected_peers)
3166 return;
3167 GNUNET_assert (0 ==
3170 all_connected_peers = NULL;
3171 GNUNET_assert (NULL == find_peer_task);
3172}
3173
3174
3175const struct GNUNET_PeerIdentity *
3177{
3179}
3180
3181
3182/* 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_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_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.
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
The lowest currently used bucket, initially 0 (for 0-bits matching bucket).
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_PeerIdentity pid
Identity of the peer we transmit to / connect to.
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:736
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:727
#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:1033
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:1011
#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:560
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:205
#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
GNUNET_SCHEDULER_TaskCallback cb
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 403 of file gnunet-service-dht_neighbours.c.

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}

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 434 of file gnunet-service-dht_neighbours.c.

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}

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.

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

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

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

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 514 of file gnunet-service-dht_neighbours.c.

517{
518 struct GNUNET_BLOCK_Group *bg = cls;
519 struct PeerInfo *pi = value;
520
522 &pi->phash,
523 1);
525 "Adding known peer (%s) to Bloom filter for FIND PEER\n",
526 GNUNET_i2s (key));
527 return GNUNET_YES;
528}

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 539 of file gnunet-service-dht_neighbours.c.

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

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 630 of file gnunet-service-dht_neighbours.c.

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

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 655 of file gnunet-service-dht_neighbours.c.

659{
660 const struct GNUNET_PeerIdentity *my_identity;
661 struct GDS_Underlay *u = cls;
662 struct PeerInfo *pi;
663 struct PeerBucket *bucket;
664 bool do_hold = false;
665
667 GNUNET_assert (NULL != my_identity);
668
669 /* Check for connect to self message */
670 if (0 == GNUNET_memcmp (my_identity, pid))
671 return;
673 "Connected to peer %s\n",
674 GNUNET_i2s (pid));
676 pid);
677 if (NULL == pi)
678 {
680 "# peers connected",
681 1,
682 GNUNET_NO);
683 pi = GNUNET_new (struct PeerInfo);
684 pi->id = *pid;
686 sizeof(*pid),
687 &pi->phash);
688 pi->peer_bucket = find_bucket (&pi->phash);
689 GNUNET_assert ( (pi->peer_bucket >= 0) &&
690 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
691 bucket = &k_buckets[pi->peer_bucket];
693 bucket->tail,
694 pi);
695 bucket->peers_size++;
697 (unsigned int) pi->peer_bucket + 1);
700 &pi->id,
701 pi,
703 if (bucket->peers_size <= bucket_size)
704 {
706 do_hold = true;
707 }
710 {
711 /* got a first connection, good time to start with FIND PEER requests... */
714 NULL);
715 }
716 }
717 {
718 struct Target *t;
719
720 t = GNUNET_new (struct Target);
721 t->u = u;
722 t->utarget = target;
723 t->pi = pi;
725 pi->t_tail,
726 t);
727 *ctx = t;
728
729 }
730 if (do_hold)
731 update_hold (bucket);
732}

References all_connected_peers, bucket_size, closest_bucket, ctx, disable_try_connect, find_bucket(), find_peer_task, 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, pid, 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 736 of file gnunet-service-dht_neighbours.c.

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

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 812 of file gnunet-service-dht_neighbours.c.

814{
815 uint32_t random_value;
816 uint32_t forward_count;
817 float target_value;
818 double rm1;
819
820 if (hop_count > GDS_NSE_get () * 4.0)
821 {
822 /* forcefully terminate */
824 "# requests TTL-dropped",
825 1,
826 GNUNET_NO);
827 return 0;
828 }
829 if (hop_count > GDS_NSE_get () * 2.0)
830 {
831 /* Once we have reached our ideal number of hops, only forward to 1 peer */
832 return 1;
833 }
834 /* bound by system-wide maximum and minimum */
835 if (0 == target_replication)
836 target_replication = 1; /* 0 is verboten */
837 target_replication =
839 target_replication);
840 rm1 = target_replication - 1.0;
841 target_value =
842 1 + (rm1) / (GDS_NSE_get () + (rm1 * hop_count));
843
844 /* Set forward count to floor of target_value */
845 forward_count = (uint32_t) target_value;
846 /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
847 target_value = target_value - forward_count;
848 random_value = GNUNET_CRYPTO_random_u32 (UINT32_MAX);
849 if (random_value < (target_value * UINT32_MAX))
850 forward_count++;
851 return GNUNET_MIN (forward_count,
853}

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

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 867 of file gnunet-service-dht_neighbours.c.

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

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 940 of file gnunet-service-dht_neighbours.c.

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

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 1156 of file gnunet-service-dht_neighbours.c.

1161{
1162 unsigned int target;
1163 unsigned int off;
1164 struct PeerInfo **rtargets;
1165
1166 GNUNET_assert (NULL != bloom);
1167 target = get_forward_count (hop_count,
1168 target_replication);
1169 if (0 == target)
1170 {
1171 *targets = NULL;
1172 return 0;
1173 }
1174 rtargets = GNUNET_new_array (target,
1175 struct PeerInfo *);
1176 for (off = 0; off < target; off++)
1177 {
1178 struct PeerInfo *nxt;
1179
1180 nxt = select_peer (key,
1181 bloom,
1182 hop_count);
1183 if (NULL == nxt)
1184 break;
1185 rtargets[off] = nxt;
1186 }
1188 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1189 off,
1191 (unsigned int) hop_count,
1192 GNUNET_h2s (key),
1193 target);
1194 if (0 == off)
1195 {
1196 GNUNET_free (rtargets);
1197 *targets = NULL;
1198 return 0;
1199 }
1200 *targets = rtargets;
1202 "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1203 GNUNET_h2s (key),
1204 off,
1205 target);
1206 return off;
1207}

References all_connected_peers, get_forward_count(), GNUNET_assert, GNUNET_CONTAINER_multipeermap_size(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_h2s(), GNUNET_log, GNUNET_new_array, key, 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 1216 of file gnunet-service-dht_neighbours.c.

1217{
1218 struct GNUNET_HELLO_Parser *b;
1219
1221 return;
1222
1224 bd->data_size);
1226 {
1229 NULL);
1230 }
1232}

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 1249 of file gnunet-service-dht_neighbours.c.

1252{
1253 struct GDS_RoutingPutCallbackData *gds_routing = cls;
1254 struct PeerInfo *target;
1255
1256 if (NULL == ppm)
1257 {
1258 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1259 if (*(gds_routing->queued) >= gds_routing->target_count)
1260 {
1261 if (gds_routing->cb)
1262 gds_routing->cb (gds_routing->cb_cls, GNUNET_SYSERR);
1263
1264 GNUNET_free (gds_routing->targets);
1265 GNUNET_free (gds_routing->queued);
1266 }
1267
1268 return true;
1269 }
1270
1271 target = gds_routing->targets[gds_routing->index];
1272
1274 "Routing PUT for %s after %u hops to %s\n",
1275 GNUNET_h2s (&(gds_routing->key)),
1276 (unsigned int) gds_routing->hop_count,
1277 GNUNET_i2s (&target->id));
1278 do_send (target,
1279 &ppm->header);
1280 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1281
1282 if (*(gds_routing->queued) >= gds_routing->target_count)
1283 {
1284 if (gds_routing->cb)
1285 gds_routing->cb (gds_routing->cb_cls, GNUNET_OK);
1286
1287 GNUNET_free (gds_routing->targets);
1289 "# PUT messages queued for transmission",
1290 gds_routing->target_count,
1291 GNUNET_NO);
1292 GNUNET_free (gds_routing->queued);
1293 }
1294
1295 return true;
1296}

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 1300 of file gnunet-service-dht_neighbours.c.

1306{
1307 const struct GNUNET_PeerIdentity *my_identity;
1308 const struct GNUNET_HashCode *my_identity_hash;
1309 struct GDS_RoutingPutCallbackData gds_routing;
1310 size_t msize;
1311 enum GNUNET_DHT_RouteOption ro = bd->ro;
1312 unsigned int put_path_length = bd->put_path_length;
1313 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1314 bool truncated = (0 != (bd->ro & GNUNET_DHT_RO_TRUNCATED));
1315 const struct GNUNET_PeerIdentity *trunc_peer
1316 = truncated
1317 ? &bd->trunc_peer
1318 : NULL;
1319 struct GNUNET_PeerIdentity trunc_peer_out;
1321
1323 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1324 GNUNET_assert (NULL != my_identity);
1325
1328 bd->ro, &ro,
1329 bd->expiration_time,
1330 bd->data, bd->data_size,
1331 put_path, put_path_length,
1332 &put_path_length,
1333 trunc_peer,
1334 &trunc_peer_out,
1335 &truncated);
1336 if (truncated)
1337 trunc_peer = &trunc_peer_out;
1338 /* Path may have been truncated by the call above */
1340 "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1342 GNUNET_h2s (&bd->key),
1343 (bd->ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1344 (bd->ro & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1345
1346 /* if we got a HELLO, consider it for our own routing table */
1347 hello_check (bd);
1348 GNUNET_assert ((NULL != bf) && (NULL != my_identity_hash));
1349 GNUNET_CONTAINER_bloomfilter_add (bf, my_identity_hash);
1351 "# PUT requests routed",
1352 1,
1353 GNUNET_NO);
1354 if (GNUNET_OK != ret)
1355 {
1356 if (cb)
1357 cb (cb_cls, ret);
1358 return;
1359 }
1360 gds_routing.target_count
1361 = get_target_peers (&bd->key,
1362 bf,
1363 hop_count,
1364 desired_replication_level,
1365 &(gds_routing.targets));
1366 if (0 == gds_routing.target_count)
1367 {
1369 "Routing PUT for %s terminates after %u hops at %s\n",
1370 GNUNET_h2s (&bd->key),
1371 (unsigned int) hop_count,
1373 if (cb)
1374 cb (cb_cls, GNUNET_NO);
1375 if (gds_routing.targets)
1376 GNUNET_free (gds_routing.targets);
1377 return;
1378 }
1379 GNUNET_memcpy (&(gds_routing.key), &(bd->key),
1380 sizeof (gds_routing.key));
1381 for (unsigned int i = 0; i < gds_routing.target_count; i++)
1382 {
1383 struct PeerInfo *target = gds_routing.targets[i];
1384
1386 &target->phash);
1387 }
1388
1389 gds_routing.queued = GNUNET_new (unsigned int);
1390 *(gds_routing.queued) = 0;
1391
1392 gds_routing.cb = cb;
1393 gds_routing.cb_cls = cb_cls;
1394
1395 for (unsigned int i = 0; i < gds_routing.target_count; i++)
1396 {
1397 struct PeerInfo *target = gds_routing.targets[i];
1398 struct PeerPutMessage *ppm;
1399 char buf[msize] GNUNET_ALIGN;
1400
1401 gds_routing.index = i;
1402
1403 ppm = (struct PeerPutMessage *) buf;
1404 GDS_helper_make_put_message (ppm, msize,
1405 NULL,
1406 &target->id,
1407 &target->phash,
1408 bf,
1409 &bd->key,
1410 ro,
1411 bd->type,
1412 bd->expiration_time,
1413 bd->data, bd->data_size,
1414 put_path, put_path_length,
1415 hop_count,
1417 trunc_peer,
1419 sizeof (gds_routing),
1420 &gds_routing);
1421 }
1422}

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_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 1426 of file gnunet-service-dht_neighbours.c.

1435{
1436 const struct GNUNET_PeerIdentity *my_identity;
1437 const struct GNUNET_HashCode *my_identity_hash;
1438 unsigned int target_count;
1439 struct PeerInfo **targets;
1440 size_t msize;
1441 size_t result_filter_size;
1442 void *result_filter;
1443
1445 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1446
1447 if (NULL == my_identity_hash)
1448 return GNUNET_NO;
1449
1450 GNUNET_assert (NULL != peer_bf);
1452 "# GET requests routed",
1453 1,
1454 GNUNET_NO);
1455 target_count = get_target_peers (key,
1456 peer_bf,
1457 hop_count,
1458 desired_replication_level,
1459 &targets);
1461 "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1463 GNUNET_h2s (key),
1465 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1466 GNUNET_assert (NULL != my_identity_hash);
1467 GNUNET_CONTAINER_bloomfilter_add (peer_bf, my_identity_hash);
1468 if (0 == target_count)
1469 {
1471 "Routing GET for %s terminates after %u hops at %s\n",
1472 GNUNET_h2s (key),
1473 (unsigned int) hop_count,
1475 return GNUNET_NO;
1476 }
1477 if (GNUNET_OK !=
1479 &result_filter,
1480 &result_filter_size))
1481 {
1482 result_filter = NULL;
1483 result_filter_size = 0;
1484 }
1485 msize = xquery_size + result_filter_size;
1486 if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1487 {
1488 GNUNET_break (0);
1489 GNUNET_free (result_filter);
1490 GNUNET_free (targets);
1491 return GNUNET_NO;
1492 }
1493 /* update BF */
1494 for (unsigned int i = 0; i < target_count; i++)
1495 {
1496 struct PeerInfo *target = targets[i];
1497
1499 &target->phash);
1500 }
1501 /* forward request */
1502 for (unsigned int i = 0; i < target_count; i++)
1503 {
1504 struct PeerInfo *target = targets[i];
1505 struct PeerGetMessage *pgm;
1506 char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1507 char *rf;
1508
1510 "Routing GET for %s after %u hops to %s\n",
1511 GNUNET_h2s (key),
1512 (unsigned int) hop_count,
1513 GNUNET_i2s (&target->id));
1514 pgm = (struct PeerGetMessage *) buf;
1516 pgm->header.size = htons (sizeof (buf));
1517 pgm->type = htonl (type);
1518 pgm->options = htons (options);
1519 pgm->hop_count = htons (hop_count + 1);
1521 pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1524 pgm->bloomfilter,
1526 pgm->key = *key;
1527 rf = (char *) &pgm[1];
1528 GNUNET_memcpy (rf,
1529 result_filter,
1532 xquery,
1533 xquery_size);
1534 do_send (target,
1535 &pgm->header);
1536 }
1538 "# GET messages queued for transmission",
1539 target_count,
1540 GNUNET_NO);
1541 GNUNET_free (targets);
1542 GNUNET_free (result_filter);
1543 return (0 < target_count) ? GNUNET_OK : GNUNET_NO;
1544}

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, PeerInfo::phash, 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 1548 of file gnunet-service-dht_neighbours.c.

1549{
1551 target);
1552}

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 1573 of file gnunet-service-dht_neighbours.c.

1574{
1575 if (reply->block_data)
1576 GNUNET_free (reply->block_data);
1577 if ((reply->bd.put_path_length > 0) && (reply->put_path))
1578 GNUNET_free (reply->put_path);
1579 if (reply->buf)
1580 GNUNET_free (reply->buf);
1581}

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 1585 of file gnunet-service-dht_neighbours.c.

1588{
1589 GNUNET_break (success);
1590 if (cb)
1591 cb (cls);
1592}

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 1596 of file gnunet-service-dht_neighbours.c.

1598{
1599 struct GDS_NeighboursReply *reply = cls;
1600 struct PeerResultMessage *prm = reply->prm;
1601 struct GNUNET_DHT_PathElement *paths = reply->paths;
1602 unsigned int ppl = ntohs (prm->put_path_length);
1603 unsigned int get_path_length = ntohs (prm->get_path_length);
1604 void *tgt = &paths[get_path_length + ppl];
1605 void *data;
1606
1607 if (! sig)
1608 {
1610 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1611 return true;
1612 }
1613
1614 memcpy (tgt,
1615 sig,
1616 sizeof (*sig));
1617 data = tgt + sizeof (*sig);
1619 "Signing GET PATH %u/%u of %s => %s\n",
1620 ppl,
1621 get_path_length,
1622 GNUNET_h2s (&prm->key),
1623 GNUNET_B2S (sig));
1624#if SANITY_CHECKS > 1
1625 {
1626 const struct GNUNET_PeerIdentity *my_identity;
1627 struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
1628 const struct GNUNET_PeerIdentity *trunc_peer = reply->trunc_peer_is_null?
1629 NULL : &reply->trunc_peer_id;
1630
1632 GNUNET_assert (NULL != my_identity);
1633
1634 memcpy (xpaths,
1635 &paths[ppl],
1636 get_path_length * sizeof (struct GNUNET_DHT_PathElement));
1637 xpaths[get_path_length].sig = *sig;
1638 xpaths[get_path_length].pred = *my_identity;
1639 if (0 !=
1641 reply->bd.data_size,
1642 reply->bd.expiration_time,
1643 trunc_peer,
1644 paths,
1645 ppl,
1646 xpaths,
1647 get_path_length + 1,
1648 &reply->pi->id))
1649 {
1650 GNUNET_break (0);
1652 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1653 return true;
1654 }
1655 }
1656#endif
1658 reply->bd.data,
1659 reply->bd.data_size);
1660 do_send (reply->pi,
1661 &prm->header);
1663 safe_neighbours_callback (reply->cb_cls, reply->cb, true);
1664 return true;
1665}

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 1669 of file gnunet-service-dht_neighbours.c.

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

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_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 1899 of file gnunet-service-dht_neighbours.c.

1901{
1902 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1903 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1904 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1905 uint16_t msize = ntohs (put->header.size);
1906 uint16_t putlen = ntohs (put->put_path_length);
1907 size_t xsize = (has_path
1908 ? sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1909 : 0)
1910 + (truncated
1911 ? sizeof (struct GNUNET_PeerIdentity)
1912 : 0);
1913 size_t var_meta_size
1914 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1915 + xsize;
1916
1917 (void) cls;
1918 if ( (msize <
1919 sizeof (struct PeerPutMessage) + var_meta_size) ||
1920 (putlen >
1921 (GNUNET_MAX_MESSAGE_SIZE
1922 - sizeof (struct PeerPutMessage)
1923 - xsize)
1924 / sizeof(struct GNUNET_DHT_PathElement)) )
1925 {
1926 GNUNET_break_op (0);
1927 return GNUNET_SYSERR;
1928 }
1929 if (GNUNET_BLOCK_TYPE_ANY == htonl (put->type))
1930 {
1931 GNUNET_break_op (0);
1932 return GNUNET_SYSERR;
1933 }
1934 return GNUNET_OK;
1935}

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 1951 of file gnunet-service-dht_neighbours.c.

1953{
1954 struct ForwardedDHTPut *put = cls;
1955
1956 /* notify monitoring clients */
1957 put->block.ro |= ((GNUNET_OK == forwarded)
1959 : 0);
1961 put->hop_count,
1963
1964 if (put->put_path)
1965 GNUNET_free (put->put_path);
1966 GNUNET_free (put->data);
1967 GNUNET_free (put);
1968}

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 1978 of file gnunet-service-dht_neighbours.c.

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

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 2230 of file gnunet-service-dht_neighbours.c.

2235{
2236 const struct GNUNET_HashCode *my_identity_hash;
2237 const struct GNUNET_PeerIdentity *my_identity;
2238 struct GNUNET_TIME_Absolute block_expiration;
2239 size_t block_size;
2240 void *block;
2241
2242 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
2245 "Handle finding my own HELLO %s\n",
2246 GNUNET_h2s (my_identity_hash));
2247 if (NULL == GDS_my_hello)
2248 {
2250 "# FIND PEER requests ignored due to lack of HELLO",
2251 1,
2252 GNUNET_NO);
2253 if (cb)
2254 cb (cb_cls);
2255 return;
2256 }
2257
2260 &block,
2261 &block_size,
2262 &block_expiration))
2263 {
2264 if (cb)
2265 cb (cb_cls);
2266 return;
2267 }
2268
2272 bg,
2273 my_identity_hash,
2274 NULL, 0,
2275 block,
2276 block_size))
2277 {
2278 struct GNUNET_DATACACHE_Block bd = {
2280 .expiration_time
2283 .key = *my_identity_hash,
2284 .data = block,
2285 .data_size = block_size
2286 };
2287
2289 &bd,
2290 query_hash,
2291 0, NULL /* get path */,
2292 cb,
2293 cb_cls);
2294 }
2295 else
2296 {
2298 "# FIND PEER requests ignored due to Bloomfilter",
2299 1,
2300 GNUNET_NO);
2301 if (cb)
2302 cb (cb_cls);
2303 }
2304
2305 GNUNET_free (block);
2306}

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 2318 of file gnunet-service-dht_neighbours.c.

2323{
2324 /* Force non-random selection by hop count */
2325 struct PeerInfo *peer;
2326
2327 peer = select_peer (query_hash,
2328 NULL,
2329 GDS_NSE_get () + 1);
2331 "Handle finding local HELLO %s\n",
2332 GNUNET_h2s (&peer->phash));
2333 if ( (NULL != peer->hello) &&
2339 bg,
2340 &peer->phash,
2341 NULL, 0, /* xquery */
2342 peer->hello,
2343 peer->hello_size)) )
2344 {
2345 struct GNUNET_DATACACHE_Block bd = {
2347 .expiration_time = peer->hello_expiration,
2348 .key = peer->phash,
2349 .data = peer->hello,
2350 .data_size = peer->hello_size
2351 };
2352
2354 &bd,
2355 query_hash,
2356 0, NULL /* get path */,
2357 cb,
2358 cb_cls);
2359 }
2360 else if (cb)
2361 cb (cb_cls);
2362}

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 2380 of file gnunet-service-dht_neighbours.c.

2382{
2383 struct HandleCallbackLocal *local = cls;
2384
2386 bd,
2387 &bd->key,
2388 0, NULL /* get path */,
2389 local->cb,
2390 local->cb_cls);
2391}

References HandleCallbackLocal::cb, HandleCallbackLocal::cb_cls, GDS_NEIGHBOURS_handle_reply(), GNUNET_DATACACHE_Block::key, and HandleCallbackLocal::peer.

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 2402 of file gnunet-service-dht_neighbours.c.

2404{
2405 uint16_t msize = ntohs (get->header.size);
2406 uint16_t result_filter_size = ntohs (get->result_filter_size);
2407
2408 (void) cls;
2409 if (msize < sizeof(*get) + result_filter_size)
2410 {
2411 GNUNET_break_op (0);
2412 return GNUNET_SYSERR;
2413 }
2414 return GNUNET_OK;
2415}

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 2429 of file gnunet-service-dht_neighbours.c.

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

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 2488 of file gnunet-service-dht_neighbours.c.

2489{
2490 struct HandleCallbackGet *handle = cls;
2491 enum GNUNET_BLOCK_Type type = ntohl (handle->get->type);
2492
2494 "Handle getting local HELLO %s of type %u\n",
2495 GNUNET_h2s (&handle->get->key),
2496 type);
2497
2499 {
2500 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2501 const void *result_filter = (const void *) &handle->get[1];
2502 uint16_t msize = ntohs (handle->get->header.size);
2503 uint16_t result_filter_size = ntohs (handle->get->result_filter_size);
2504 const void *xquery = result_filter + result_filter_size;
2505 size_t xquery_size = msize - sizeof (*handle->get) - result_filter_size;
2506 struct HandleCallbackLocal local;
2507 local.peer = handle->t->pi;
2509 local.cb_cls = handle;
2510
2512 handle->eval = GDS_DATACACHE_get_closest (&handle->get->key,
2513 type,
2514 xquery,
2515 xquery_size,
2516 handle->bg,
2518 &local);
2519 else
2520 handle->eval = GDS_DATACACHE_handle_get (&handle->get->key,
2521 type,
2522 xquery,
2523 xquery_size,
2524 handle->bg,
2526 &local);
2527 }
2528 else
2530}

References HandleCallbackLocal::cb, HandleCallbackLocal::cb_cls, 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, HandleCallbackLocal::peer, 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 2534 of file gnunet-service-dht_neighbours.c.

2535{
2536 struct HandleCallbackGet *handle = cls;
2537 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2538
2541 &handle->get->key,
2542 handle->bg,
2544 handle);
2545 else
2547}

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 2557 of file gnunet-service-dht_neighbours.c.

2559{
2560 struct Target *t = cls;
2561 struct PeerInfo *peer = t->pi;
2562 uint16_t msize = ntohs (get->header.size);
2563 uint16_t result_filter_size = ntohs (get->result_filter_size);
2564 uint16_t hop_count = ntohs (get->hop_count);
2565 enum GNUNET_BLOCK_Type type = ntohl (get->type);
2566 enum GNUNET_DHT_RouteOption options = ntohs (get->options);
2567 const void *result_filter = (const void *) &get[1];
2568 const void *xquery = result_filter + result_filter_size;
2569 size_t xquery_size = msize - sizeof (*get) - result_filter_size;
2570
2571 /* parse and validate message */
2573 "# P2P GET requests received",
2574 1,
2575 GNUNET_NO);
2577 "# P2P GET bytes received",
2578 msize,
2579 GNUNET_NO);
2580 if (GNUNET_NO ==
2582 type,
2583 &get->key,
2584 xquery,
2585 xquery_size))
2586 {
2587 /* request invalid */
2588 GNUNET_break_op (0);
2589 return;
2590 }
2591
2592 {
2593 const struct GNUNET_PeerIdentity *my_identity;
2594 struct HandleCallbackGet *handle;
2595
2597 handle->t = t;
2598 handle->get = GNUNET_memdup (get, msize);
2600
2602 GNUNET_assert (NULL != my_identity);
2603
2604 handle->peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2609 &peer->phash));
2611 type,
2612 result_filter,
2613 result_filter_size,
2614 "filter-size",
2615 result_filter_size,
2616 NULL);
2618 "GET for %s at %s after %u hops\n",
2619 GNUNET_h2s (&get->key),
2621 (unsigned int) hop_count);
2622 /* local lookup (this may update the bg) */
2624 (GDS_am_closest_peer (&get->key,
2625 handle->peer_bf)) )
2626 {
2629 {
2631 "# P2P HELLO lookup requests processed",
2632 1,
2633 GNUNET_NO);
2635 &get->key,
2636 handle->bg,
2638 handle);
2639 }
2640 else
2642 }
2643 else
2644 {
2646 "# P2P GET requests ONLY routed",
2647 1,
2648 GNUNET_NO);
2650 }
2651 }
2652}

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 2664 of file gnunet-service-dht_neighbours.c.

2668{
2669 /* forward to local clients */
2671 "Forwarding reply to local clients\n");
2672 if (! GDS_CLIENTS_handle_reply (bd,
2673 query_hash,
2674 get_path_length,
2675 get_path))
2676 {
2677 GNUNET_break (0);
2678 return;
2679 }
2681 get_path,
2682 get_path_length);
2684 {
2685 struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2686 + bd->put_path_length)];
2687 struct GNUNET_DATACACHE_Block bdx = *bd;
2688
2689 if (NULL != bd->put_path)
2690 GNUNET_memcpy (xput_path,
2691 bd->put_path,
2692 bd->put_path_length * sizeof(struct
2694 GNUNET_memcpy (&xput_path[bd->put_path_length],
2695 get_path,
2696 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2697 bdx.put_path = xput_path;
2698 bdx.put_path_length += get_path_length;
2700 }
2701 /* forward to other peers */
2703 query_hash,
2704 get_path_length,
2705 get_path);
2706}

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 2717 of file gnunet-service-dht_neighbours.c.

2719{
2720 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2721 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2722 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2723 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2724
2725 uint16_t get_path_length = ntohs (prm->get_path_length);
2726 uint16_t put_path_length = ntohs (prm->put_path_length);
2727 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2728 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2729
2730 (void) cls;
2731 if ( (msize < vsize) ||
2732 (msize - vsize <
2733 (get_path_length + put_path_length)
2734 * sizeof(struct GNUNET_DHT_PathElement)) ||
2735 (get_path_length >
2736 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2737 (put_path_length >
2738 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2739 {
2740 GNUNET_break_op (0);
2741 return GNUNET_SYSERR;
2742 }
2743 return GNUNET_OK;
2744}

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 2754 of file gnunet-service-dht_neighbours.c.

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

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 2943 of file gnunet-service-dht_neighbours.c.

2945{
2946 struct Target *t = cls;
2947 struct PeerInfo *peer = t->pi;
2949 size_t hellob_size;
2950 void *hellob;
2952
2954 &peer->id,
2955 &hellob,
2956 &hellob_size,
2957 &expiration);
2958 GNUNET_free (hellob);
2959 return ret;
2960}

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 2970 of file gnunet-service-dht_neighbours.c.

2972{
2973 struct Target *t = cls;
2974 struct PeerInfo *peer = t->pi;
2975
2976 GNUNET_free (peer->hello);
2977 peer->hello_size = 0;
2980 &peer->id,
2981 &peer->hello,
2982 &peer->hello_size,
2983 &peer->hello_expiration));
2984}

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 2988 of file gnunet-service-dht_neighbours.c.

2993{
2994 struct Target *t = *tctx;
2995 struct GNUNET_MQ_MessageHandler core_handlers[] = {
2996 GNUNET_MQ_hd_var_size (dht_p2p_get,
2998 struct PeerGetMessage,
2999 t),
3000 GNUNET_MQ_hd_var_size (dht_p2p_put,
3002 struct PeerPutMessage,
3003 t),
3004 GNUNET_MQ_hd_var_size (dht_p2p_result,
3006 struct PeerResultMessage,
3007 t),
3008 GNUNET_MQ_hd_var_size (dht_p2p_hello,
3010 struct GNUNET_MessageHeader,
3011 t),
3013 };
3014 const struct GNUNET_MessageHeader *mh = message;
3015
3016 (void) cls; /* the 'struct GDS_Underlay' */
3017 (void) sctx; /* our receiver address */
3018 if (NULL == t)
3019 {
3020 /* Received message claiming to originate from myself?
3021 Ignore! */
3022 GNUNET_break_op (0);
3023 return;
3024 }
3025 if (message_size < sizeof (*mh))
3026 {
3027 GNUNET_break_op (0);
3028 return;
3029 }
3030 if (message_size != ntohs (mh->size))
3031 {
3032 GNUNET_break_op (0);
3033 return;
3034 }
3036 "Handling message of type %u from peer %s\n",
3037 ntohs (mh->type),
3038 GNUNET_i2s (&t->pi->id));
3039 if (GNUNET_OK !=
3040 GNUNET_MQ_handle_message (core_handlers,
3041 mh))
3042 {
3043 GNUNET_break_op (0);
3044 return;
3045 }
3046}

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 3057 of file gnunet-service-dht_neighbours.c.

3060{
3061 const struct GNUNET_PeerIdentity *my_identity;
3062 struct GNUNET_HashCode phash;
3063 int peer_bucket;
3064 struct PeerBucket *bucket;
3065 (void) cls;
3066
3068 GNUNET_assert (NULL != my_identity);
3069
3070 if (0 == GNUNET_memcmp (my_identity, pid))
3071 {
3073 "Got a HELLO for my own PID, ignoring it\n");
3074 return; /* that's us! */
3075 }
3077 sizeof(*pid),
3078 &phash);
3079 peer_bucket = find_bucket (&phash);
3080 GNUNET_assert ( (peer_bucket >= 0) &&
3081 ((unsigned int) peer_bucket < MAX_BUCKETS));
3082 bucket = &k_buckets[peer_bucket];
3083 for (struct PeerInfo *pi = bucket->head;
3084 NULL != pi;
3085 pi = pi->next)
3086 if (0 ==
3087 GNUNET_memcmp (&pi->id,
3088 pid))
3089 {
3090 /* already connected */
3092 uri);
3093 return;
3094 }
3095 if (bucket->peers_size >= bucket_size)
3096 return; /* do not care */
3098 "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
3099 GNUNET_i2s (pid),
3100 uri,
3101 peer_bucket,
3102 bucket->peers_size,
3103 bucket_size);
3104 /* new peer that we like! */
3106 uri);
3107}

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, pid, 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 3116 of file gnunet-service-dht_neighbours.c.

3117{
3118 for (unsigned int bc = 0; bc<closest_bucket; bc++)
3119 {
3120 struct PeerBucket *bucket = &k_buckets[bc];
3121 unsigned int count = 0;
3122
3123 for (struct PeerInfo *pos = bucket->head;
3124 NULL != pos;
3125 pos = pos->next)
3126 {
3127 if (count >= bucket_size)
3128 break; /* we only consider first #bucket_size entries per bucket */
3129 count++;
3130 do_send (pos,
3131 msg);
3132 }
3133 }
3134}

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 3138 of file gnunet-service-dht_neighbours.c.

3139{
3140
3141 unsigned long long temp_config_num;
3142
3145 "DHT",
3146 "DISABLE_TRY_CONNECT");
3147 if (GNUNET_OK ==
3149 "DHT",
3150 "bucket_size",
3151 &temp_config_num))
3152 bucket_size = (unsigned int) temp_config_num;
3155 "DHT",
3156 "CACHE_RESULTS");
3158 GNUNET_YES);
3159 return GNUNET_OK;
3160}

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 3164 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 3177 of file gnunet-service-dht_neighbours.c.

3178{
3180}

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

The lowest currently used bucket, initially 0 (for 0-bits matching bucket).

Definition at line 360 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 366 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 371 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 376 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 382 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 392 of file gnunet-service-dht_neighbours.c.

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