GNUnet 0.26.2-98-gb402d9955
 
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 =
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}
620
621
629static void
630update_hold (struct PeerBucket *bucket)
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}
652
653
654void
655GDS_u_connect (void *cls,
656 struct GNUNET_DHTU_Target *target,
657 const struct GNUNET_PeerIdentity *pid,
658 void **ctx)
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}
733
734
735void
736GDS_u_disconnect (void *ctx)
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}
801
802
811static unsigned int
812get_forward_count (uint16_t hop_count,
813 uint16_t target_replication)
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;
849 UINT32_MAX);
850 if (random_value < (target_value * UINT32_MAX))
851 forward_count++;
852 return GNUNET_MIN (forward_count,
854}
855
856
869 const struct GNUNET_CONTAINER_BloomFilter *bloom)
870{
871 const struct GNUNET_HashCode *my_identity_hash;
872 int delta;
873 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
874 GNUNET_assert (NULL != my_identity_hash);
875 if (0 == GNUNET_memcmp (my_identity_hash, key))
876 return GNUNET_YES;
877 for (int bucket_num = find_bucket (key);
878 bucket_num < closest_bucket;
879 bucket_num++)
880 {
881 unsigned int count = 0;
882 GNUNET_assert (bucket_num >= 0);
883 for (struct PeerInfo *pos = k_buckets[bucket_num].head;
884 NULL != pos;
885 pos = pos->next)
886 {
887 if (count >= bucket_size)
888 break; /* we only consider first #bucket_size entries per bucket */
889 count++;
890 if ( (NULL != bloom) &&
891 (GNUNET_YES ==
893 &pos->phash)) )
894 continue; /* Ignore filtered peers */
895 /* All peers in this bucket must be closer than us, as
896 they mismatch with our PID on the pivotal bit. So
897 because an unfiltered peer exists, we are not the
898 closest. */
899 delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
900 my_identity_hash,
901 key);
902 switch (delta)
903 {
904 case -1: /* pos closer */
905 return GNUNET_NO;
906 case 0: /* identical, impossible! */
907 GNUNET_assert (0);
908 break;
909 case 1: /* I am closer */
910 break;
911 }
912 }
913 }
914 /* No closer (unfiltered) peers found; we must be the closest! */
915 return GNUNET_YES;
916}
917
918
940static struct PeerInfo *
941select_peer (const struct GNUNET_HashCode *key,
942 const struct GNUNET_CONTAINER_BloomFilter *bloom,
943 uint32_t hops)
944{
945 if (0 == closest_bucket)
946 {
948 "# Peer selection failed",
949 1,
950 GNUNET_NO);
951 return NULL; /* we have zero connections */
952 }
953 if (hops >= GDS_NSE_get ())
954 {
955 /* greedy selection (closest peer that is not in Bloom filter) */
956 struct PeerInfo *chosen = NULL;
957 int best_bucket;
958 int bucket_offset;
959
960 {
961 const struct GNUNET_HashCode *my_identity_hash;
962 struct GNUNET_HashCode xor;
963 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
964 GNUNET_assert (NULL != my_identity_hash);
966 my_identity_hash,
967 &xor);
968 best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
969 }
970 if (best_bucket >= closest_bucket)
971 bucket_offset = closest_bucket - 1;
972 else
973 bucket_offset = best_bucket;
974 while (-1 != bucket_offset)
975 {
976 struct PeerBucket *bucket = &k_buckets[bucket_offset];
977 unsigned int count = 0;
978
979 for (struct PeerInfo *pos = bucket->head;
980 NULL != pos;
981 pos = pos->next)
982 {
983 if (count >= bucket_size)
984 break; /* we only consider first #bucket_size entries per bucket */
985 count++;
986 if ( (NULL != bloom) &&
987 (GNUNET_YES ==
989 &pos->phash)) )
990 {
992 "Excluded peer `%s' due to BF match in greedy routing for %s\n",
993 GNUNET_i2s (&pos->id),
994 GNUNET_h2s (key));
995 continue;
996 }
997 if (NULL == chosen)
998 {
999 /* First candidate */
1000 chosen = pos;
1001 }
1002 else
1003 {
1004 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
1005 &chosen->phash,
1006 key);
1007 switch (delta)
1008 {
1009 case -1: /* pos closer */
1010 chosen = pos;
1011 break;
1012 case 0: /* identical, impossible! */
1013 GNUNET_assert (0);
1014 break;
1015 case 1: /* chosen closer */
1016 break;
1017 }
1018 }
1019 count++;
1020 } /* for all (#bucket_size) peers in bucket */
1021 if (NULL != chosen)
1022 break;
1023
1024 /* If we chose nothing in first iteration, first go through deeper
1025 buckets (best chance to find a good match), and if we still found
1026 nothing, then to shallower buckets. Terminate on any match in the
1027 current bucket, as this search order guarantees that it can only get
1028 worse as we keep going. */
1029 if (bucket_offset > best_bucket)
1030 {
1031 /* Go through more deeper buckets */
1032 bucket_offset++;
1033 if (bucket_offset == closest_bucket)
1034 {
1035 /* Can't go any deeper, if nothing selected,
1036 go for shallower buckets */
1037 bucket_offset = best_bucket - 1;
1038 }
1039 }
1040 else
1041 {
1042 /* We're either at the 'best_bucket' or already moving
1043 on to shallower buckets. */
1044 if (bucket_offset == best_bucket)
1045 bucket_offset++; /* go for deeper buckets */
1046 else
1047 bucket_offset--; /* go for shallower buckets */
1048 }
1049 } /* for applicable buckets (starting at best match) */
1050 if (NULL == chosen)
1051 {
1053 "# Peer selection failed",
1054 1,
1055 GNUNET_NO);
1056 return NULL;
1057 }
1059 "Selected peer `%s' in greedy routing for %s\n",
1060 GNUNET_i2s (&chosen->id),
1061 GNUNET_h2s (key));
1062 return chosen;
1063 } /* end of 'greedy' peer selection */
1064
1065 /* select "random" peer */
1066 /* count number of peers that are available and not filtered,
1067 but limit to at most #bucket_size peers, starting with
1068 those 'furthest' from us. */
1069 {
1070 unsigned int total = 0;
1071 unsigned int selected;
1072
1073 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1074 {
1075 struct PeerBucket *bucket = &k_buckets[bc];
1076 unsigned int count = 0;
1077
1078 for (struct PeerInfo *pos = bucket->head;
1079 NULL != pos;
1080 pos = pos->next)
1081 {
1082 count++;
1083 if (count > bucket_size)
1084 break; /* limits search to #bucket_size peers per bucket */
1085 if ( (NULL != bloom) &&
1086 (GNUNET_YES ==
1088 &pos->phash)) )
1089 {
1091 "Excluded peer `%s' due to BF match in random routing for %s\n",
1092 GNUNET_i2s (&pos->id),
1093 GNUNET_h2s (key));
1094 continue; /* Ignore filtered peers */
1095 }
1096 total++;
1097 } /* for all peers in bucket */
1098 } /* for all buckets */
1099 if (0 == total) /* No peers to select from! */
1100 {
1102 "# Peer selection failed",
1103 1,
1104 GNUNET_NO);
1105 return NULL;
1106 }
1107
1108 /* Now actually choose a peer */
1110 total);
1111 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1112 {
1113 unsigned int count = 0;
1114
1115 for (struct PeerInfo *pos = k_buckets[bc].head;
1116 pos != NULL;
1117 pos = pos->next)
1118 {
1119 count++;
1120 if (count > bucket_size)
1121 break; /* limits search to #bucket_size peers per bucket */
1122
1123 if ( (NULL != bloom) &&
1124 (GNUNET_YES ==
1126 &pos->phash)) )
1127 continue; /* Ignore bloomfiltered peers */
1128 if (0 == selected--)
1129 {
1131 "Selected peer `%s' in random routing for %s\n",
1132 GNUNET_i2s (&pos->id),
1133 GNUNET_h2s (key));
1134 return pos;
1135 }
1136 } /* for peers in bucket */
1137 } /* for all buckets */
1138 } /* random peer selection scope */
1139 GNUNET_break (0);
1140 return NULL;
1141}
1142
1143
1157static unsigned int
1158get_target_peers (const struct GNUNET_HashCode *key,
1159 struct GNUNET_CONTAINER_BloomFilter *bloom,
1160 uint16_t hop_count,
1161 uint16_t target_replication,
1162 struct PeerInfo ***targets)
1163{
1164 unsigned int target;
1165 unsigned int off;
1166 struct PeerInfo **rtargets;
1167
1168 GNUNET_assert (NULL != bloom);
1169 target = get_forward_count (hop_count,
1170 target_replication);
1171 if (0 == target)
1172 {
1173 *targets = NULL;
1174 return 0;
1175 }
1176 rtargets = GNUNET_new_array (target,
1177 struct PeerInfo *);
1178 for (off = 0; off < target; off++)
1179 {
1180 struct PeerInfo *nxt;
1181
1182 nxt = select_peer (key,
1183 bloom,
1184 hop_count);
1185 if (NULL == nxt)
1186 break;
1187 rtargets[off] = nxt;
1188 }
1190 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1191 off,
1193 (unsigned int) hop_count,
1194 GNUNET_h2s (key),
1195 target);
1196 if (0 == off)
1197 {
1198 GNUNET_free (rtargets);
1199 *targets = NULL;
1200 return 0;
1201 }
1202 *targets = rtargets;
1204 "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1205 GNUNET_h2s (key),
1206 off,
1207 target);
1208 return off;
1209}
1210
1211
1217static void
1218hello_check (const struct GNUNET_DATACACHE_Block *bd)
1219{
1220 struct GNUNET_HELLO_Parser *b;
1221
1223 return;
1224
1226 bd->data_size);
1228 {
1231 NULL);
1232 }
1234}
1235
1236
1238{
1239 unsigned int hop_count;
1240 unsigned int target_count;
1241 struct PeerInfo **targets;
1242 struct GNUNET_HashCode key;
1243 unsigned int index;
1244 unsigned int *queued;
1246 void *cb_cls;
1247};
1248
1249
1250static bool
1251cb_routing_put_message (void *cls,
1252 size_t msize,
1253 struct PeerPutMessage *ppm)
1254{
1255 struct GDS_RoutingPutCallbackData *gds_routing = cls;
1256 struct PeerInfo *target;
1257
1258 if (NULL == ppm)
1259 {
1260 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1261 if (*(gds_routing->queued) >= gds_routing->target_count)
1262 {
1263 if (gds_routing->cb)
1264 gds_routing->cb (gds_routing->cb_cls, GNUNET_SYSERR);
1265
1266 GNUNET_free (gds_routing->targets);
1267 GNUNET_free (gds_routing->queued);
1268 }
1269
1270 return true;
1271 }
1272
1273 target = gds_routing->targets[gds_routing->index];
1274
1276 "Routing PUT for %s after %u hops to %s\n",
1277 GNUNET_h2s (&(gds_routing->key)),
1278 (unsigned int) gds_routing->hop_count,
1279 GNUNET_i2s (&target->id));
1280 do_send (target,
1281 &ppm->header);
1282 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1283
1284 if (*(gds_routing->queued) >= gds_routing->target_count)
1285 {
1286 if (gds_routing->cb)
1287 gds_routing->cb (gds_routing->cb_cls, GNUNET_OK);
1288
1289 GNUNET_free (gds_routing->targets);
1291 "# PUT messages queued for transmission",
1292 gds_routing->target_count,
1293 GNUNET_NO);
1294 GNUNET_free (gds_routing->queued);
1295 }
1296
1297 return true;
1298}
1299
1300
1301void
1303 uint16_t desired_replication_level,
1304 uint16_t hop_count,
1307 void *cb_cls)
1308{
1309 const struct GNUNET_PeerIdentity *my_identity;
1310 const struct GNUNET_HashCode *my_identity_hash;
1311 struct GDS_RoutingPutCallbackData gds_routing;
1312 size_t msize;
1313 enum GNUNET_DHT_RouteOption ro = bd->ro;
1314 unsigned int put_path_length = bd->put_path_length;
1315 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1316 bool truncated = (0 != (bd->ro & GNUNET_DHT_RO_TRUNCATED));
1317 const struct GNUNET_PeerIdentity *trunc_peer
1318 = truncated
1319 ? &bd->trunc_peer
1320 : NULL;
1321 struct GNUNET_PeerIdentity trunc_peer_out;
1323
1325 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1326 GNUNET_assert (NULL != my_identity);
1327
1330 bd->ro, &ro,
1331 bd->expiration_time,
1332 bd->data, bd->data_size,
1333 put_path, put_path_length,
1334 &put_path_length,
1335 trunc_peer,
1336 &trunc_peer_out,
1337 &truncated);
1338 if (truncated)
1339 trunc_peer = &trunc_peer_out;
1340 /* Path may have been truncated by the call above */
1342 "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1344 GNUNET_h2s (&bd->key),
1345 (bd->ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1346 (bd->ro & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1347
1348 /* if we got a HELLO, consider it for our own routing table */
1349 hello_check (bd);
1350 GNUNET_assert ((NULL != bf) && (NULL != my_identity_hash));
1351 GNUNET_CONTAINER_bloomfilter_add (bf, my_identity_hash);
1353 "# PUT requests routed",
1354 1,
1355 GNUNET_NO);
1356 if (GNUNET_OK != ret)
1357 {
1358 if (cb)
1359 cb (cb_cls, ret);
1360 return;
1361 }
1362 gds_routing.target_count
1363 = get_target_peers (&bd->key,
1364 bf,
1365 hop_count,
1366 desired_replication_level,
1367 &(gds_routing.targets));
1368 if (0 == gds_routing.target_count)
1369 {
1371 "Routing PUT for %s terminates after %u hops at %s\n",
1372 GNUNET_h2s (&bd->key),
1373 (unsigned int) hop_count,
1375 if (cb)
1376 cb (cb_cls, GNUNET_NO);
1377 if (gds_routing.targets)
1378 GNUNET_free (gds_routing.targets);
1379 return;
1380 }
1381 GNUNET_memcpy (&(gds_routing.key), &(bd->key),
1382 sizeof (gds_routing.key));
1383 for (unsigned int i = 0; i < gds_routing.target_count; i++)
1384 {
1385 struct PeerInfo *target = gds_routing.targets[i];
1386
1388 &target->phash);
1389 }
1390
1391 gds_routing.queued = GNUNET_new (unsigned int);
1392 *(gds_routing.queued) = 0;
1393
1394 gds_routing.cb = cb;
1395 gds_routing.cb_cls = cb_cls;
1396
1397 for (unsigned int i = 0; i < gds_routing.target_count; i++)
1398 {
1399 struct PeerInfo *target = gds_routing.targets[i];
1400 struct PeerPutMessage *ppm;
1401 char buf[msize] GNUNET_ALIGN;
1402
1403 gds_routing.index = i;
1404
1405 ppm = (struct PeerPutMessage *) buf;
1406 GDS_helper_make_put_message (ppm, msize,
1407 NULL,
1408 &target->id,
1409 &target->phash,
1410 bf,
1411 &bd->key,
1412 ro,
1413 bd->type,
1414 bd->expiration_time,
1415 bd->data, bd->data_size,
1416 put_path, put_path_length,
1417 hop_count,
1419 trunc_peer,
1421 sizeof (gds_routing),
1422 &gds_routing);
1423 }
1424}
1425
1426
1431 uint16_t hop_count,
1432 const struct GNUNET_HashCode *key,
1433 const void *xquery,
1434 size_t xquery_size,
1435 struct GNUNET_BLOCK_Group *bg,
1436 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
1437{
1438 const struct GNUNET_PeerIdentity *my_identity;
1439 const struct GNUNET_HashCode *my_identity_hash;
1440 unsigned int target_count;
1441 struct PeerInfo **targets;
1442 size_t msize;
1443 size_t result_filter_size;
1444 void *result_filter;
1445
1447 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1448
1449 if (NULL == my_identity_hash)
1450 return GNUNET_NO;
1451
1452 GNUNET_assert (NULL != peer_bf);
1454 "# GET requests routed",
1455 1,
1456 GNUNET_NO);
1457 target_count = get_target_peers (key,
1458 peer_bf,
1459 hop_count,
1460 desired_replication_level,
1461 &targets);
1463 "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1465 GNUNET_h2s (key),
1467 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1468 GNUNET_assert (NULL != my_identity_hash);
1469 GNUNET_CONTAINER_bloomfilter_add (peer_bf, my_identity_hash);
1470 if (0 == target_count)
1471 {
1473 "Routing GET for %s terminates after %u hops at %s\n",
1474 GNUNET_h2s (key),
1475 (unsigned int) hop_count,
1477 return GNUNET_NO;
1478 }
1479 if (GNUNET_OK !=
1481 &result_filter,
1482 &result_filter_size))
1483 {
1484 result_filter = NULL;
1485 result_filter_size = 0;
1486 }
1487 msize = xquery_size + result_filter_size;
1488 if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1489 {
1490 GNUNET_break (0);
1491 GNUNET_free (result_filter);
1492 GNUNET_free (targets);
1493 return GNUNET_NO;
1494 }
1495 /* update BF */
1496 for (unsigned int i = 0; i < target_count; i++)
1497 {
1498 struct PeerInfo *target = targets[i];
1499
1501 &target->phash);
1502 }
1503 /* forward request */
1504 for (unsigned int i = 0; i < target_count; i++)
1505 {
1506 struct PeerInfo *target = targets[i];
1507 struct PeerGetMessage *pgm;
1508 char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1509 char *rf;
1510
1512 "Routing GET for %s after %u hops to %s\n",
1513 GNUNET_h2s (key),
1514 (unsigned int) hop_count,
1515 GNUNET_i2s (&target->id));
1516 pgm = (struct PeerGetMessage *) buf;
1518 pgm->header.size = htons (sizeof (buf));
1519 pgm->type = htonl (type);
1520 pgm->options = htons (options);
1521 pgm->hop_count = htons (hop_count + 1);
1523 pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1526 pgm->bloomfilter,
1528 pgm->key = *key;
1529 rf = (char *) &pgm[1];
1530 GNUNET_memcpy (rf,
1531 result_filter,
1534 xquery,
1535 xquery_size);
1536 do_send (target,
1537 &pgm->header);
1538 }
1540 "# GET messages queued for transmission",
1541 target_count,
1542 GNUNET_NO);
1543 GNUNET_free (targets);
1544 GNUNET_free (result_filter);
1545 return (0 < target_count) ? GNUNET_OK : GNUNET_NO;
1546}
1547
1548
1549struct PeerInfo *
1551{
1553 target);
1554}
1555
1556
1558{
1559 struct PeerInfo *pi;
1560 struct PeerResultMessage *prm;
1563 void *block_data;
1566 bool trunc_peer_is_null;
1567 char *buf;
1568
1570 void *cb_cls;
1571};
1572
1573
1574static void
1576{
1577 if (reply->block_data)
1578 GNUNET_free (reply->block_data);
1579 if ((reply->bd.put_path_length > 0) && (reply->put_path))
1580 GNUNET_free (reply->put_path);
1581 if (reply->buf)
1582 GNUNET_free (reply->buf);
1583}
1584
1585
1586static void
1587safe_neighbours_callback (void *cls,
1589 bool success)
1590{
1591 GNUNET_break (success);
1592 if (cb)
1593 cb (cls);
1594}
1595
1596
1597static bool
1598cb_path_signed (void *cls,
1599 const struct GNUNET_CRYPTO_EddsaSignature *sig)
1600{
1601 struct GDS_NeighboursReply *reply = cls;
1602 struct PeerResultMessage *prm = reply->prm;
1603 struct GNUNET_DHT_PathElement *paths = reply->paths;
1604 unsigned int ppl = ntohs (prm->put_path_length);
1605 unsigned int get_path_length = ntohs (prm->get_path_length);
1606 void *tgt = &paths[get_path_length + ppl];
1607 void *data;
1608
1609 if (! sig)
1610 {
1612 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1613 return true;
1614 }
1615
1616 memcpy (tgt,
1617 sig,
1618 sizeof (*sig));
1619 data = tgt + sizeof (*sig);
1621 "Signing GET PATH %u/%u of %s => %s\n",
1622 ppl,
1623 get_path_length,
1624 GNUNET_h2s (&prm->key),
1625 GNUNET_B2S (sig));
1626#if SANITY_CHECKS > 1
1627 {
1628 const struct GNUNET_PeerIdentity *my_identity;
1629 struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
1630 const struct GNUNET_PeerIdentity *trunc_peer = reply->trunc_peer_is_null?
1631 NULL : &reply->trunc_peer_id;
1632
1634 GNUNET_assert (NULL != my_identity);
1635
1636 memcpy (xpaths,
1637 &paths[ppl],
1638 get_path_length * sizeof (struct GNUNET_DHT_PathElement));
1639 xpaths[get_path_length].sig = *sig;
1640 xpaths[get_path_length].pred = *my_identity;
1641 if (0 !=
1643 reply->bd.data_size,
1644 reply->bd.expiration_time,
1645 trunc_peer,
1646 paths,
1647 ppl,
1648 xpaths,
1649 get_path_length + 1,
1650 &reply->pi->id))
1651 {
1652 GNUNET_break (0);
1654 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1655 return true;
1656 }
1657 }
1658#endif
1660 reply->bd.data,
1661 reply->bd.data_size);
1662 do_send (reply->pi,
1663 &prm->header);
1665 safe_neighbours_callback (reply->cb_cls, reply->cb, true);
1666 return true;
1667}
1668
1669
1670void
1672 const struct GNUNET_DATACACHE_Block *bd,
1673 const struct GNUNET_HashCode *query_hash,
1674 unsigned int get_path_length,
1675 const struct GNUNET_DHT_PathElement *get_path,
1677 void *cb_cls)
1678{
1679 struct GNUNET_DHT_PathElement *paths;
1680 size_t msize;
1681 unsigned int ppl = bd->put_path_length;
1682 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1683 enum GNUNET_DHT_RouteOption ro = bd->ro;
1684 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1685 const struct GNUNET_PeerIdentity *trunc_peer
1686 = truncated
1687 ? &bd->trunc_peer
1688 : NULL;
1689 bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1690#if SANITY_CHECKS > 1
1691 const struct GNUNET_PeerIdentity *my_identity;
1692 unsigned int failure_offset;
1693
1695 GNUNET_assert (NULL != my_identity);
1696
1697 failure_offset
1699 bd->data_size,
1700 bd->expiration_time,
1701 trunc_peer,
1702 put_path,
1703 ppl,
1704 get_path,
1705 get_path_length,
1706 my_identity);
1707 if (0 != failure_offset)
1708 {
1709 GNUNET_assert (failure_offset <= ppl + get_path_length);
1710 GNUNET_break_op (0);
1711 if (failure_offset < ppl)
1712 {
1713 trunc_peer = &put_path[failure_offset - 1].pred;
1714 put_path += failure_offset;
1715 ppl -= failure_offset;
1716 truncated = true;
1718 }
1719 else
1720 {
1721 failure_offset -= ppl;
1722 if (0 == failure_offset)
1723 trunc_peer = &put_path[ppl - 1].pred;
1724 else
1725 trunc_peer = &get_path[failure_offset - 1].pred;
1726 ppl = 0;
1727 put_path = NULL;
1728 truncated = true;
1730 get_path += failure_offset;
1731 get_path_length -= failure_offset;
1732 }
1733 }
1734#endif
1735 msize = bd->data_size + sizeof (struct PeerResultMessage);
1736 if (msize > GNUNET_MAX_MESSAGE_SIZE)
1737 {
1738 GNUNET_break_op (0);
1739 safe_neighbours_callback (cb_cls, cb, false);
1740 return;
1741 }
1742 if (truncated)
1743 msize += sizeof (struct GNUNET_PeerIdentity);
1744 if (tracking)
1745 msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
1746 if (msize < bd->data_size)
1747 {
1748 GNUNET_break_op (0);
1749 safe_neighbours_callback (cb_cls, cb, false);
1750 return;
1751 }
1752 if ( (GNUNET_MAX_MESSAGE_SIZE - msize)
1753 / sizeof(struct GNUNET_DHT_PathElement)
1754 < (get_path_length + ppl) )
1755 {
1756 get_path_length = 0;
1757 ppl = 0;
1758 }
1759 if ( (get_path_length > UINT16_MAX) ||
1760 (ppl > UINT16_MAX) )
1761 {
1762 GNUNET_break (0);
1763 get_path_length = 0;
1764 ppl = 0;
1765 }
1766 msize += (get_path_length + ppl)
1767 * sizeof(struct GNUNET_DHT_PathElement);
1769 "Forwarding reply for key %s to peer %s\n",
1770 GNUNET_h2s (query_hash),
1771 GNUNET_i2s (&pi->id));
1773 "# RESULT messages queued for transmission",
1774 1,
1775 GNUNET_NO);
1776 {
1777 struct PeerResultMessage *prm;
1778 char buf[msize] GNUNET_ALIGN;
1779
1780 prm = (struct PeerResultMessage *) buf;
1782 prm->header.size = htons (sizeof (buf));
1783 prm->type = htonl ((uint32_t) bd->type);
1784 prm->reserved = htons (0);
1785 prm->options = htons ((uint16_t) ro);
1786 prm->put_path_length = htons ((uint16_t) ppl);
1787 prm->get_path_length = htons ((uint16_t) get_path_length);
1789 prm->key = *query_hash;
1790 if (truncated)
1791 {
1792 void *tgt = &prm[1];
1793
1794 GNUNET_memcpy (tgt,
1795 trunc_peer,
1796 sizeof (struct GNUNET_PeerIdentity));
1797 paths = (struct GNUNET_DHT_PathElement *)
1798 (tgt + sizeof (struct GNUNET_PeerIdentity));
1799 }
1800 else
1801 {
1802 paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1803 }
1804 if (NULL != put_path)
1805 {
1806 GNUNET_memcpy (paths,
1807 put_path,
1808 ppl * sizeof(struct GNUNET_DHT_PathElement));
1809 }
1810 else
1811 {
1812 GNUNET_assert (0 == ppl);
1813 }
1814 if (NULL != get_path)
1815 {
1816 GNUNET_memcpy (&paths[ppl],
1817 get_path,
1818 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1819 }
1820 else
1821 {
1822 GNUNET_assert (0 == get_path_length);
1823 }
1824 if (tracking)
1825 {
1826 struct GDS_NeighboursReply reply;
1827 const struct GNUNET_PeerIdentity *pred;
1828
1829 reply.pi = pi;
1830 GNUNET_memcpy (&reply.bd, bd, sizeof (reply.bd));
1831 reply.block_data = GNUNET_memdup (bd->data, bd->data_size);
1832 reply.put_path = GNUNET_memdup (bd->put_path,
1833 sizeof (struct GNUNET_DHT_PathElement)
1834 * bd->put_path_length);
1835
1836 reply.bd.data = reply.block_data;
1837 reply.bd.put_path = reply.put_path;
1838
1839 reply.buf = GNUNET_memdup (buf, msize);
1840 reply.prm = (struct PeerResultMessage*) reply.buf;
1841 reply.paths = (struct GNUNET_DHT_PathElement*) (reply.buf + (buf - (const
1842 char*)
1843 paths));
1844
1845 if (trunc_peer)
1846 {
1847 reply.trunc_peer_is_null = false;
1848 GNUNET_memcpy (&reply.trunc_peer_id, trunc_peer,
1849 sizeof (reply.trunc_peer_id));
1850 }
1851 else
1852 {
1853 reply.trunc_peer_is_null = true;
1854 }
1855
1856 reply.cb = cb;
1857 reply.cb_cls = cb_cls;
1858
1859 if (ppl + get_path_length > 0)
1860 pred = &paths[ppl + get_path_length - 1].pred;
1861 else if (truncated)
1862 pred = trunc_peer;
1863 else
1864 pred = NULL; /* we are first! */
1865 /* Note that the last signature in 'paths' was not initialized before,
1866 so this is crucial to avoid sending garbage. */
1868 bd->data_size,
1869 NULL,
1870 bd->expiration_time,
1871 pred,
1872 &pi->id,
1874 sizeof (reply),
1875 &reply);
1876 }
1877 else
1878 {
1879 void *data;
1880 data = &prm[1];
1882 bd->data,
1883 bd->data_size);
1884 do_send (pi,
1885 &prm->header);
1886 safe_neighbours_callback (cb_cls, cb, true);
1887 return;
1888 }
1889 }
1890}
1891
1892
1900static enum GNUNET_GenericReturnValue
1901check_dht_p2p_put (void *cls,
1902 const struct PeerPutMessage *put)
1903{
1904 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1905 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1906 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1907 uint16_t msize = ntohs (put->header.size);
1908 uint16_t putlen = ntohs (put->put_path_length);
1909 size_t xsize = (has_path
1910 ? sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1911 : 0)
1912 + (truncated
1913 ? sizeof (struct GNUNET_PeerIdentity)
1914 : 0);
1915 size_t var_meta_size
1916 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1917 + xsize;
1918
1919 (void) cls;
1920 if ( (msize <
1921 sizeof (struct PeerPutMessage) + var_meta_size) ||
1922 (putlen >
1923 (GNUNET_MAX_MESSAGE_SIZE
1924 - sizeof (struct PeerPutMessage)
1925 - xsize)
1926 / sizeof(struct GNUNET_DHT_PathElement)) )
1927 {
1928 GNUNET_break_op (0);
1929 return GNUNET_SYSERR;
1930 }
1931 if (GNUNET_BLOCK_TYPE_ANY == htonl (put->type))
1932 {
1933 GNUNET_break_op (0);
1934 return GNUNET_SYSERR;
1935 }
1936 return GNUNET_OK;
1937}
1938
1939
1940struct ForwardedDHTPut
1941{
1943
1945 void *data;
1946
1947 uint32_t hop_count;
1949};
1950
1951
1952static void
1953cb_forwarded_dht_p2p_put (void *cls,
1954 enum GNUNET_GenericReturnValue forwarded)
1955{
1956 struct ForwardedDHTPut *put = cls;
1957
1958 /* notify monitoring clients */
1959 put->block.ro |= ((GNUNET_OK == forwarded)
1961 : 0);
1963 put->hop_count,
1965
1966 if (put->put_path)
1967 GNUNET_free (put->put_path);
1968 GNUNET_free (put->data);
1969 GNUNET_free (put);
1970}
1971
1972
1979static void
1980handle_dht_p2p_put (void *cls,
1981 const struct PeerPutMessage *put)
1982{
1983 struct Target *t = cls;
1984 struct PeerInfo *peer = t->pi;
1985 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1986 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1987 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1988 uint16_t msize = ntohs (put->header.size);
1989 uint16_t putlen = ntohs (put->put_path_length);
1990 const struct GNUNET_PeerIdentity *trunc_peer
1991 = truncated
1992 ? (const struct GNUNET_PeerIdentity *) &put[1]
1993 : NULL;
1994 const struct GNUNET_DHT_PathElement *put_path
1995 = truncated
1996 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
1997 : (const struct GNUNET_DHT_PathElement *) &put[1];
1998 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
1999 = has_path
2000 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &put_path[putlen]
2001 : NULL;
2002 const char *data
2003 = has_path
2004 ? (const char *) &last_sig[1]
2005 : (const char *) &put_path[putlen];
2006 size_t var_meta_size
2007 = putlen * sizeof(struct GNUNET_DHT_PathElement)
2008 + (has_path ? sizeof (*last_sig) : 0)
2009 + (truncated ? sizeof (*trunc_peer) : 0);
2010 struct GNUNET_DATACACHE_Block bd = {
2011 .key = put->key,
2012 .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
2013 .type = ntohl (put->type),
2014 .ro = ro,
2015 .data_size = msize - sizeof(*put) - var_meta_size,
2016 .data = data
2017 };
2018
2019 if (NULL != trunc_peer)
2020 bd.trunc_peer = *trunc_peer;
2022 "PUT for `%s' from %s with RO (%s/%s)\n",
2023 GNUNET_h2s (&put->key),
2024 GNUNET_i2s (&peer->id),
2025 (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
2026 has_path ? "R" : "-");
2028 {
2030 "# Expired PUTs discarded",
2031 1,
2032 GNUNET_NO);
2033 return;
2034 }
2035 {
2036 /* Only call 'check_block' if that keeps our CPU load (from
2037 the cryptography) below 50% on average */
2038 static struct GNUNET_TIME_Relative avg_latency;
2039 static struct GNUNET_TIME_Absolute next_time;
2040
2041 if (GNUNET_TIME_absolute_is_past (next_time))
2042 {
2043 struct GNUNET_TIME_Absolute now
2045 struct GNUNET_TIME_Relative latency;
2047
2048 if (GNUNET_NO ==
2050 bd.type,
2051 bd.data,
2052 bd.data_size))
2053 {
2054 GNUNET_break_op (0);
2055 return;
2056 }
2057 latency = GNUNET_TIME_absolute_get_duration (now);
2058 /* Use *moving average* to estimate check_block latency */
2059 avg_latency
2062 GNUNET_TIME_relative_multiply (avg_latency,
2063 7),
2064 latency),
2065 8);
2066 /* average delay = 50% of avg_latency => 50% CPU load from crypto (at most) */
2069 avg_latency.rel_value_us > 0
2070 ? avg_latency.rel_value_us
2071 : 1LLU);
2073 }
2074 }
2075 if (! has_path)
2076 putlen = 0;
2078 "# P2P PUT requests received",
2079 1,
2080 GNUNET_NO);
2082 "# P2P PUT bytes received",
2083 msize,
2084 GNUNET_NO);
2085 {
2086 struct GNUNET_HashCode test_key;
2088
2090 bd.type,
2091 bd.data,
2092 bd.data_size,
2093 &test_key);
2094 switch (ret)
2095 {
2096 case GNUNET_YES:
2097 if (0 != GNUNET_memcmp (&test_key,
2098 &bd.key))
2099 {
2100 GNUNET_break_op (0);
2101 return;
2102 }
2103 break;
2104 case GNUNET_NO:
2105 /* cannot verify, good luck */
2106 break;
2107 case GNUNET_SYSERR:
2108 /* block type not supported, good luck */
2109 break;
2110 }
2111 }
2112
2113 {
2115 struct GNUNET_DHT_PathElement pp[putlen + 1];
2116
2122 &peer->phash));
2123 /* extend 'put path' by sender */
2124 bd.put_path = pp;
2125 bd.put_path_length = putlen + 1;
2126 if (has_path)
2127 {
2128 unsigned int failure_offset;
2129
2130 GNUNET_memcpy (pp,
2131 put_path,
2132 putlen * sizeof(struct GNUNET_DHT_PathElement));
2133 pp[putlen].pred = peer->id;
2134 pp[putlen].sig = *last_sig;
2135#if SANITY_CHECKS
2136 {
2137 const struct GNUNET_PeerIdentity *my_identity;
2139 GNUNET_assert (NULL != my_identity);
2140 /* TODO: might want to eventually implement probabilistic
2141 load-based path verification, but for now it is all or nothing */
2142 failure_offset
2144 bd.data_size,
2145 bd.expiration_time,
2146 trunc_peer,
2147 pp,
2148 putlen + 1,
2149 NULL, 0, /* get_path */
2150 my_identity);
2151 }
2152#else
2153 failure_offset = 0;
2154#endif
2155 if (0 != failure_offset)
2156 {
2157 GNUNET_break_op (0);
2159 "Recorded put path invalid at offset %u, truncating\n",
2160 failure_offset);
2161 GNUNET_assert (failure_offset <= putlen + 1);
2162 bd.put_path = &pp[failure_offset];
2163 bd.put_path_length = (putlen + 1) - failure_offset;
2165 bd.trunc_peer = pp[failure_offset - 1].pred;
2166 }
2167 }
2168 else
2169 {
2170 bd.put_path_length = 0;
2171 }
2172
2173 /* give to local clients */
2175 &bd.key,
2176 0, NULL /* get path */));
2177
2178 /* store locally */
2179 if ( (0 != (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2180 (GDS_am_closest_peer (&put->key,
2181 bf)) )
2183
2184 {
2186 GNUNET_memcpy (&forward->block, &bd, sizeof (bd));
2187
2188 if (bd.put_path_length > 0)
2189 {
2190 forward->put_path = GNUNET_memdup (
2191 bd.put_path,
2192 sizeof (struct GNUNET_DHT_PathElement) * bd.put_path_length);
2193 forward->block.put_path = forward->put_path;
2194 }
2195
2196 forward->data = GNUNET_memdup (bd.data, bd.data_size);
2197 forward->block.data = forward->data;
2198
2199 forward->desired_replication_level = ntohs (put->desired_replication_level
2200 );
2201 forward->hop_count = ntohs (put->hop_count);
2202
2203 /* route to other peers */
2205 forward->desired_replication_level,
2206 forward->hop_count,
2207 bf,
2209 forward);
2210 }
2212 }
2213}
2214
2215
2216struct BlockCls
2217{
2218 struct PeerInfo *pi;
2219 const struct GNUNET_HashCode *query_hash;
2220 struct GNUNET_BLOCK_Group *bg;
2221};
2222
2223
2232static void
2233handle_find_my_hello (struct PeerInfo *pi,
2234 const struct GNUNET_HashCode *query_hash,
2235 struct GNUNET_BLOCK_Group *bg,
2237 void *cb_cls)
2238{
2239 const struct GNUNET_HashCode *my_identity_hash;
2240 const struct GNUNET_PeerIdentity *my_identity;
2241 struct GNUNET_TIME_Absolute block_expiration;
2242 size_t block_size;
2243 void *block;
2244
2245 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
2248 "Handle finding my own HELLO %s\n",
2249 GNUNET_h2s (my_identity_hash));
2250 if (NULL == GDS_my_hello)
2251 {
2253 "# FIND PEER requests ignored due to lack of HELLO",
2254 1,
2255 GNUNET_NO);
2256 if (cb)
2257 cb (cb_cls);
2258 return;
2259 }
2260
2263 &block,
2264 &block_size,
2265 &block_expiration))
2266 {
2267 if (cb)
2268 cb (cb_cls);
2269 return;
2270 }
2271
2275 bg,
2276 my_identity_hash,
2277 NULL, 0,
2278 block,
2279 block_size))
2280 {
2281 struct GNUNET_DATACACHE_Block bd = {
2283 .expiration_time
2286 .key = *my_identity_hash,
2287 .data = block,
2288 .data_size = block_size
2289 };
2290
2292 &bd,
2293 query_hash,
2294 0, NULL /* get path */,
2295 cb,
2296 cb_cls);
2297 }
2298 else
2299 {
2301 "# FIND PEER requests ignored due to Bloomfilter",
2302 1,
2303 GNUNET_NO);
2304 if (cb)
2305 cb (cb_cls);
2306 }
2307
2308 GNUNET_free (block);
2309}
2310
2311
2320static void
2322 const struct GNUNET_HashCode *query_hash,
2323 struct GNUNET_BLOCK_Group *bg,
2325 void *cb_cls)
2326{
2327 /* Force non-random selection by hop count */
2328 struct PeerInfo *peer;
2329
2330 peer = select_peer (query_hash,
2331 NULL,
2332 GDS_NSE_get () + 1);
2334 "Handle finding local HELLO %s\n",
2335 GNUNET_h2s (&peer->phash));
2336 if ( (NULL != peer->hello) &&
2342 bg,
2343 &peer->phash,
2344 NULL, 0, /* xquery */
2345 peer->hello,
2346 peer->hello_size)) )
2347 {
2348 struct GNUNET_DATACACHE_Block bd = {
2350 .expiration_time = peer->hello_expiration,
2351 .key = peer->phash,
2352 .data = peer->hello,
2353 .data_size = peer->hello_size
2354 };
2355
2357 &bd,
2358 query_hash,
2359 0, NULL /* get path */,
2360 cb,
2361 cb_cls);
2362 }
2363 else if (cb)
2364 cb (cb_cls);
2365}
2366
2367
2369{
2370 struct PeerInfo *peer;
2372 void *cb_cls;
2373};
2374
2375
2382static void
2383handle_local_result (void *cls,
2384 const struct GNUNET_DATACACHE_Block *bd)
2385{
2386 struct HandleCallbackLocal *local = cls;
2387
2389 bd,
2390 &bd->key,
2391 0, NULL /* get path */,
2392 local->cb,
2393 local->cb_cls);
2394}
2395
2396
2404static enum GNUNET_GenericReturnValue
2405check_dht_p2p_get (void *cls,
2406 const struct PeerGetMessage *get)
2407{
2408 uint16_t msize = ntohs (get->header.size);
2409 uint16_t result_filter_size = ntohs (get->result_filter_size);
2410
2411 (void) cls;
2412 if (msize < sizeof(*get) + result_filter_size)
2413 {
2414 GNUNET_break_op (0);
2415 return GNUNET_SYSERR;
2416 }
2417 return GNUNET_OK;
2418}
2419
2420
2421struct HandleCallbackGet
2422{
2423 struct Target *t;
2424 struct PeerGetMessage *get;
2426 struct GNUNET_BLOCK_Group *bg;
2428};
2429
2430
2431static void
2433{
2434 struct HandleCallbackGet *handle = cls;
2435 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2436 enum GNUNET_BLOCK_Type type = ntohl (handle->get->type);
2437 const void *result_filter = (const void *) &handle->get[1];
2438 uint16_t msize = ntohs (handle->get->header.size);
2439 uint16_t result_filter_size = ntohs (handle->get->result_filter_size);
2440 const void *xquery = result_filter + result_filter_size;
2441 size_t xquery_size = msize - sizeof (*handle->get) - result_filter_size;
2442
2443 /* remember request for routing replies
2444 TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2445 */
2446 GDS_ROUTING_add (&handle->t->pi->id,
2447 type,
2448 handle->bg, /* bg now owned by routing, but valid at least until end of this function! */
2449 options,
2450 &handle->get->key,
2451 xquery,
2452 xquery_size);
2453
2454 /* P2P forwarding */
2455 {
2456 bool forwarded = false;
2457 uint16_t desired_replication_level = ntohs (
2458 handle->get->desired_replication_level);
2459 uint16_t hop_count = ntohs (handle->get->hop_count);
2460
2462 forwarded = (GNUNET_OK ==
2464 options,
2465 desired_replication_level,
2466 hop_count,
2467 &handle->get->key,
2468 xquery,
2469 xquery_size,
2470 handle->bg,
2471 handle->peer_bf));
2473 options
2474 | (forwarded
2475 ? 0
2477 type,
2478 hop_count,
2479 desired_replication_level,
2480 &handle->get->key);
2481 }
2482 /* clean up; note that 'bg' is owned by routing now! */
2484
2485 GNUNET_free (handle->get);
2487}
2488
2489
2490static void
2492{
2493 struct HandleCallbackGet *handle = cls;
2494 enum GNUNET_BLOCK_Type type = ntohl (handle->get->type);
2495
2497 "Handle getting local HELLO %s of type %u\n",
2498 GNUNET_h2s (&handle->get->key),
2499 type);
2500
2502 {
2503 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2504 const void *result_filter = (const void *) &handle->get[1];
2505 uint16_t msize = ntohs (handle->get->header.size);
2506 uint16_t result_filter_size = ntohs (handle->get->result_filter_size);
2507 const void *xquery = result_filter + result_filter_size;
2508 size_t xquery_size = msize - sizeof (*handle->get) - result_filter_size;
2509 struct HandleCallbackLocal local;
2510 local.peer = handle->t->pi;
2512 local.cb_cls = handle;
2513
2515 handle->eval = GDS_DATACACHE_get_closest (&handle->get->key,
2516 type,
2517 xquery,
2518 xquery_size,
2519 handle->bg,
2521 &local);
2522 else
2523 handle->eval = GDS_DATACACHE_handle_get (&handle->get->key,
2524 type,
2525 xquery,
2526 xquery_size,
2527 handle->bg,
2529 &local);
2530 }
2531 else
2533}
2534
2535
2536static void
2538{
2539 struct HandleCallbackGet *handle = cls;
2540 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2541
2544 &handle->get->key,
2545 handle->bg,
2547 handle);
2548 else
2550}
2551
2552
2559static void
2560handle_dht_p2p_get (void *cls,
2561 const struct PeerGetMessage *get)
2562{
2563 struct Target *t = cls;
2564 struct PeerInfo *peer = t->pi;
2565 uint16_t msize = ntohs (get->header.size);
2566 uint16_t result_filter_size = ntohs (get->result_filter_size);
2567 uint16_t hop_count = ntohs (get->hop_count);
2568 enum GNUNET_BLOCK_Type type = ntohl (get->type);
2569 enum GNUNET_DHT_RouteOption options = ntohs (get->options);
2570 const void *result_filter = (const void *) &get[1];
2571 const void *xquery = result_filter + result_filter_size;
2572 size_t xquery_size = msize - sizeof (*get) - result_filter_size;
2573
2574 /* parse and validate message */
2576 "# P2P GET requests received",
2577 1,
2578 GNUNET_NO);
2580 "# P2P GET bytes received",
2581 msize,
2582 GNUNET_NO);
2583 if (GNUNET_NO ==
2585 type,
2586 &get->key,
2587 xquery,
2588 xquery_size))
2589 {
2590 /* request invalid */
2591 GNUNET_break_op (0);
2592 return;
2593 }
2594
2595 {
2596 const struct GNUNET_PeerIdentity *my_identity;
2597 struct HandleCallbackGet *handle;
2598
2600 handle->t = t;
2601 handle->get = GNUNET_memdup (get, msize);
2603
2605 GNUNET_assert (NULL != my_identity);
2606
2607 handle->peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2612 &peer->phash));
2614 type,
2615 result_filter,
2616 result_filter_size,
2617 "filter-size",
2618 result_filter_size,
2619 NULL);
2621 "GET for %s at %s after %u hops\n",
2622 GNUNET_h2s (&get->key),
2624 (unsigned int) hop_count);
2625 /* local lookup (this may update the bg) */
2627 (GDS_am_closest_peer (&get->key,
2628 handle->peer_bf)) )
2629 {
2632 {
2634 "# P2P HELLO lookup requests processed",
2635 1,
2636 GNUNET_NO);
2638 &get->key,
2639 handle->bg,
2641 handle);
2642 }
2643 else
2645 }
2646 else
2647 {
2649 "# P2P GET requests ONLY routed",
2650 1,
2651 GNUNET_NO);
2653 }
2654 }
2655}
2656
2657
2666static void
2668 const struct GNUNET_HashCode *query_hash,
2669 unsigned int get_path_length,
2670 const struct GNUNET_DHT_PathElement *get_path)
2671{
2672 /* forward to local clients */
2674 "Forwarding reply to local clients\n");
2675 if (! GDS_CLIENTS_handle_reply (bd,
2676 query_hash,
2677 get_path_length,
2678 get_path))
2679 {
2680 GNUNET_break (0);
2681 return;
2682 }
2684 get_path,
2685 get_path_length);
2687 {
2688 struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2689 + bd->put_path_length)];
2690 struct GNUNET_DATACACHE_Block bdx = *bd;
2691
2692 if (NULL != bd->put_path)
2693 GNUNET_memcpy (xput_path,
2694 bd->put_path,
2695 bd->put_path_length * sizeof(struct
2697 GNUNET_memcpy (&xput_path[bd->put_path_length],
2698 get_path,
2699 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2700 bdx.put_path = xput_path;
2701 bdx.put_path_length += get_path_length;
2703 }
2704 /* forward to other peers */
2706 query_hash,
2707 get_path_length,
2708 get_path);
2709}
2710
2711
2719static enum GNUNET_GenericReturnValue
2720check_dht_p2p_result (void *cls,
2721 const struct PeerResultMessage *prm)
2722{
2723 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2724 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2725 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2726 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2727
2728 uint16_t get_path_length = ntohs (prm->get_path_length);
2729 uint16_t put_path_length = ntohs (prm->put_path_length);
2730 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2731 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2732
2733 (void) cls;
2734 if ( (msize < vsize) ||
2735 (msize - vsize <
2736 (get_path_length + put_path_length)
2737 * sizeof(struct GNUNET_DHT_PathElement)) ||
2738 (get_path_length >
2739 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2740 (put_path_length >
2741 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2742 {
2743 GNUNET_break_op (0);
2744 return GNUNET_SYSERR;
2745 }
2746 return GNUNET_OK;
2747}
2748
2749
2756static void
2757handle_dht_p2p_result (void *cls,
2758 const struct PeerResultMessage *prm)
2759{
2760 struct Target *t = cls;
2761 struct PeerInfo *peer = t->pi;
2762 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2763 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2764 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2765 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2766 uint16_t get_path_length = ntohs (prm->get_path_length);
2767 uint16_t put_path_length = ntohs (prm->put_path_length);
2768 const struct GNUNET_PeerIdentity *trunc_peer
2769 = truncated
2770 ? (const struct GNUNET_PeerIdentity *) &prm[1]
2771 : NULL;
2772 const struct GNUNET_DHT_PathElement *put_path
2773 = truncated
2774 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2775 : (const struct GNUNET_DHT_PathElement *) &prm[1];
2776 const struct GNUNET_DHT_PathElement *get_path
2777 = &put_path[put_path_length];
2778 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2779 = tracked
2780 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &get_path[get_path_length]
2781 : NULL;
2782 const void *data
2783 = tracked
2784 ? (const void *) &last_sig[1]
2785 : (const void *) &get_path[get_path_length];
2786 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2787 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2788 struct GNUNET_DATACACHE_Block bd = {
2790 .put_path = put_path,
2791 .put_path_length = put_path_length,
2792 .key = prm->key,
2793 .type = ntohl (prm->type),
2794 .ro = ro,
2795 .data = data,
2796 .data_size = msize - vsize - (get_path_length + put_path_length)
2797 * sizeof(struct GNUNET_DHT_PathElement)
2798 };
2799
2800 /* parse and validate message */
2802 {
2804 "# Expired results discarded",
2805 1,
2806 GNUNET_NO);
2807 return;
2808 }
2809 if (GNUNET_OK !=
2811 bd.type,
2812 bd.data,
2813 bd.data_size))
2814 {
2815 GNUNET_break_op (0);
2816 return;
2817 }
2819 "# P2P RESULTS received",
2820 1,
2821 GNUNET_NO);
2823 "# P2P RESULT bytes received",
2824 msize,
2825 GNUNET_NO);
2826 {
2828
2830 bd.type,
2831 bd.data,
2832 bd.data_size,
2833 &bd.key);
2834 if (GNUNET_NO == ret)
2835 bd.key = prm->key;
2836 }
2837
2838 /* if we got a HELLO, consider it for our own routing table */
2839 hello_check (&bd);
2840
2841 /* Need to append 'peer' to 'get_path' */
2842 if (tracked)
2843 {
2844 struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2845 struct GNUNET_DHT_PathElement *gp = xget_path;
2846 unsigned int failure_offset;
2847
2848 GNUNET_memcpy (xget_path,
2849 get_path,
2850 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2851 xget_path[get_path_length].pred = peer->id;
2852 /* use memcpy(), as last_sig may not be aligned */
2853 memcpy (&xget_path[get_path_length].sig,
2854 last_sig,
2855 sizeof (*last_sig));
2856#if SANITY_CHECKS
2857 {
2858 const struct GNUNET_PeerIdentity *my_identity;
2860 GNUNET_assert (NULL != my_identity);
2861 /* TODO: might want to eventually implement probabilistic
2862 load-based path verification, but for now it is all or nothing */
2863 failure_offset
2865 bd.data_size,
2866 bd.expiration_time,
2867 trunc_peer,
2868 put_path,
2869 put_path_length,
2870 gp,
2871 get_path_length + 1,
2872 my_identity);
2873 }
2874#else
2875 failure_offset = 0;
2876#endif
2877 if (0 != failure_offset)
2878 {
2880 "Recorded path invalid at offset %u, truncating\n",
2881 failure_offset);
2882 GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length
2883 + 1);
2884 if (failure_offset < bd.put_path_length)
2885 {
2886 /* failure on put path */
2887 trunc_peer = &bd.put_path[failure_offset - 1].pred;
2889 bd.put_path = &bd.put_path[failure_offset];
2890 bd.put_path_length -= failure_offset;
2891 truncated = true;
2892 }
2893 else
2894 {
2895 /* failure on get path */
2896 failure_offset -= bd.put_path_length;
2897 if (0 == failure_offset)
2898 trunc_peer = &bd.put_path[bd.put_path_length - 1].pred;
2899 else
2900 trunc_peer = &gp[failure_offset - 1].pred;
2901 get_path_length -= failure_offset;
2902 gp = &gp[failure_offset];
2903 bd.put_path_length = 0;
2904 bd.put_path = NULL;
2906 truncated = true;
2907 }
2908 }
2910 "Extending GET path of length %u with %s\n",
2911 get_path_length,
2912 GNUNET_i2s (&peer->id));
2913 if (truncated)
2914 {
2915 GNUNET_assert (NULL != trunc_peer);
2916 bd.trunc_peer = *trunc_peer;
2917 }
2919 &prm->key,
2920 get_path_length + 1,
2921 gp);
2922 }
2923 else
2924 {
2925 if (truncated)
2926 {
2927 GNUNET_assert (NULL != trunc_peer);
2928 bd.trunc_peer = *trunc_peer;
2929 }
2931 &prm->key,
2932 0,
2933 NULL);
2934 }
2935}
2936
2937
2945static enum GNUNET_GenericReturnValue
2946check_dht_p2p_hello (void *cls,
2947 const struct GNUNET_MessageHeader *hello)
2948{
2949 struct Target *t = cls;
2950 struct PeerInfo *peer = t->pi;
2952 size_t hellob_size;
2953 void *hellob;
2955
2957 &peer->id,
2958 &hellob,
2959 &hellob_size,
2960 &expiration);
2961 GNUNET_free (hellob);
2962 return ret;
2963}
2964
2965
2972static void
2973handle_dht_p2p_hello (void *cls,
2974 const struct GNUNET_MessageHeader *hello)
2975{
2976 struct Target *t = cls;
2977 struct PeerInfo *peer = t->pi;
2978
2979 GNUNET_free (peer->hello);
2980 peer->hello_size = 0;
2983 &peer->id,
2984 &peer->hello,
2985 &peer->hello_size,
2986 &peer->hello_expiration));
2987}
2988
2989
2990void
2991GDS_u_receive (void *cls,
2992 void **tctx,
2993 void **sctx,
2994 const void *message,
2995 size_t message_size)
2996{
2997 struct Target *t = *tctx;
2998 struct GNUNET_MQ_MessageHandler core_handlers[] = {
2999 GNUNET_MQ_hd_var_size (dht_p2p_get,
3001 struct PeerGetMessage,
3002 t),
3003 GNUNET_MQ_hd_var_size (dht_p2p_put,
3005 struct PeerPutMessage,
3006 t),
3007 GNUNET_MQ_hd_var_size (dht_p2p_result,
3009 struct PeerResultMessage,
3010 t),
3011 GNUNET_MQ_hd_var_size (dht_p2p_hello,
3013 struct GNUNET_MessageHeader,
3014 t),
3016 };
3017 const struct GNUNET_MessageHeader *mh = message;
3018
3019 (void) cls; /* the 'struct GDS_Underlay' */
3020 (void) sctx; /* our receiver address */
3021 if (NULL == t)
3022 {
3023 /* Received message claiming to originate from myself?
3024 Ignore! */
3025 GNUNET_break_op (0);
3026 return;
3027 }
3028 if (message_size < sizeof (*mh))
3029 {
3030 GNUNET_break_op (0);
3031 return;
3032 }
3033 if (message_size != ntohs (mh->size))
3034 {
3035 GNUNET_break_op (0);
3036 return;
3037 }
3039 "Handling message of type %u from peer %s\n",
3040 ntohs (mh->type),
3041 GNUNET_i2s (&t->pi->id));
3042 if (GNUNET_OK !=
3043 GNUNET_MQ_handle_message (core_handlers,
3044 mh))
3045 {
3046 GNUNET_break_op (0);
3047 return;
3048 }
3049}
3050
3051
3059void
3060GDS_try_connect (void *cls,
3061 const struct GNUNET_PeerIdentity *pid,
3062 const char *uri)
3063{
3064 const struct GNUNET_PeerIdentity *my_identity;
3065 struct GNUNET_HashCode phash;
3066 int peer_bucket;
3067 struct PeerBucket *bucket;
3068 (void) cls;
3069
3071 GNUNET_assert (NULL != my_identity);
3072
3073 if (0 == GNUNET_memcmp (my_identity, pid))
3074 {
3076 "Got a HELLO for my own PID, ignoring it\n");
3077 return; /* that's us! */
3078 }
3080 sizeof(*pid),
3081 &phash);
3082 peer_bucket = find_bucket (&phash);
3083 GNUNET_assert ( (peer_bucket >= 0) &&
3084 ((unsigned int) peer_bucket < MAX_BUCKETS));
3085 bucket = &k_buckets[peer_bucket];
3086 for (struct PeerInfo *pi = bucket->head;
3087 NULL != pi;
3088 pi = pi->next)
3089 if (0 ==
3090 GNUNET_memcmp (&pi->id,
3091 pid))
3092 {
3093 /* already connected */
3095 uri);
3096 return;
3097 }
3098 if (bucket->peers_size >= bucket_size)
3099 return; /* do not care */
3101 "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
3102 GNUNET_i2s (pid),
3103 uri,
3104 peer_bucket,
3105 bucket->peers_size,
3106 bucket_size);
3107 /* new peer that we like! */
3109 uri);
3110}
3111
3112
3118void
3120{
3121 for (unsigned int bc = 0; bc<closest_bucket; bc++)
3122 {
3123 struct PeerBucket *bucket = &k_buckets[bc];
3124 unsigned int count = 0;
3125
3126 for (struct PeerInfo *pos = bucket->head;
3127 NULL != pos;
3128 pos = pos->next)
3129 {
3130 if (count >= bucket_size)
3131 break; /* we only consider first #bucket_size entries per bucket */
3132 count++;
3133 do_send (pos,
3134 msg);
3135 }
3136 }
3137}
3138
3139
3142{
3143
3144 unsigned long long temp_config_num;
3145
3148 "DHT",
3149 "DISABLE_TRY_CONNECT");
3150 if (GNUNET_OK ==
3152 "DHT",
3153 "bucket_size",
3154 &temp_config_num))
3155 bucket_size = (unsigned int) temp_config_num;
3158 "DHT",
3159 "CACHE_RESULTS");
3161 GNUNET_YES);
3162 return GNUNET_OK;
3163}
3164
3165
3166void
3168{
3169 if (NULL == all_connected_peers)
3170 return;
3171 GNUNET_assert (0 ==
3174 all_connected_peers = NULL;
3175 GNUNET_assert (NULL == find_peer_task);
3176}
3177
3178
3179const struct GNUNET_PeerIdentity *
3181{
3183}
3184
3185
3186/* 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(enum GNUNET_CRYPTO_Quality mode, uint64_t max)
Generate a random unsigned 64-bit value.
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random value.
@ GNUNET_CRYPTO_QUALITY_WEAK
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
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:1355
@ 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:41
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 =
559 1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
563 GNUNET_SCHEDULER_add_delayed (next_send_time,
565 NULL);
566 if (done_early)
567 return;
568 }
569
570 /* actually send 'find peer' request */
571 {
572 const struct GNUNET_HashCode *my_identity_hash;
573 struct GNUNET_BLOCK_Group *bg;
574 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
575
576 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
577 GNUNET_assert (NULL != my_identity_hash);
578
581 NULL,
582 0,
583 "seen-set-size",
586 NULL);
589 bg);
590 peer_bf
594 if (GNUNET_OK !=
599 0, /* hop count */
600 my_identity_hash,
601 NULL, 0, /* xquery */
602 bg,
603 peer_bf))
604 {
606 "# Failed to initiate FIND PEER lookup",
607 1,
608 GNUNET_NO);
609 }
610 else
611 {
613 "# FIND PEER messages initiated",
614 1,
615 GNUNET_NO);
616 }
619 }
620}

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

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

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

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

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

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

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

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

References GDS_NSE_get(), GDS_stats, GNUNET_CRYPTO_QUALITY_WEAK, 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 869 of file gnunet-service-dht_neighbours.c.

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

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

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

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

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

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

1220{
1221 struct GNUNET_HELLO_Parser *b;
1222
1224 return;
1225
1227 bd->data_size);
1229 {
1232 NULL);
1233 }
1235}

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

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

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

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

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

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

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

1552{
1554 target);
1555}

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

1577{
1578 if (reply->block_data)
1579 GNUNET_free (reply->block_data);
1580 if ((reply->bd.put_path_length > 0) && (reply->put_path))
1581 GNUNET_free (reply->put_path);
1582 if (reply->buf)
1583 GNUNET_free (reply->buf);
1584}

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

1591{
1592 GNUNET_break (success);
1593 if (cb)
1594 cb (cls);
1595}

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

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

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

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

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

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

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

1956{
1957 struct ForwardedDHTPut *put = cls;
1958
1959 /* notify monitoring clients */
1960 put->block.ro |= ((GNUNET_OK == forwarded)
1962 : 0);
1964 put->hop_count,
1966
1967 if (put->put_path)
1968 GNUNET_free (put->put_path);
1969 GNUNET_free (put->data);
1970 GNUNET_free (put);
1971}

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

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

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

2239{
2240 const struct GNUNET_HashCode *my_identity_hash;
2241 const struct GNUNET_PeerIdentity *my_identity;
2242 struct GNUNET_TIME_Absolute block_expiration;
2243 size_t block_size;
2244 void *block;
2245
2246 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
2249 "Handle finding my own HELLO %s\n",
2250 GNUNET_h2s (my_identity_hash));
2251 if (NULL == GDS_my_hello)
2252 {
2254 "# FIND PEER requests ignored due to lack of HELLO",
2255 1,
2256 GNUNET_NO);
2257 if (cb)
2258 cb (cb_cls);
2259 return;
2260 }
2261
2264 &block,
2265 &block_size,
2266 &block_expiration))
2267 {
2268 if (cb)
2269 cb (cb_cls);
2270 return;
2271 }
2272
2276 bg,
2277 my_identity_hash,
2278 NULL, 0,
2279 block,
2280 block_size))
2281 {
2282 struct GNUNET_DATACACHE_Block bd = {
2284 .expiration_time
2287 .key = *my_identity_hash,
2288 .data = block,
2289 .data_size = block_size
2290 };
2291
2293 &bd,
2294 query_hash,
2295 0, NULL /* get path */,
2296 cb,
2297 cb_cls);
2298 }
2299 else
2300 {
2302 "# FIND PEER requests ignored due to Bloomfilter",
2303 1,
2304 GNUNET_NO);
2305 if (cb)
2306 cb (cb_cls);
2307 }
2308
2309 GNUNET_free (block);
2310}

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

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

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

2386{
2387 struct HandleCallbackLocal *local = cls;
2388
2390 bd,
2391 &bd->key,
2392 0, NULL /* get path */,
2393 local->cb,
2394 local->cb_cls);
2395}

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

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

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

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

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

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

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

2539{
2540 struct HandleCallbackGet *handle = cls;
2541 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2542
2545 &handle->get->key,
2546 handle->bg,
2548 handle);
2549 else
2551}

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

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

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

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

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

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

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

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

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

2949{
2950 struct Target *t = cls;
2951 struct PeerInfo *peer = t->pi;
2953 size_t hellob_size;
2954 void *hellob;
2956
2958 &peer->id,
2959 &hellob,
2960 &hellob_size,
2961 &expiration);
2962 GNUNET_free (hellob);
2963 return ret;
2964}

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

2976{
2977 struct Target *t = cls;
2978 struct PeerInfo *peer = t->pi;
2979
2980 GNUNET_free (peer->hello);
2981 peer->hello_size = 0;
2984 &peer->id,
2985 &peer->hello,
2986 &peer->hello_size,
2987 &peer->hello_expiration));
2988}

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

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

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

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

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

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

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

3143{
3144
3145 unsigned long long temp_config_num;
3146
3149 "DHT",
3150 "DISABLE_TRY_CONNECT");
3151 if (GNUNET_OK ==
3153 "DHT",
3154 "bucket_size",
3155 &temp_config_num))
3156 bucket_size = (unsigned int) temp_config_num;
3159 "DHT",
3160 "CACHE_RESULTS");
3162 GNUNET_YES);
3163 return GNUNET_OK;
3164}

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

3182{
3184}

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().