GNUnet debian-0.24.3-29-g453fda2cf
 
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  BlockCls
 

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.
 
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_handle_put (const struct GNUNET_DATACACHE_Block *bd, uint16_t desired_replication_level, uint16_t hop_count, struct GNUNET_CONTAINER_BloomFilter *bf)
 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.
 
bool 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)
 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 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)
 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)
 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 handle_dht_p2p_get (void *cls, const struct PeerGetMessage *get)
 Core handler for p2p get requests.
 
static bool 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.
 
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 38 of file gnunet-service-dht_neighbours.c.

107{
111 struct GNUNET_MessageHeader header;
112
116 uint32_t type GNUNET_PACKED;
117
121 uint16_t reserved GNUNET_PACKED;
122
126 uint16_t options GNUNET_PACKED;
127
131 uint16_t put_path_length GNUNET_PACKED;
132
136 uint16_t get_path_length GNUNET_PACKED;
137
141 struct GNUNET_TIME_AbsoluteNBO expiration_time;
142
146 struct GNUNET_HashCode key;
147
148 /* trunc_peer (if truncated) */
149
150 /* put path (if tracked) */
151
152 /* get path (if tracked) */
153
154 /* sender_sig (if path tracking is on) */
155
156 /* Payload */
157};
158
159
163struct PeerGetMessage
164{
169
173 uint32_t type GNUNET_PACKED;
174
178 uint16_t options GNUNET_PACKED;
179
183 uint16_t hop_count GNUNET_PACKED;
184
189
194
199
203 struct GNUNET_HashCode key;
204
205 /* result bloomfilter */
206
207 /* xquery */
208
209};
211
212
216struct PeerInfo;
217
218
222struct Target
223{
227 struct Target *next;
228
232 struct Target *prev;
233
238
242 struct GDS_Underlay *u;
243
247 struct PeerInfo *pi;
248
253
257 unsigned int load;
258
263 bool dropped;
264
265};
266
267
271struct PeerInfo
272{
276 struct GNUNET_PeerIdentity id;
277
281 struct GNUNET_HashCode phash;
282
287
291 struct PeerInfo *next;
292
296 struct PeerInfo *prev;
297
301 struct Target *t_head;
302
306 struct Target *t_tail;
307
311 void *hello;
312
316 size_t hello_size;
317
321 int peer_bucket;
322};
323
324
328struct PeerBucket
329{
333 struct PeerInfo *head;
334
338 struct PeerInfo *tail;
339
343 unsigned int peers_size;
344};
345
346
350static int cache_results;
351
355static unsigned int closest_bucket;
356
361static unsigned int newly_found_peers;
362
366static int disable_try_connect;
367
371static struct PeerBucket k_buckets[MAX_BUCKETS];
372
378
382static unsigned int bucket_size = DEFAULT_BUCKET_SIZE;
383
388
389
397static void
398send_done_cb (void *cls)
399{
400 struct Target *t = cls;
401 struct PeerInfo *pi = t->pi; /* NULL if t->dropped! */
402
403 GNUNET_assert (t->load > 0);
404 t->load--;
405 if (0 < t->load)
406 return;
407 if (t->dropped)
408 {
409 GNUNET_free (t);
410 return;
411 }
412 /* move target back to the front */
414 pi->t_tail,
415 t);
417 pi->t_tail,
418 t);
419}
420
421
428static void
429do_send (struct PeerInfo *pi,
430 const struct GNUNET_MessageHeader *msg)
431{
432 struct Target *t;
433
434 for (t = pi->t_head;
435 NULL != t;
436 t = t->next)
437 if (t->load < MAXIMUM_PENDING_PER_PEER)
438 break;
439 if (NULL == t)
440 {
441 /* all targets busy, drop message */
443 "# messages dropped (underlays busy)",
444 1,
445 GNUNET_NO);
446 return;
447 }
448 t->load++;
449 /* rotate busy targets to the end */
450 if (MAXIMUM_PENDING_PER_PEER == t->load)
451 {
453 pi->t_tail,
454 t);
456 pi->t_tail,
457 t);
458 }
459 GDS_u_send (t->u,
460 t->utarget,
461 msg,
462 ntohs (msg->size),
464 t);
465}
466
467
475static int
476find_bucket (const struct GNUNET_HashCode *hc)
477{
478 struct GNUNET_HashCode xor;
479 unsigned int bits;
480
483 &xor);
485 if (bits == MAX_BUCKETS)
486 {
487 /* How can all bits match? Got my own ID? */
488 GNUNET_break (0);
489 return -1;
490 }
491 return MAX_BUCKETS - bits - 1;
492}
493
494
505add_known_to_bloom (void *cls,
506 const struct GNUNET_PeerIdentity *key,
507 void *value)
508{
509 struct GNUNET_BLOCK_Group *bg = cls;
510 struct PeerInfo *pi = value;
511
513 &pi->phash,
514 1);
516 "Adding known peer (%s) to Bloom filter for FIND PEER\n",
517 GNUNET_i2s (key));
518 return GNUNET_YES;
519}
520
521
529static void
530send_find_peer_message (void *cls)
531{
532 (void) cls;
533
534 /* Compute when to do this again (and if we should
535 even send a message right now) */
536 {
537 struct GNUNET_TIME_Relative next_send_time;
538 bool done_early;
539
540 find_peer_task = NULL;
541 done_early = (newly_found_peers > bucket_size);
542 /* schedule next round, taking longer if we found more peers
543 in the last round. */
544 next_send_time.rel_value_us =
550 1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
554 GNUNET_SCHEDULER_add_delayed (next_send_time,
556 NULL);
557 if (done_early)
558 return;
559 }
560
561 /* actually send 'find peer' request */
562 {
563 struct GNUNET_BLOCK_Group *bg;
564 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
565
568 NULL,
569 0,
570 "seen-set-size",
573 NULL);
576 bg);
577 peer_bf
581 if (GNUNET_OK !=
586 0, /* hop count */
588 NULL, 0, /* xquery */
589 bg,
590 peer_bf))
591 {
593 "# Failed to initiate FIND PEER lookup",
594 1,
595 GNUNET_NO);
596 }
597 else
598 {
600 "# FIND PEER messages initiated",
601 1,
602 GNUNET_NO);
603 }
606 }
607}
608
609
617static void
618update_hold (struct PeerBucket *bucket)
619{
620 unsigned int off = 0;
621
622 /* find the peer -- we just go over all of them, should
623 be hardly any more expensive than just finding the 'right'
624 one. */
625 for (struct PeerInfo *pos = bucket->head;
626 NULL != pos;
627 pos = pos->next)
628 {
629 if (off > bucket_size)
630 break; /* We only hold up to #bucket_size peers per bucket */
631 off++;
632 for (struct Target *tp = pos->t_head;
633 NULL != tp;
634 tp = tp->next)
635 if (NULL == tp->ph)
636 tp->ph = GDS_u_hold (tp->u,
637 tp->utarget);
638 }
639}
640
641
642void
643GDS_u_connect (void *cls,
644 struct GNUNET_DHTU_Target *target,
645 const struct GNUNET_PeerIdentity *pid,
646 void **ctx)
647{
648 struct GDS_Underlay *u = cls;
649 struct PeerInfo *pi;
650 struct PeerBucket *bucket;
651 bool do_hold = false;
652
653 /* Check for connect to self message */
655 pid))
656 return;
658 "Connected to peer %s\n",
659 GNUNET_i2s (pid));
661 pid);
662 if (NULL == pi)
663 {
665 "# peers connected",
666 1,
667 GNUNET_NO);
668 pi = GNUNET_new (struct PeerInfo);
669 pi->id = *pid;
671 sizeof(*pid),
672 &pi->phash);
673 pi->peer_bucket = find_bucket (&pi->phash);
674 GNUNET_assert ( (pi->peer_bucket >= 0) &&
675 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
676 bucket = &k_buckets[pi->peer_bucket];
678 bucket->tail,
679 pi);
680 bucket->peers_size++;
682 (unsigned int) pi->peer_bucket + 1);
685 &pi->id,
686 pi,
688 if (bucket->peers_size <= bucket_size)
689 {
691 do_hold = true;
692 }
695 {
696 /* got a first connection, good time to start with FIND PEER requests... */
699 NULL);
700 }
701 }
702 {
703 struct Target *t;
704
705 t = GNUNET_new (struct Target);
706 t->u = u;
707 t->utarget = target;
708 t->pi = pi;
710 pi->t_tail,
711 t);
712 *ctx = t;
713
714 }
715 if (do_hold)
716 update_hold (bucket);
717}
718
719
720void
721GDS_u_disconnect (void *ctx)
722{
723 struct Target *t = ctx;
724 struct PeerInfo *pi;
725 struct PeerBucket *bucket;
726 bool was_held = false;
727
728 /* Check for disconnect from self message (on shutdown) */
729 if (NULL == t)
730 return;
731 pi = t->pi;
733 pi->t_tail,
734 t);
735 if (NULL != t->ph)
736 {
737 GDS_u_drop (t->u,
738 t->ph);
739 t->ph = NULL;
740 was_held = true;
741 }
742 if (t->load > 0)
743 {
744 t->dropped = true;
745 t->pi = NULL;
746 }
747 else
748 {
749 GNUNET_free (t);
750 }
751 if (NULL != pi->t_head)
752 return; /* got other connections still */
754 "Disconnected from peer %s\n",
755 GNUNET_i2s (&pi->id));
757 "# peers connected",
758 -1,
759 GNUNET_NO);
762 &pi->id,
763 pi));
766 {
768 find_peer_task = NULL;
769 }
770 GNUNET_assert (pi->peer_bucket >= 0);
771 bucket = &k_buckets[pi->peer_bucket];
773 bucket->tail,
774 pi);
775 GNUNET_assert (bucket->peers_size > 0);
776 bucket->peers_size--;
777 if ( (was_held) &&
778 (bucket->peers_size >= bucket_size - 1) )
779 update_hold (bucket);
780 while ( (closest_bucket > 0) &&
783 GNUNET_free (pi->hello);
784 GNUNET_free (pi);
785}
786
787
796static unsigned int
797get_forward_count (uint16_t hop_count,
798 uint16_t target_replication)
799{
800 uint32_t random_value;
801 uint32_t forward_count;
802 float target_value;
803 double rm1;
804
805 if (hop_count > GDS_NSE_get () * 4.0)
806 {
807 /* forcefully terminate */
809 "# requests TTL-dropped",
810 1,
811 GNUNET_NO);
812 return 0;
813 }
814 if (hop_count > GDS_NSE_get () * 2.0)
815 {
816 /* Once we have reached our ideal number of hops, only forward to 1 peer */
817 return 1;
818 }
819 /* bound by system-wide maximum and minimum */
820 if (0 == target_replication)
821 target_replication = 1; /* 0 is verboten */
822 target_replication =
824 target_replication);
825 rm1 = target_replication - 1.0;
826 target_value =
827 1 + (rm1) / (GDS_NSE_get () + (rm1 * hop_count));
828
829 /* Set forward count to floor of target_value */
830 forward_count = (uint32_t) target_value;
831 /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
832 target_value = target_value - forward_count;
834 UINT32_MAX);
835 if (random_value < (target_value * UINT32_MAX))
836 forward_count++;
837 return GNUNET_MIN (forward_count,
839}
840
841
854 const struct GNUNET_CONTAINER_BloomFilter *bloom)
855{
856 int delta;
858 key))
859 return GNUNET_YES;
860 for (int bucket_num = find_bucket (key);
861 bucket_num < closest_bucket;
862 bucket_num++)
863 {
864 unsigned int count = 0;
865
866 GNUNET_assert (bucket_num >= 0);
867 for (struct PeerInfo *pos = k_buckets[bucket_num].head;
868 NULL != pos;
869 pos = pos->next)
870 {
871 if (count >= bucket_size)
872 break; /* we only consider first #bucket_size entries per bucket */
873 count++;
874 if ( (NULL != bloom) &&
875 (GNUNET_YES ==
877 &pos->phash)) )
878 continue; /* Ignore filtered peers */
879 /* All peers in this bucket must be closer than us, as
880 they mismatch with our PID on the pivotal bit. So
881 because an unfiltered peer exists, we are not the
882 closest. */
883 delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
885 key);
886 switch (delta)
887 {
888 case -1: /* pos closer */
889 return GNUNET_NO;
890 case 0: /* identical, impossible! */
891 GNUNET_assert (0);
892 break;
893 case 1: /* I am closer */
894 break;
895 }
896 }
897 }
898 /* No closer (unfiltered) peers found; we must be the closest! */
899 return GNUNET_YES;
900}
901
902
924static struct PeerInfo *
925select_peer (const struct GNUNET_HashCode *key,
926 const struct GNUNET_CONTAINER_BloomFilter *bloom,
927 uint32_t hops)
928{
929 if (0 == closest_bucket)
930 {
932 "# Peer selection failed",
933 1,
934 GNUNET_NO);
935 return NULL; /* we have zero connections */
936 }
937 if (hops >= GDS_NSE_get ())
938 {
939 /* greedy selection (closest peer that is not in Bloom filter) */
940 struct PeerInfo *chosen = NULL;
941 int best_bucket;
942 int bucket_offset;
943
944 {
945 struct GNUNET_HashCode xor;
946
949 &xor);
950 best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
951 }
952 if (best_bucket >= closest_bucket)
953 bucket_offset = closest_bucket - 1;
954 else
955 bucket_offset = best_bucket;
956 while (-1 != bucket_offset)
957 {
958 struct PeerBucket *bucket = &k_buckets[bucket_offset];
959 unsigned int count = 0;
960
961 for (struct PeerInfo *pos = bucket->head;
962 NULL != pos;
963 pos = pos->next)
964 {
965 if (count >= bucket_size)
966 break; /* we only consider first #bucket_size entries per bucket */
967 count++;
968 if ( (NULL != bloom) &&
969 (GNUNET_YES ==
971 &pos->phash)) )
972 {
974 "Excluded peer `%s' due to BF match in greedy routing for %s\n",
975 GNUNET_i2s (&pos->id),
976 GNUNET_h2s (key));
977 continue;
978 }
979 if (NULL == chosen)
980 {
981 /* First candidate */
982 chosen = pos;
983 }
984 else
985 {
986 int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
987 &chosen->phash,
988 key);
989 switch (delta)
990 {
991 case -1: /* pos closer */
992 chosen = pos;
993 break;
994 case 0: /* identical, impossible! */
995 GNUNET_assert (0);
996 break;
997 case 1: /* chosen closer */
998 break;
999 }
1000 }
1001 count++;
1002 } /* for all (#bucket_size) peers in bucket */
1003 if (NULL != chosen)
1004 break;
1005
1006 /* If we chose nothing in first iteration, first go through deeper
1007 buckets (best chance to find a good match), and if we still found
1008 nothing, then to shallower buckets. Terminate on any match in the
1009 current bucket, as this search order guarantees that it can only get
1010 worse as we keep going. */
1011 if (bucket_offset > best_bucket)
1012 {
1013 /* Go through more deeper buckets */
1014 bucket_offset++;
1015 if (bucket_offset == closest_bucket)
1016 {
1017 /* Can't go any deeper, if nothing selected,
1018 go for shallower buckets */
1019 bucket_offset = best_bucket - 1;
1020 }
1021 }
1022 else
1023 {
1024 /* We're either at the 'best_bucket' or already moving
1025 on to shallower buckets. */
1026 if (bucket_offset == best_bucket)
1027 bucket_offset++; /* go for deeper buckets */
1028 else
1029 bucket_offset--; /* go for shallower buckets */
1030 }
1031 } /* for applicable buckets (starting at best match) */
1032 if (NULL == chosen)
1033 {
1035 "# Peer selection failed",
1036 1,
1037 GNUNET_NO);
1038 return NULL;
1039 }
1041 "Selected peer `%s' in greedy routing for %s\n",
1042 GNUNET_i2s (&chosen->id),
1043 GNUNET_h2s (key));
1044 return chosen;
1045 } /* end of 'greedy' peer selection */
1046
1047 /* select "random" peer */
1048 /* count number of peers that are available and not filtered,
1049 but limit to at most #bucket_size peers, starting with
1050 those 'furthest' from us. */
1051 {
1052 unsigned int total = 0;
1053 unsigned int selected;
1054
1055 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1056 {
1057 struct PeerBucket *bucket = &k_buckets[bc];
1058 unsigned int count = 0;
1059
1060 for (struct PeerInfo *pos = bucket->head;
1061 NULL != pos;
1062 pos = pos->next)
1063 {
1064 count++;
1065 if (count > bucket_size)
1066 break; /* limits search to #bucket_size peers per bucket */
1067 if ( (NULL != bloom) &&
1068 (GNUNET_YES ==
1070 &pos->phash)) )
1071 {
1073 "Excluded peer `%s' due to BF match in random routing for %s\n",
1074 GNUNET_i2s (&pos->id),
1075 GNUNET_h2s (key));
1076 continue; /* Ignore filtered peers */
1077 }
1078 total++;
1079 } /* for all peers in bucket */
1080 } /* for all buckets */
1081 if (0 == total) /* No peers to select from! */
1082 {
1084 "# Peer selection failed",
1085 1,
1086 GNUNET_NO);
1087 return NULL;
1088 }
1089
1090 /* Now actually choose a peer */
1092 total);
1093 for (unsigned int bc = 0; bc < closest_bucket; bc++)
1094 {
1095 unsigned int count = 0;
1096
1097 for (struct PeerInfo *pos = k_buckets[bc].head;
1098 pos != NULL;
1099 pos = pos->next)
1100 {
1101 count++;
1102 if (count > bucket_size)
1103 break; /* limits search to #bucket_size peers per bucket */
1104
1105 if ( (NULL != bloom) &&
1106 (GNUNET_YES ==
1108 &pos->phash)) )
1109 continue; /* Ignore bloomfiltered peers */
1110 if (0 == selected--)
1111 {
1113 "Selected peer `%s' in random routing for %s\n",
1114 GNUNET_i2s (&pos->id),
1115 GNUNET_h2s (key));
1116 return pos;
1117 }
1118 } /* for peers in bucket */
1119 } /* for all buckets */
1120 } /* random peer selection scope */
1121 GNUNET_break (0);
1122 return NULL;
1123}
1124
1125
1139static unsigned int
1140get_target_peers (const struct GNUNET_HashCode *key,
1141 struct GNUNET_CONTAINER_BloomFilter *bloom,
1142 uint16_t hop_count,
1143 uint16_t target_replication,
1144 struct PeerInfo ***targets)
1145{
1146 unsigned int target;
1147 unsigned int off;
1148 struct PeerInfo **rtargets;
1149
1150 GNUNET_assert (NULL != bloom);
1151 target = get_forward_count (hop_count,
1152 target_replication);
1153 if (0 == target)
1154 {
1155 *targets = NULL;
1156 return 0;
1157 }
1158 rtargets = GNUNET_new_array (target,
1159 struct PeerInfo *);
1160 for (off = 0; off < target; off++)
1161 {
1162 struct PeerInfo *nxt;
1163
1164 nxt = select_peer (key,
1165 bloom,
1166 hop_count);
1167 if (NULL == nxt)
1168 break;
1169 rtargets[off] = nxt;
1170 }
1172 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1173 off,
1175 (unsigned int) hop_count,
1176 GNUNET_h2s (key),
1177 target);
1178 if (0 == off)
1179 {
1180 GNUNET_free (rtargets);
1181 *targets = NULL;
1182 return 0;
1183 }
1184 *targets = rtargets;
1186 "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1187 GNUNET_h2s (key),
1188 off,
1189 target);
1190 return off;
1191}
1192
1193
1199static void
1200hello_check (const struct GNUNET_DATACACHE_Block *bd)
1201{
1202 struct GNUNET_HELLO_Parser *b;
1203
1205 return;
1206
1208 bd->data_size);
1210 {
1213 NULL);
1214 }
1216}
1217
1218
1221 uint16_t desired_replication_level,
1222 uint16_t hop_count,
1224{
1225 unsigned int target_count;
1226 struct PeerInfo **targets;
1227 size_t msize;
1228 enum GNUNET_DHT_RouteOption ro = bd->ro;
1229 unsigned int put_path_length = bd->put_path_length;
1230 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1231 bool truncated = (0 != (bd->ro & GNUNET_DHT_RO_TRUNCATED));
1232 const struct GNUNET_PeerIdentity *trunc_peer
1233 = truncated
1234 ? &bd->trunc_peer
1235 : NULL;
1236 struct GNUNET_PeerIdentity trunc_peer_out;
1238
1241 bd->ro, &ro,
1242 bd->expiration_time,
1243 bd->data, bd->data_size,
1244 put_path, put_path_length,
1245 &put_path_length,
1246 trunc_peer,
1247 &trunc_peer_out,
1248 &truncated);
1249 if (truncated)
1250 trunc_peer = &trunc_peer_out;
1251 /* Path may have been truncated by the call above */
1253 "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1255 GNUNET_h2s (&bd->key),
1256 (bd->ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1257 (bd->ro & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1258
1259 /* if we got a HELLO, consider it for our own routing table */
1260 hello_check (bd);
1261 GNUNET_assert (NULL != bf);
1265 "# PUT requests routed",
1266 1,
1267 GNUNET_NO);
1268 if (GNUNET_OK != ret)
1269 return ret;
1270 target_count
1271 = get_target_peers (&bd->key,
1272 bf,
1273 hop_count,
1274 desired_replication_level,
1275 &targets);
1276 if (0 == target_count)
1277 {
1279 "Routing PUT for %s terminates after %u hops at %s\n",
1280 GNUNET_h2s (&bd->key),
1281 (unsigned int) hop_count,
1283 return GNUNET_NO;
1284 }
1285 for (unsigned int i = 0; i < target_count; i++)
1286 {
1287 struct PeerInfo *target = targets[i];
1288
1290 &target->phash);
1291 }
1292 for (unsigned int i = 0; i < target_count; i++)
1293 {
1294 struct PeerInfo *target = targets[i];
1295 struct PeerPutMessage *ppm;
1296 char buf[msize] GNUNET_ALIGN;
1297
1298 ppm = (struct PeerPutMessage *) buf;
1299 GDS_helper_make_put_message (ppm, msize,
1301 &target->id,
1302 &target->phash,
1303 bf,
1304 &bd->key,
1305 ro,
1306 bd->type,
1307 bd->expiration_time,
1308 bd->data, bd->data_size,
1309 put_path, put_path_length,
1310 hop_count,
1312 trunc_peer);
1314 "Routing PUT for %s after %u hops to %s\n",
1315 GNUNET_h2s (&bd->key),
1316 (unsigned int) hop_count,
1317 GNUNET_i2s (&target->id));
1318 do_send (target,
1319 &ppm->header);
1320 }
1321 GNUNET_free (targets);
1323 "# PUT messages queued for transmission",
1324 target_count,
1325 GNUNET_NO);
1326 return GNUNET_OK;
1327}
1328
1329
1334 uint16_t hop_count,
1335 const struct GNUNET_HashCode *key,
1336 const void *xquery,
1337 size_t xquery_size,
1338 struct GNUNET_BLOCK_Group *bg,
1339 struct GNUNET_CONTAINER_BloomFilter *peer_bf)
1340{
1341 unsigned int target_count;
1342 struct PeerInfo **targets;
1343 size_t msize;
1344 size_t result_filter_size;
1345 void *result_filter;
1346
1347 GNUNET_assert (NULL != peer_bf);
1349 "# GET requests routed",
1350 1,
1351 GNUNET_NO);
1352 target_count = get_target_peers (key,
1353 peer_bf,
1354 hop_count,
1355 desired_replication_level,
1356 &targets);
1358 "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1360 GNUNET_h2s (key),
1362 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1363
1366 if (0 == target_count)
1367 {
1369 "Routing GET for %s terminates after %u hops at %s\n",
1370 GNUNET_h2s (key),
1371 (unsigned int) hop_count,
1373 return GNUNET_NO;
1374 }
1375 if (GNUNET_OK !=
1377 &result_filter,
1378 &result_filter_size))
1379 {
1380 result_filter = NULL;
1381 result_filter_size = 0;
1382 }
1383 msize = xquery_size + result_filter_size;
1384 if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1385 {
1386 GNUNET_break (0);
1387 GNUNET_free (result_filter);
1388 GNUNET_free (targets);
1389 return GNUNET_NO;
1390 }
1391 /* update BF */
1392 for (unsigned int i = 0; i < target_count; i++)
1393 {
1394 struct PeerInfo *target = targets[i];
1395
1397 &target->phash);
1398 }
1399 /* forward request */
1400 for (unsigned int i = 0; i < target_count; i++)
1401 {
1402 struct PeerInfo *target = targets[i];
1403 struct PeerGetMessage *pgm;
1404 char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1405 char *rf;
1406
1408 "Routing GET for %s after %u hops to %s\n",
1409 GNUNET_h2s (key),
1410 (unsigned int) hop_count,
1411 GNUNET_i2s (&target->id));
1412 pgm = (struct PeerGetMessage *) buf;
1414 pgm->header.size = htons (sizeof (buf));
1415 pgm->type = htonl (type);
1416 pgm->options = htons (options);
1417 pgm->hop_count = htons (hop_count + 1);
1419 pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1422 pgm->bloomfilter,
1424 pgm->key = *key;
1425 rf = (char *) &pgm[1];
1426 GNUNET_memcpy (rf,
1427 result_filter,
1430 xquery,
1431 xquery_size);
1432 do_send (target,
1433 &pgm->header);
1434 }
1436 "# GET messages queued for transmission",
1437 target_count,
1438 GNUNET_NO);
1439 GNUNET_free (targets);
1440 GNUNET_free (result_filter);
1441 return (0 < target_count) ? GNUNET_OK : GNUNET_NO;
1442}
1443
1444
1445struct PeerInfo *
1447{
1449 target);
1450}
1451
1452
1453bool
1455 const struct GNUNET_DATACACHE_Block *bd,
1456 const struct GNUNET_HashCode *query_hash,
1457 unsigned int get_path_length,
1458 const struct GNUNET_DHT_PathElement *get_path)
1459{
1460 struct GNUNET_DHT_PathElement *paths;
1461 size_t msize;
1462 unsigned int ppl = bd->put_path_length;
1463 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1464 enum GNUNET_DHT_RouteOption ro = bd->ro;
1465 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1466 const struct GNUNET_PeerIdentity *trunc_peer
1467 = truncated
1468 ? &bd->trunc_peer
1469 : NULL;
1470 bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1471#if SANITY_CHECKS > 1
1472 unsigned int failure_offset;
1473
1474 failure_offset
1476 bd->data_size,
1477 bd->expiration_time,
1478 trunc_peer,
1479 put_path,
1480 ppl,
1481 get_path,
1482 get_path_length,
1484 if (0 != failure_offset)
1485 {
1486 GNUNET_assert (failure_offset <= ppl + get_path_length);
1487 GNUNET_break_op (0);
1488 if (failure_offset < ppl)
1489 {
1490 trunc_peer = &put_path[failure_offset - 1].pred;
1491 put_path += failure_offset;
1492 ppl -= failure_offset;
1493 truncated = true;
1495 }
1496 else
1497 {
1498 failure_offset -= ppl;
1499 if (0 == failure_offset)
1500 trunc_peer = &put_path[ppl - 1].pred;
1501 else
1502 trunc_peer = &get_path[failure_offset - 1].pred;
1503 ppl = 0;
1504 put_path = NULL;
1505 truncated = true;
1507 get_path += failure_offset;
1508 get_path_length -= failure_offset;
1509 }
1510 }
1511#endif
1512 msize = bd->data_size + sizeof (struct PeerResultMessage);
1513 if (msize > GNUNET_MAX_MESSAGE_SIZE)
1514 {
1515 GNUNET_break_op (0);
1516 return false;
1517 }
1518 if (truncated)
1519 msize += sizeof (struct GNUNET_PeerIdentity);
1520 if (tracking)
1521 msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
1522 if (msize < bd->data_size)
1523 {
1524 GNUNET_break_op (0);
1525 return false;
1526 }
1527 if ( (GNUNET_MAX_MESSAGE_SIZE - msize)
1528 / sizeof(struct GNUNET_DHT_PathElement)
1529 < (get_path_length + ppl) )
1530 {
1531 get_path_length = 0;
1532 ppl = 0;
1533 }
1534 if ( (get_path_length > UINT16_MAX) ||
1535 (ppl > UINT16_MAX) )
1536 {
1537 GNUNET_break (0);
1538 get_path_length = 0;
1539 ppl = 0;
1540 }
1541 msize += (get_path_length + ppl)
1542 * sizeof(struct GNUNET_DHT_PathElement);
1544 "Forwarding reply for key %s to peer %s\n",
1545 GNUNET_h2s (query_hash),
1546 GNUNET_i2s (&pi->id));
1548 "# RESULT messages queued for transmission",
1549 1,
1550 GNUNET_NO);
1551 {
1552 struct PeerResultMessage *prm;
1553 char buf[msize] GNUNET_ALIGN;
1554 void *data;
1555
1556 prm = (struct PeerResultMessage *) buf;
1558 prm->header.size = htons (sizeof (buf));
1559 prm->type = htonl ((uint32_t) bd->type);
1560 prm->reserved = htons (0);
1561 prm->options = htons ((uint16_t) ro);
1562 prm->put_path_length = htons ((uint16_t) ppl);
1563 prm->get_path_length = htons ((uint16_t) get_path_length);
1565 prm->key = *query_hash;
1566 if (truncated)
1567 {
1568 void *tgt = &prm[1];
1569
1570 GNUNET_memcpy (tgt,
1571 trunc_peer,
1572 sizeof (struct GNUNET_PeerIdentity));
1573 paths = (struct GNUNET_DHT_PathElement *)
1574 (tgt + sizeof (struct GNUNET_PeerIdentity));
1575 }
1576 else
1577 {
1578 paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1579 }
1580 if (NULL != put_path)
1581 {
1582 GNUNET_memcpy (paths,
1583 put_path,
1584 ppl * sizeof(struct GNUNET_DHT_PathElement));
1585 }
1586 else
1587 {
1588 GNUNET_assert (0 == ppl);
1589 }
1590 if (NULL != get_path)
1591 {
1592 GNUNET_memcpy (&paths[ppl],
1593 get_path,
1594 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1595 }
1596 else
1597 {
1598 GNUNET_assert (0 == get_path_length);
1599 }
1600 if (tracking)
1601 {
1603 void *tgt = &paths[get_path_length + ppl];
1604 const struct GNUNET_PeerIdentity *pred;
1605
1606 if (ppl + get_path_length > 0)
1607 pred = &paths[ppl + get_path_length - 1].pred;
1608 else if (truncated)
1609 pred = trunc_peer;
1610 else
1611 pred = NULL; /* we are first! */
1612 /* Note that the last signature in 'paths' was not initialized before,
1613 so this is crucial to avoid sending garbage. */
1615 bd->data_size,
1617 bd->expiration_time,
1618 pred,
1619 &pi->id,
1620 &sig);
1621 memcpy (tgt,
1622 &sig,
1623 sizeof (sig));
1624 data = tgt + sizeof (sig);
1626 "Signing GET PATH %u/%u of %s => %s\n",
1627 ppl,
1628 get_path_length,
1629 GNUNET_h2s (query_hash),
1630 GNUNET_B2S (&sig));
1631#if SANITY_CHECKS > 1
1632 {
1633 struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
1634
1635 memcpy (xpaths,
1636 &paths[ppl],
1637 get_path_length * sizeof (struct GNUNET_DHT_PathElement));
1638 xpaths[get_path_length].sig = sig;
1639 xpaths[get_path_length].pred = GDS_my_identity;
1640 if (0 !=
1642 bd->data_size,
1643 bd->expiration_time,
1644 trunc_peer,
1645 paths,
1646 ppl,
1647 xpaths,
1648 get_path_length + 1,
1649 &pi->id))
1650 {
1651 GNUNET_break (0);
1652 return false;
1653 }
1654 }
1655#endif
1656 }
1657 else
1658 {
1659 data = &prm[1];
1660 }
1662 bd->data,
1663 bd->data_size);
1664 do_send (pi,
1665 &prm->header);
1666 }
1667 return true;
1668}
1669
1670
1678static enum GNUNET_GenericReturnValue
1679check_dht_p2p_put (void *cls,
1680 const struct PeerPutMessage *put)
1681{
1682 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1683 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1684 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1685 uint16_t msize = ntohs (put->header.size);
1686 uint16_t putlen = ntohs (put->put_path_length);
1687 size_t xsize = (has_path
1688 ? sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1689 : 0)
1690 + (truncated
1691 ? sizeof (struct GNUNET_PeerIdentity)
1692 : 0);
1693 size_t var_meta_size
1694 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1695 + xsize;
1696
1697 (void) cls;
1698 if ( (msize <
1699 sizeof (struct PeerPutMessage) + var_meta_size) ||
1700 (putlen >
1701 (GNUNET_MAX_MESSAGE_SIZE
1702 - sizeof (struct PeerPutMessage)
1703 - xsize)
1704 / sizeof(struct GNUNET_DHT_PathElement)) )
1705 {
1706 GNUNET_break_op (0);
1707 return GNUNET_SYSERR;
1708 }
1709 if (GNUNET_BLOCK_TYPE_ANY == htonl (put->type))
1710 {
1711 GNUNET_break_op (0);
1712 return GNUNET_SYSERR;
1713 }
1714 return GNUNET_OK;
1715}
1716
1717
1724static void
1725handle_dht_p2p_put (void *cls,
1726 const struct PeerPutMessage *put)
1727{
1728 struct Target *t = cls;
1729 struct PeerInfo *peer = t->pi;
1730 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1731 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1732 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1733 uint16_t msize = ntohs (put->header.size);
1734 uint16_t putlen = ntohs (put->put_path_length);
1735 const struct GNUNET_PeerIdentity *trunc_peer
1736 = truncated
1737 ? (const struct GNUNET_PeerIdentity *) &put[1]
1738 : NULL;
1739 const struct GNUNET_DHT_PathElement *put_path
1740 = truncated
1741 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
1742 : (const struct GNUNET_DHT_PathElement *) &put[1];
1743 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
1744 = has_path
1745 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &put_path[putlen]
1746 : NULL;
1747 const char *data
1748 = has_path
1749 ? (const char *) &last_sig[1]
1750 : (const char *) &put_path[putlen];
1751 size_t var_meta_size
1752 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1753 + (has_path ? sizeof (*last_sig) : 0)
1754 + (truncated ? sizeof (*trunc_peer) : 0);
1755 struct GNUNET_DATACACHE_Block bd = {
1756 .key = put->key,
1757 .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
1758 .type = ntohl (put->type),
1759 .ro = ro,
1760 .data_size = msize - sizeof(*put) - var_meta_size,
1761 .data = data
1762 };
1763
1764 if (NULL != trunc_peer)
1765 bd.trunc_peer = *trunc_peer;
1767 "PUT for `%s' from %s with RO (%s/%s)\n",
1768 GNUNET_h2s (&put->key),
1769 GNUNET_i2s (&peer->id),
1770 (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1771 has_path ? "R" : "-");
1773 {
1775 "# Expired PUTs discarded",
1776 1,
1777 GNUNET_NO);
1778 return;
1779 }
1780 {
1781 /* Only call 'check_block' if that keeps our CPU load (from
1782 the cryptography) below 50% on average */
1783 static struct GNUNET_TIME_Relative avg_latency;
1784 static struct GNUNET_TIME_Absolute next_time;
1785
1786 if (GNUNET_TIME_absolute_is_past (next_time))
1787 {
1788 struct GNUNET_TIME_Absolute now
1790 struct GNUNET_TIME_Relative latency;
1792
1793 if (GNUNET_NO ==
1795 bd.type,
1796 bd.data,
1797 bd.data_size))
1798 {
1799 GNUNET_break_op (0);
1800 return;
1801 }
1802 latency = GNUNET_TIME_absolute_get_duration (now);
1803 /* Use *moving average* to estimate check_block latency */
1804 avg_latency
1807 GNUNET_TIME_relative_multiply (avg_latency,
1808 7),
1809 latency),
1810 8);
1811 /* average delay = 50% of avg_latency => 50% CPU load from crypto (at most) */
1814 avg_latency.rel_value_us > 0
1815 ? avg_latency.rel_value_us
1816 : 1LLU);
1818 }
1819 }
1820 if (! has_path)
1821 putlen = 0;
1823 "# P2P PUT requests received",
1824 1,
1825 GNUNET_NO);
1827 "# P2P PUT bytes received",
1828 msize,
1829 GNUNET_NO);
1830 {
1831 struct GNUNET_HashCode test_key;
1833
1835 bd.type,
1836 bd.data,
1837 bd.data_size,
1838 &test_key);
1839 switch (ret)
1840 {
1841 case GNUNET_YES:
1842 if (0 != GNUNET_memcmp (&test_key,
1843 &bd.key))
1844 {
1845 GNUNET_break_op (0);
1846 return;
1847 }
1848 break;
1849 case GNUNET_NO:
1850 /* cannot verify, good luck */
1851 break;
1852 case GNUNET_SYSERR:
1853 /* block type not supported, good luck */
1854 break;
1855 }
1856 }
1857
1858 {
1860 struct GNUNET_DHT_PathElement pp[putlen + 1];
1861
1867 &peer->phash));
1868 /* extend 'put path' by sender */
1869 bd.put_path = pp;
1870 bd.put_path_length = putlen + 1;
1871 if (has_path)
1872 {
1873 unsigned int failure_offset;
1874
1875 GNUNET_memcpy (pp,
1876 put_path,
1877 putlen * sizeof(struct GNUNET_DHT_PathElement));
1878 pp[putlen].pred = peer->id;
1879 pp[putlen].sig = *last_sig;
1880#if SANITY_CHECKS
1881 /* TODO: might want to eventually implement probabilistic
1882 load-based path verification, but for now it is all or nothing */
1883 failure_offset
1885 bd.data_size,
1886 bd.expiration_time,
1887 trunc_peer,
1888 pp,
1889 putlen + 1,
1890 NULL, 0, /* get_path */
1892#else
1893 failure_offset = 0;
1894#endif
1895 if (0 != failure_offset)
1896 {
1897 GNUNET_break_op (0);
1899 "Recorded put path invalid at offset %u, truncating\n",
1900 failure_offset);
1901 GNUNET_assert (failure_offset <= putlen + 1);
1902 bd.put_path = &pp[failure_offset];
1903 bd.put_path_length = (putlen + 1) - failure_offset;
1905 bd.trunc_peer = pp[failure_offset - 1].pred;
1906 }
1907 }
1908 else
1909 {
1910 bd.put_path_length = 0;
1911 }
1912
1913 /* give to local clients */
1915 &bd.key,
1916 0, NULL /* get path */));
1917
1918 /* store locally */
1919 if ( (0 != (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
1920 (GDS_am_closest_peer (&put->key,
1921 bf)) )
1923 {
1924 enum GNUNET_GenericReturnValue forwarded;
1925
1926 /* route to other peers */
1927 forwarded
1929 ntohs (put->desired_replication_level),
1930 ntohs (put->hop_count),
1931 bf);
1932 /* notify monitoring clients */
1933 bd.ro |= ((GNUNET_OK == forwarded)
1935 : 0);
1937 ntohs (put->hop_count),
1938 ntohs (put->desired_replication_level));
1939 }
1941 }
1942}
1943
1944
1945struct BlockCls
1946{
1947 struct PeerInfo *pi;
1948 const struct GNUNET_HashCode *query_hash;
1949 struct GNUNET_BLOCK_Group *bg;
1950};
1951
1952
1961static void
1962handle_find_my_hello (struct PeerInfo *pi,
1963 const struct GNUNET_HashCode *query_hash,
1964 struct GNUNET_BLOCK_Group *bg)
1965{
1966
1967 if (NULL == GDS_my_hello)
1968 {
1970 "# FIND PEER requests ignored due to lack of HELLO",
1971 1,
1972 GNUNET_NO);
1973 }
1974 else if (GNUNET_BLOCK_REPLY_OK_MORE ==
1977 bg,
1979 NULL, 0,
1981 ntohs (GDS_my_hello->size)))
1982 {
1983 struct GNUNET_DATACACHE_Block bd = {
1985 .expiration_time
1988 .key = GDS_my_identity_hash,
1989 .data = GDS_my_hello,
1990 .data_size = ntohs (GDS_my_hello->size)
1991 };
1992
1994 &bd,
1995 query_hash,
1996 0, NULL /* get path */));
1997 }
1998 else
1999 {
2001 "# FIND PEER requests ignored due to Bloomfilter",
2002 1,
2003 GNUNET_NO);
2004 }
2005}
2006
2007
2016static void
2018 const struct GNUNET_HashCode *query_hash,
2019 struct GNUNET_BLOCK_Group *bg)
2020{
2021 /* Force non-random selection by hop count */
2022 struct PeerInfo *peer;
2023
2024 peer = select_peer (query_hash,
2025 NULL,
2026 GDS_NSE_get () + 1);
2027 if ( (NULL != peer->hello) &&
2033 bg,
2034 &peer->phash,
2035 NULL, 0, /* xquery */
2036 peer->hello,
2037 peer->hello_size)) )
2038 {
2039 struct GNUNET_DATACACHE_Block bd = {
2041 .expiration_time = peer->hello_expiration,
2042 .key = peer->phash,
2043 .data = peer->hello,
2044 .data_size = peer->hello_size
2045 };
2046
2048 &bd,
2049 query_hash,
2050 0, NULL /* get path */));
2051 }
2052}
2053
2054
2061static void
2062handle_local_result (void *cls,
2063 const struct GNUNET_DATACACHE_Block *bd)
2064{
2065 struct PeerInfo *peer = cls;
2066
2068 bd,
2069 &bd->key,
2070 0, NULL /* get path */));
2071}
2072
2073
2081static enum GNUNET_GenericReturnValue
2082check_dht_p2p_get (void *cls,
2083 const struct PeerGetMessage *get)
2084{
2085 uint16_t msize = ntohs (get->header.size);
2086 uint16_t result_filter_size = ntohs (get->result_filter_size);
2087
2088 (void) cls;
2089 if (msize < sizeof(*get) + result_filter_size)
2090 {
2091 GNUNET_break_op (0);
2092 return GNUNET_SYSERR;
2093 }
2094 return GNUNET_OK;
2095}
2096
2097
2104static void
2105handle_dht_p2p_get (void *cls,
2106 const struct PeerGetMessage *get)
2107{
2108 struct Target *t = cls;
2109 struct PeerInfo *peer = t->pi;
2110 uint16_t msize = ntohs (get->header.size);
2111 uint16_t result_filter_size = ntohs (get->result_filter_size);
2112 uint16_t hop_count = ntohs (get->hop_count);
2113 enum GNUNET_BLOCK_Type type = ntohl (get->type);
2114 enum GNUNET_DHT_RouteOption options = ntohs (get->options);
2116 const void *result_filter = (const void *) &get[1];
2117 const void *xquery = result_filter + result_filter_size;
2118 size_t xquery_size = msize - sizeof (*get) - result_filter_size;
2119
2120 /* parse and validate message */
2122 "# P2P GET requests received",
2123 1,
2124 GNUNET_NO);
2126 "# P2P GET bytes received",
2127 msize,
2128 GNUNET_NO);
2129 if (GNUNET_NO ==
2131 type,
2132 &get->key,
2133 xquery,
2134 xquery_size))
2135 {
2136 /* request invalid */
2137 GNUNET_break_op (0);
2138 return;
2139 }
2140
2141 {
2142 struct GNUNET_BLOCK_Group *bg;
2143 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
2144
2145 peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2148 ;
2151 &peer->phash));
2153 type,
2154 result_filter,
2155 result_filter_size,
2156 "filter-size",
2157 result_filter_size,
2158 NULL);
2160 "GET for %s at %s after %u hops\n",
2161 GNUNET_h2s (&get->key),
2163 (unsigned int) hop_count);
2164 /* local lookup (this may update the bg) */
2166 (GDS_am_closest_peer (&get->key,
2167 peer_bf)) )
2168 {
2171 {
2173 "# P2P HELLO lookup requests processed",
2174 1,
2175 GNUNET_NO);
2177 &get->key,
2178 bg);
2181 &get->key,
2182 bg);
2183 }
2185 {
2187 eval = GDS_DATACACHE_get_closest (&get->key,
2188 type,
2189 xquery,
2190 xquery_size,
2191 bg,
2193 peer);
2194 else
2195 eval = GDS_DATACACHE_handle_get (&get->key,
2196 type,
2197 xquery,
2198 xquery_size,
2199 bg,
2201 peer);
2202 }
2203 }
2204 else
2205 {
2207 "# P2P GET requests ONLY routed",
2208 1,
2209 GNUNET_NO);
2210 }
2211
2212 /* remember request for routing replies
2213 TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2214 */
2215 GDS_ROUTING_add (&peer->id,
2216 type,
2217 bg, /* bg now owned by routing, but valid at least until end of this function! */
2218 options,
2219 &get->key,
2220 xquery,
2221 xquery_size);
2222
2223 /* P2P forwarding */
2224 {
2225 bool forwarded = false;
2226 uint16_t desired_replication_level = ntohs (
2227 get->desired_replication_level);
2228
2229 if (eval != GNUNET_BLOCK_REPLY_OK_LAST)
2230 forwarded = (GNUNET_OK ==
2232 options,
2233 desired_replication_level,
2234 hop_count,
2235 &get->key,
2236 xquery,
2237 xquery_size,
2238 bg,
2239 peer_bf));
2241 options
2242 | (forwarded
2243 ? 0
2245 type,
2246 hop_count,
2247 desired_replication_level,
2248 &get->key);
2249 }
2250 /* clean up; note that 'bg' is owned by routing now! */
2252 }
2253}
2254
2255
2265static bool
2267 const struct GNUNET_HashCode *query_hash,
2268 unsigned int get_path_length,
2269 const struct GNUNET_DHT_PathElement *get_path)
2270{
2271 /* forward to local clients */
2273 "Forwarding reply to local clients\n");
2274 if (! GDS_CLIENTS_handle_reply (bd,
2275 query_hash,
2276 get_path_length,
2277 get_path))
2278 {
2279 GNUNET_break (0);
2280 return false;
2281 }
2283 get_path,
2284 get_path_length);
2286 {
2287 struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2288 + bd->put_path_length)];
2289 struct GNUNET_DATACACHE_Block bdx = *bd;
2290
2291 if (NULL != bd->put_path)
2292 GNUNET_memcpy (xput_path,
2293 bd->put_path,
2294 bd->put_path_length * sizeof(struct
2296 GNUNET_memcpy (&xput_path[bd->put_path_length],
2297 get_path,
2298 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2299 bdx.put_path = xput_path;
2300 bdx.put_path_length += get_path_length;
2302 }
2303 /* forward to other peers */
2305 query_hash,
2306 get_path_length,
2307 get_path);
2308 return true;
2309}
2310
2311
2319static enum GNUNET_GenericReturnValue
2320check_dht_p2p_result (void *cls,
2321 const struct PeerResultMessage *prm)
2322{
2323 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2324 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2325 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2326 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2327
2328 uint16_t get_path_length = ntohs (prm->get_path_length);
2329 uint16_t put_path_length = ntohs (prm->put_path_length);
2330 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2331 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2332
2333 (void) cls;
2334 if ( (msize < vsize) ||
2335 (msize - vsize <
2336 (get_path_length + put_path_length)
2337 * sizeof(struct GNUNET_DHT_PathElement)) ||
2338 (get_path_length >
2339 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2340 (put_path_length >
2341 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2342 {
2343 GNUNET_break_op (0);
2344 return GNUNET_SYSERR;
2345 }
2346 return GNUNET_OK;
2347}
2348
2349
2356static void
2357handle_dht_p2p_result (void *cls,
2358 const struct PeerResultMessage *prm)
2359{
2360 struct Target *t = cls;
2361 struct PeerInfo *peer = t->pi;
2362 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2363 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2364 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2365 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2366 uint16_t get_path_length = ntohs (prm->get_path_length);
2367 uint16_t put_path_length = ntohs (prm->put_path_length);
2368 const struct GNUNET_PeerIdentity *trunc_peer
2369 = truncated
2370 ? (const struct GNUNET_PeerIdentity *) &prm[1]
2371 : NULL;
2372 const struct GNUNET_DHT_PathElement *put_path
2373 = truncated
2374 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2375 : (const struct GNUNET_DHT_PathElement *) &prm[1];
2376 const struct GNUNET_DHT_PathElement *get_path
2377 = &put_path[put_path_length];
2378 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2379 = tracked
2380 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &get_path[get_path_length]
2381 : NULL;
2382 const void *data
2383 = tracked
2384 ? (const void *) &last_sig[1]
2385 : (const void *) &get_path[get_path_length];
2386 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2387 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2388 struct GNUNET_DATACACHE_Block bd = {
2390 .put_path = put_path,
2391 .put_path_length = put_path_length,
2392 .key = prm->key,
2393 .type = ntohl (prm->type),
2394 .ro = ro,
2395 .data = data,
2396 .data_size = msize - vsize - (get_path_length + put_path_length)
2397 * sizeof(struct GNUNET_DHT_PathElement)
2398 };
2399
2400 /* parse and validate message */
2402 {
2404 "# Expired results discarded",
2405 1,
2406 GNUNET_NO);
2407 return;
2408 }
2409 if (GNUNET_OK !=
2411 bd.type,
2412 bd.data,
2413 bd.data_size))
2414 {
2415 GNUNET_break_op (0);
2416 return;
2417 }
2419 "# P2P RESULTS received",
2420 1,
2421 GNUNET_NO);
2423 "# P2P RESULT bytes received",
2424 msize,
2425 GNUNET_NO);
2426 {
2428
2430 bd.type,
2431 bd.data,
2432 bd.data_size,
2433 &bd.key);
2434 if (GNUNET_NO == ret)
2435 bd.key = prm->key;
2436 }
2437
2438 /* if we got a HELLO, consider it for our own routing table */
2439 hello_check (&bd);
2440
2441 /* Need to append 'peer' to 'get_path' */
2442 if (tracked)
2443 {
2444 struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2445 struct GNUNET_DHT_PathElement *gp = xget_path;
2446 unsigned int failure_offset;
2447
2448 GNUNET_memcpy (xget_path,
2449 get_path,
2450 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2451 xget_path[get_path_length].pred = peer->id;
2452 /* use memcpy(), as last_sig may not be aligned */
2453 memcpy (&xget_path[get_path_length].sig,
2454 last_sig,
2455 sizeof (*last_sig));
2456#if SANITY_CHECKS
2457 /* TODO: might want to eventually implement probabilistic
2458 load-based path verification, but for now it is all or nothing */
2459 failure_offset
2461 bd.data_size,
2462 bd.expiration_time,
2463 trunc_peer,
2464 put_path,
2465 put_path_length,
2466 gp,
2467 get_path_length + 1,
2469#else
2470 failure_offset = 0;
2471#endif
2472 if (0 != failure_offset)
2473 {
2475 "Recorded path invalid at offset %u, truncating\n",
2476 failure_offset);
2477 GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length
2478 + 1);
2479 if (failure_offset < bd.put_path_length)
2480 {
2481 /* failure on put path */
2482 trunc_peer = &bd.put_path[failure_offset - 1].pred;
2484 bd.put_path = &bd.put_path[failure_offset];
2485 bd.put_path_length -= failure_offset;
2486 truncated = true;
2487 }
2488 else
2489 {
2490 /* failure on get path */
2491 failure_offset -= bd.put_path_length;
2492 if (0 == failure_offset)
2493 trunc_peer = &bd.put_path[bd.put_path_length - 1].pred;
2494 else
2495 trunc_peer = &gp[failure_offset - 1].pred;
2496 get_path_length -= failure_offset;
2497 gp = &gp[failure_offset];
2498 bd.put_path_length = 0;
2499 bd.put_path = NULL;
2501 truncated = true;
2502 }
2503 }
2505 "Extending GET path of length %u with %s\n",
2506 get_path_length,
2507 GNUNET_i2s (&peer->id));
2508 if (truncated)
2509 {
2510 GNUNET_assert (NULL != trunc_peer);
2511 bd.trunc_peer = *trunc_peer;
2512 }
2514 &prm->key,
2515 get_path_length + 1,
2516 gp));
2517 }
2518 else
2519 {
2520 if (truncated)
2521 {
2522 GNUNET_assert (NULL != trunc_peer);
2523 bd.trunc_peer = *trunc_peer;
2524 }
2526 &prm->key,
2527 0,
2528 NULL));
2529 }
2530}
2531
2532
2540static enum GNUNET_GenericReturnValue
2541check_dht_p2p_hello (void *cls,
2542 const struct GNUNET_MessageHeader *hello)
2543{
2544 struct Target *t = cls;
2545 struct PeerInfo *peer = t->pi;
2547 size_t hellob_size;
2548 void *hellob;
2550
2552 &peer->id,
2553 &hellob,
2554 &hellob_size,
2555 &expiration);
2556 GNUNET_free (hellob);
2557 return ret;
2558}
2559
2560
2567static void
2568handle_dht_p2p_hello (void *cls,
2569 const struct GNUNET_MessageHeader *hello)
2570{
2571 struct Target *t = cls;
2572 struct PeerInfo *peer = t->pi;
2573
2574 GNUNET_free (peer->hello);
2575 peer->hello_size = 0;
2578 &peer->id,
2579 &peer->hello,
2580 &peer->hello_size,
2581 &peer->hello_expiration));
2582}
2583
2584
2585void
2586GDS_u_receive (void *cls,
2587 void **tctx,
2588 void **sctx,
2589 const void *message,
2590 size_t message_size)
2591{
2592 struct Target *t = *tctx;
2593 struct GNUNET_MQ_MessageHandler core_handlers[] = {
2594 GNUNET_MQ_hd_var_size (dht_p2p_get,
2596 struct PeerGetMessage,
2597 t),
2598 GNUNET_MQ_hd_var_size (dht_p2p_put,
2600 struct PeerPutMessage,
2601 t),
2602 GNUNET_MQ_hd_var_size (dht_p2p_result,
2604 struct PeerResultMessage,
2605 t),
2606 GNUNET_MQ_hd_var_size (dht_p2p_hello,
2608 struct GNUNET_MessageHeader,
2609 t),
2611 };
2612 const struct GNUNET_MessageHeader *mh = message;
2613
2614 (void) cls; /* the 'struct GDS_Underlay' */
2615 (void) sctx; /* our receiver address */
2616 if (NULL == t)
2617 {
2618 /* Received message claiming to originate from myself?
2619 Ignore! */
2620 GNUNET_break_op (0);
2621 return;
2622 }
2623 if (message_size < sizeof (*mh))
2624 {
2625 GNUNET_break_op (0);
2626 return;
2627 }
2628 if (message_size != ntohs (mh->size))
2629 {
2630 GNUNET_break_op (0);
2631 return;
2632 }
2634 "Handling message of type %u from peer %s\n",
2635 ntohs (mh->type),
2636 GNUNET_i2s (&t->pi->id));
2637 if (GNUNET_OK !=
2638 GNUNET_MQ_handle_message (core_handlers,
2639 mh))
2640 {
2641 GNUNET_break_op (0);
2642 return;
2643 }
2644}
2645
2646
2654void
2655GDS_try_connect (void *cls,
2656 const struct GNUNET_PeerIdentity *pid,
2657 const char *uri)
2658{
2659 struct GNUNET_HashCode phash;
2660 int peer_bucket;
2661 struct PeerBucket *bucket;
2662 (void) cls;
2663
2664 if (0 == GNUNET_memcmp (&GDS_my_identity,
2665 pid))
2666 {
2668 "Got a HELLO for my own PID, ignoring it\n");
2669 return; /* that's us! */
2670 }
2672 sizeof(*pid),
2673 &phash);
2674 peer_bucket = find_bucket (&phash);
2675 GNUNET_assert ( (peer_bucket >= 0) &&
2676 ((unsigned int) peer_bucket < MAX_BUCKETS));
2677 bucket = &k_buckets[peer_bucket];
2678 for (struct PeerInfo *pi = bucket->head;
2679 NULL != pi;
2680 pi = pi->next)
2681 if (0 ==
2682 GNUNET_memcmp (&pi->id,
2683 pid))
2684 {
2685 /* already connected */
2687 uri);
2688 return;
2689 }
2690 if (bucket->peers_size >= bucket_size)
2691 return; /* do not care */
2693 "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
2694 GNUNET_i2s (pid),
2695 uri,
2696 peer_bucket,
2697 bucket->peers_size,
2698 bucket_size);
2699 /* new peer that we like! */
2701 uri);
2702}
2703
2704
2710void
2712{
2713 for (unsigned int bc = 0; bc<closest_bucket; bc++)
2714 {
2715 struct PeerBucket *bucket = &k_buckets[bc];
2716 unsigned int count = 0;
2717
2718 for (struct PeerInfo *pos = bucket->head;
2719 NULL != pos;
2720 pos = pos->next)
2721 {
2722 if (count >= bucket_size)
2723 break; /* we only consider first #bucket_size entries per bucket */
2724 count++;
2725 do_send (pos,
2726 msg);
2727 }
2728 }
2729}
2730
2731
2734{
2735
2736 unsigned long long temp_config_num;
2737
2740 "DHT",
2741 "DISABLE_TRY_CONNECT");
2742 if (GNUNET_OK ==
2744 "DHT",
2745 "bucket_size",
2746 &temp_config_num))
2747 bucket_size = (unsigned int) temp_config_num;
2750 "DHT",
2751 "CACHE_RESULTS");
2753 GNUNET_YES);
2754 return GNUNET_OK;
2755}
2756
2757
2758void
2760{
2761 if (NULL == all_connected_peers)
2762 return;
2763 GNUNET_assert (0 ==
2766 all_connected_peers = NULL;
2767 GNUNET_assert (NULL == find_peer_task);
2768}
2769
2770
2771struct GNUNET_PeerIdentity *
2773{
2774 return &GDS_my_identity;
2775}
2776
2777
2778/* 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
void 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)
Definition dht_helper.c:178
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:36
void 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, struct GNUNET_CRYPTO_EddsaSignature *sig)
Sign that we are routing a message from pred to succ.
Definition dht_helper.c:151
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 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 unsigned long long reserved
How much space have we currently reserved?
struct GNUNET_PeerIdentity GDS_my_identity
Identity of this peer.
double GDS_NSE_get(void)
Return the current NSE.
struct GNUNET_MessageHeader * GDS_my_hello
Our HELLO.
struct GNUNET_CRYPTO_EddsaPrivateKey GDS_my_private_key
Our private key.
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.
struct GNUNET_HashCode GDS_my_identity_hash
Hash of the identity of this peer.
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...
bool 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)
Handle a reply (route to origin).
static void handle_dht_p2p_result(void *cls, const struct PeerResultMessage *prm)
Core handler for p2p result messages.
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_handle_put(const struct GNUNET_DATACACHE_Block *bd, uint16_t desired_replication_level, uint16_t hop_count, struct GNUNET_CONTAINER_BloomFilter *bf)
Perform a PUT operation.
#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.
struct PeerInfo * GDS_NEIGHBOURS_lookup_peer(const struct GNUNET_PeerIdentity *target)
Lookup peer by peer's identity.
struct GNUNET_PeerIdentity * GDS_NEIGHBOURS_get_id()
Get the ID of the local node.
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 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 void handle_find_local_hello(struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg)
We have received a request for nearby HELLOs.
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.
#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 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.
#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 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 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 unsigned int bucket_size
Maximum size for each bucket.
static void handle_find_my_hello(struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg)
We have received a request for a HELLO.
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 struct PeerBucket k_buckets[sizeof(struct GNUNET_HashCode) *8]
The buckets.
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_init()
Initialize neighbours subsystem.
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.
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_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_SCHEDULER_Task * t
Main task.
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.
#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:1349
@ 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:379
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:997
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:975
#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:523
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_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:980
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:1304
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:1277
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:741
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:587
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:552
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition time.c:640
bool GNUNET_TIME_absolute_is_past(struct GNUNET_TIME_Absolute abs)
Test if abs is truly in the past (excluding now).
Definition time.c:671
static struct GNUNET_TIME_Relative delta
Definition speedup.c:36
const struct GNUNET_HashCode * query_hash
struct GNUNET_BLOCK_Group * bg
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:232
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:136
struct GNUNET_SCHEDULER_Task * next
This is a linked list.
Definition scheduler.c:140
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.
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 52 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 57 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 62 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 67 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 72 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 79 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 92 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 98 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 399 of file gnunet-service-dht_neighbours.c.

400{
401 struct Target *t = cls;
402 struct PeerInfo *pi = t->pi; /* NULL if t->dropped! */
403
404 GNUNET_assert (t->load > 0);
405 t->load--;
406 if (0 < t->load)
407 return;
408 if (t->dropped)
409 {
410 GNUNET_free (t);
411 return;
412 }
413 /* move target back to the front */
415 pi->t_tail,
416 t);
418 pi->t_tail,
419 t);
420}

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

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

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 GDS_NEIGHBOURS_broadcast(), GDS_NEIGHBOURS_handle_get(), GDS_NEIGHBOURS_handle_put(), 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 477 of file gnunet-service-dht_neighbours.c.

478{
479 struct GNUNET_HashCode xor;
480 unsigned int bits;
481
484 &xor);
486 if (bits == MAX_BUCKETS)
487 {
488 /* How can all bits match? Got my own ID? */
489 GNUNET_break (0);
490 return -1;
491 }
492 return MAX_BUCKETS - bits - 1;
493}

References GNUNET_HashCode::bits, GDS_my_identity_hash, GNUNET_break, GNUNET_CRYPTO_hash_count_leading_zeros(), GNUNET_CRYPTO_hash_xor(), 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 506 of file gnunet-service-dht_neighbours.c.

509{
510 struct GNUNET_BLOCK_Group *bg = cls;
511 struct PeerInfo *pi = value;
512
514 &pi->phash,
515 1);
517 "Adding known peer (%s) to Bloom filter for FIND PEER\n",
518 GNUNET_i2s (key));
519 return GNUNET_YES;
520}

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

532{
533 (void) cls;
534
535 /* Compute when to do this again (and if we should
536 even send a message right now) */
537 {
538 struct GNUNET_TIME_Relative next_send_time;
539 bool done_early;
540
541 find_peer_task = NULL;
542 done_early = (newly_found_peers > bucket_size);
543 /* schedule next round, taking longer if we found more peers
544 in the last round. */
545 next_send_time.rel_value_us =
551 1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
555 GNUNET_SCHEDULER_add_delayed (next_send_time,
557 NULL);
558 if (done_early)
559 return;
560 }
561
562 /* actually send 'find peer' request */
563 {
564 struct GNUNET_BLOCK_Group *bg;
565 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
566
569 NULL,
570 0,
571 "seen-set-size",
574 NULL);
577 bg);
578 peer_bf
582 if (GNUNET_OK !=
587 0, /* hop count */
589 NULL, 0, /* xquery */
590 bg,
591 peer_bf))
592 {
594 "# Failed to initiate FIND PEER lookup",
595 1,
596 GNUNET_NO);
597 }
598 else
599 {
601 "# FIND PEER messages initiated",
602 1,
603 GNUNET_NO);
604 }
607 }
608}

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_my_identity_hash, GDS_NEIGHBOURS_handle_get(), 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_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 619 of file gnunet-service-dht_neighbours.c.

620{
621 unsigned int off = 0;
622
623 /* find the peer -- we just go over all of them, should
624 be hardly any more expensive than just finding the 'right'
625 one. */
626 for (struct PeerInfo *pos = bucket->head;
627 NULL != pos;
628 pos = pos->next)
629 {
630 if (off > bucket_size)
631 break; /* We only hold up to #bucket_size peers per bucket */
632 off++;
633 for (struct Target *tp = pos->t_head;
634 NULL != tp;
635 tp = tp->next)
636 if (NULL == tp->ph)
637 tp->ph = GDS_u_hold (tp->u,
638 tp->utarget);
639 }
640}

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

648{
649 struct GDS_Underlay *u = cls;
650 struct PeerInfo *pi;
651 struct PeerBucket *bucket;
652 bool do_hold = false;
653
654 /* Check for connect to self message */
656 pid))
657 return;
659 "Connected to peer %s\n",
660 GNUNET_i2s (pid));
662 pid);
663 if (NULL == pi)
664 {
666 "# peers connected",
667 1,
668 GNUNET_NO);
669 pi = GNUNET_new (struct PeerInfo);
670 pi->id = *pid;
672 sizeof(*pid),
673 &pi->phash);
674 pi->peer_bucket = find_bucket (&pi->phash);
675 GNUNET_assert ( (pi->peer_bucket >= 0) &&
676 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
677 bucket = &k_buckets[pi->peer_bucket];
679 bucket->tail,
680 pi);
681 bucket->peers_size++;
683 (unsigned int) pi->peer_bucket + 1);
686 &pi->id,
687 pi,
689 if (bucket->peers_size <= bucket_size)
690 {
692 do_hold = true;
693 }
696 {
697 /* got a first connection, good time to start with FIND PEER requests... */
700 NULL);
701 }
702 }
703 {
704 struct Target *t;
705
706 t = GNUNET_new (struct Target);
707 t->u = u;
708 t->utarget = target;
709 t->pi = pi;
711 pi->t_tail,
712 t);
713 *ctx = t;
714
715 }
716 if (do_hold)
717 update_hold (bucket);
718}

References all_connected_peers, bucket_size, closest_bucket, ctx, disable_try_connect, find_bucket(), find_peer_task, GDS_my_identity, 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_SCHEDULER_add_now(), GNUNET_STATISTICS_update(), GNUNET_YES, PeerBucket::head, PeerInfo::id, k_buckets, MAX_BUCKETS, 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 722 of file gnunet-service-dht_neighbours.c.

723{
724 struct Target *t = ctx;
725 struct PeerInfo *pi;
726 struct PeerBucket *bucket;
727 bool was_held = false;
728
729 /* Check for disconnect from self message (on shutdown) */
730 if (NULL == t)
731 return;
732 pi = t->pi;
734 pi->t_tail,
735 t);
736 if (NULL != t->ph)
737 {
738 GDS_u_drop (t->u,
739 t->ph);
740 t->ph = NULL;
741 was_held = true;
742 }
743 if (t->load > 0)
744 {
745 t->dropped = true;
746 t->pi = NULL;
747 }
748 else
749 {
750 GNUNET_free (t);
751 }
752 if (NULL != pi->t_head)
753 return; /* got other connections still */
755 "Disconnected from peer %s\n",
756 GNUNET_i2s (&pi->id));
758 "# peers connected",
759 -1,
760 GNUNET_NO);
763 &pi->id,
764 pi));
767 {
769 find_peer_task = NULL;
770 }
771 GNUNET_assert (pi->peer_bucket >= 0);
772 bucket = &k_buckets[pi->peer_bucket];
774 bucket->tail,
775 pi);
776 GNUNET_assert (bucket->peers_size > 0);
777 bucket->peers_size--;
778 if ( (was_held) &&
779 (bucket->peers_size >= bucket_size - 1) )
780 update_hold (bucket);
781 while ( (closest_bucket > 0) &&
784 GNUNET_free (pi->hello);
785 GNUNET_free (pi);
786}

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

800{
801 uint32_t random_value;
802 uint32_t forward_count;
803 float target_value;
804 double rm1;
805
806 if (hop_count > GDS_NSE_get () * 4.0)
807 {
808 /* forcefully terminate */
810 "# requests TTL-dropped",
811 1,
812 GNUNET_NO);
813 return 0;
814 }
815 if (hop_count > GDS_NSE_get () * 2.0)
816 {
817 /* Once we have reached our ideal number of hops, only forward to 1 peer */
818 return 1;
819 }
820 /* bound by system-wide maximum and minimum */
821 if (0 == target_replication)
822 target_replication = 1; /* 0 is verboten */
823 target_replication =
825 target_replication);
826 rm1 = target_replication - 1.0;
827 target_value =
828 1 + (rm1) / (GDS_NSE_get () + (rm1 * hop_count));
829
830 /* Set forward count to floor of target_value */
831 forward_count = (uint32_t) target_value;
832 /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
833 target_value = target_value - forward_count;
835 UINT32_MAX);
836 if (random_value < (target_value * UINT32_MAX))
837 forward_count++;
838 return GNUNET_MIN (forward_count,
840}

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

856{
857 int delta;
859 key))
860 return GNUNET_YES;
861 for (int bucket_num = find_bucket (key);
862 bucket_num < closest_bucket;
863 bucket_num++)
864 {
865 unsigned int count = 0;
866
867 GNUNET_assert (bucket_num >= 0);
868 for (struct PeerInfo *pos = k_buckets[bucket_num].head;
869 NULL != pos;
870 pos = pos->next)
871 {
872 if (count >= bucket_size)
873 break; /* we only consider first #bucket_size entries per bucket */
874 count++;
875 if ( (NULL != bloom) &&
876 (GNUNET_YES ==
878 &pos->phash)) )
879 continue; /* Ignore filtered peers */
880 /* All peers in this bucket must be closer than us, as
881 they mismatch with our PID on the pivotal bit. So
882 because an unfiltered peer exists, we are not the
883 closest. */
884 delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
886 key);
887 switch (delta)
888 {
889 case -1: /* pos closer */
890 return GNUNET_NO;
891 case 0: /* identical, impossible! */
892 GNUNET_assert (0);
893 break;
894 case 1: /* I am closer */
895 break;
896 }
897 }
898 }
899 /* No closer (unfiltered) peers found; we must be the closest! */
900 return GNUNET_YES;
901}

References bucket_size, closest_bucket, delta, find_bucket(), GDS_my_identity_hash, GNUNET_assert, GNUNET_CONTAINER_bloomfilter_test(), GNUNET_CRYPTO_hash_xorcmp(), GNUNET_memcmp, GNUNET_NO, GNUNET_YES, PeerBucket::head, k_buckets, key, and PeerInfo::next.

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

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

References bucket_size, closest_bucket, delta, GDS_my_identity_hash, GDS_NSE_get(), 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_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 1141 of file gnunet-service-dht_neighbours.c.

1146{
1147 unsigned int target;
1148 unsigned int off;
1149 struct PeerInfo **rtargets;
1150
1151 GNUNET_assert (NULL != bloom);
1152 target = get_forward_count (hop_count,
1153 target_replication);
1154 if (0 == target)
1155 {
1156 *targets = NULL;
1157 return 0;
1158 }
1159 rtargets = GNUNET_new_array (target,
1160 struct PeerInfo *);
1161 for (off = 0; off < target; off++)
1162 {
1163 struct PeerInfo *nxt;
1164
1165 nxt = select_peer (key,
1166 bloom,
1167 hop_count);
1168 if (NULL == nxt)
1169 break;
1170 rtargets[off] = nxt;
1171 }
1173 "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1174 off,
1176 (unsigned int) hop_count,
1177 GNUNET_h2s (key),
1178 target);
1179 if (0 == off)
1180 {
1181 GNUNET_free (rtargets);
1182 *targets = NULL;
1183 return 0;
1184 }
1185 *targets = rtargets;
1187 "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1188 GNUNET_h2s (key),
1189 off,
1190 target);
1191 return off;
1192}

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

1202{
1203 struct GNUNET_HELLO_Parser *b;
1204
1206 return;
1207
1209 bd->data_size);
1211 {
1214 NULL);
1215 }
1217}

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:

◆ GDS_NEIGHBOURS_handle_put()

enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_handle_put ( const struct GNUNET_DATACACHE_Block bd,
uint16_t  desired_replication_level,
uint16_t  hop_count,
struct GNUNET_CONTAINER_BloomFilter bf 
)

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

1225{
1226 unsigned int target_count;
1227 struct PeerInfo **targets;
1228 size_t msize;
1229 enum GNUNET_DHT_RouteOption ro = bd->ro;
1230 unsigned int put_path_length = bd->put_path_length;
1231 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1232 bool truncated = (0 != (bd->ro & GNUNET_DHT_RO_TRUNCATED));
1233 const struct GNUNET_PeerIdentity *trunc_peer
1234 = truncated
1235 ? &bd->trunc_peer
1236 : NULL;
1237 struct GNUNET_PeerIdentity trunc_peer_out;
1239
1242 bd->ro, &ro,
1243 bd->expiration_time,
1244 bd->data, bd->data_size,
1245 put_path, put_path_length,
1246 &put_path_length,
1247 trunc_peer,
1248 &trunc_peer_out,
1249 &truncated);
1250 if (truncated)
1251 trunc_peer = &trunc_peer_out;
1252 /* Path may have been truncated by the call above */
1254 "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1256 GNUNET_h2s (&bd->key),
1257 (bd->ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1258 (bd->ro & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1259
1260 /* if we got a HELLO, consider it for our own routing table */
1261 hello_check (bd);
1262 GNUNET_assert (NULL != bf);
1266 "# PUT requests routed",
1267 1,
1268 GNUNET_NO);
1269 if (GNUNET_OK != ret)
1270 return ret;
1271 target_count
1272 = get_target_peers (&bd->key,
1273 bf,
1274 hop_count,
1275 desired_replication_level,
1276 &targets);
1277 if (0 == target_count)
1278 {
1280 "Routing PUT for %s terminates after %u hops at %s\n",
1281 GNUNET_h2s (&bd->key),
1282 (unsigned int) hop_count,
1284 return GNUNET_NO;
1285 }
1286 for (unsigned int i = 0; i < target_count; i++)
1287 {
1288 struct PeerInfo *target = targets[i];
1289
1291 &target->phash);
1292 }
1293 for (unsigned int i = 0; i < target_count; i++)
1294 {
1295 struct PeerInfo *target = targets[i];
1296 struct PeerPutMessage *ppm;
1297 char buf[msize] GNUNET_ALIGN;
1298
1299 ppm = (struct PeerPutMessage *) buf;
1300 GDS_helper_make_put_message (ppm, msize,
1302 &target->id,
1303 &target->phash,
1304 bf,
1305 &bd->key,
1306 ro,
1307 bd->type,
1308 bd->expiration_time,
1309 bd->data, bd->data_size,
1310 put_path, put_path_length,
1311 hop_count,
1313 trunc_peer);
1315 "Routing PUT for %s after %u hops to %s\n",
1316 GNUNET_h2s (&bd->key),
1317 (unsigned int) hop_count,
1318 GNUNET_i2s (&target->id));
1319 do_send (target,
1320 &ppm->header);
1321 }
1322 GNUNET_free (targets);
1324 "# PUT messages queued for transmission",
1325 target_count,
1326 GNUNET_NO);
1327 return GNUNET_OK;
1328}

References GNUNET_DATACACHE_Block::data, GNUNET_DATACACHE_Block::data_size, PeerPutMessage::desired_replication_level, do_send(), GNUNET_DATACACHE_Block::expiration_time, GDS_helper_make_put_message(), GDS_helper_put_message_get_size(), GDS_my_identity, GDS_my_identity_hash, GDS_my_private_key, 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_NO, GNUNET_OK, GNUNET_STATISTICS_update(), PeerPutMessage::header, hello_check(), PeerPutMessage::hop_count, PeerInfo::id, GNUNET_DATACACHE_Block::key, PeerInfo::phash, GNUNET_DATACACHE_Block::put_path, GNUNET_DATACACHE_Block::put_path_length, PeerPutMessage::put_path_length, ret, GNUNET_DATACACHE_Block::ro, 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 1332 of file gnunet-service-dht_neighbours.c.

1341{
1342 unsigned int target_count;
1343 struct PeerInfo **targets;
1344 size_t msize;
1345 size_t result_filter_size;
1346 void *result_filter;
1347
1348 GNUNET_assert (NULL != peer_bf);
1350 "# GET requests routed",
1351 1,
1352 GNUNET_NO);
1353 target_count = get_target_peers (key,
1354 peer_bf,
1355 hop_count,
1356 desired_replication_level,
1357 &targets);
1359 "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1361 GNUNET_h2s (key),
1363 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1364
1367 if (0 == target_count)
1368 {
1370 "Routing GET for %s terminates after %u hops at %s\n",
1371 GNUNET_h2s (key),
1372 (unsigned int) hop_count,
1374 return GNUNET_NO;
1375 }
1376 if (GNUNET_OK !=
1378 &result_filter,
1379 &result_filter_size))
1380 {
1381 result_filter = NULL;
1382 result_filter_size = 0;
1383 }
1384 msize = xquery_size + result_filter_size;
1385 if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1386 {
1387 GNUNET_break (0);
1388 GNUNET_free (result_filter);
1389 GNUNET_free (targets);
1390 return GNUNET_NO;
1391 }
1392 /* update BF */
1393 for (unsigned int i = 0; i < target_count; i++)
1394 {
1395 struct PeerInfo *target = targets[i];
1396
1398 &target->phash);
1399 }
1400 /* forward request */
1401 for (unsigned int i = 0; i < target_count; i++)
1402 {
1403 struct PeerInfo *target = targets[i];
1404 struct PeerGetMessage *pgm;
1405 char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1406 char *rf;
1407
1409 "Routing GET for %s after %u hops to %s\n",
1410 GNUNET_h2s (key),
1411 (unsigned int) hop_count,
1412 GNUNET_i2s (&target->id));
1413 pgm = (struct PeerGetMessage *) buf;
1415 pgm->header.size = htons (sizeof (buf));
1416 pgm->type = htonl (type);
1417 pgm->options = htons (options);
1418 pgm->hop_count = htons (hop_count + 1);
1420 pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1423 pgm->bloomfilter,
1425 pgm->key = *key;
1426 rf = (char *) &pgm[1];
1427 GNUNET_memcpy (rf,
1428 result_filter,
1431 xquery,
1432 xquery_size);
1433 do_send (target,
1434 &pgm->header);
1435 }
1437 "# GET messages queued for transmission",
1438 target_count,
1439 GNUNET_NO);
1440 GNUNET_free (targets);
1441 GNUNET_free (result_filter);
1442 return (0 < target_count) ? GNUNET_OK : GNUNET_NO;
1443}

References PeerGetMessage::bloomfilter, PeerGetMessage::desired_replication_level, DHT_BLOOM_SIZE, do_send(), GDS_my_identity, GDS_my_identity_hash, 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_STATISTICS_update(), PeerGetMessage::header, PeerGetMessage::hop_count, PeerInfo::id, key, PeerGetMessage::key, options, PeerGetMessage::options, PeerInfo::phash, PeerGetMessage::result_filter_size, GNUNET_MessageHeader::size, type, GNUNET_MessageHeader::type, and PeerGetMessage::type.

Referenced by handle_dht_p2p_get(), 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 1447 of file gnunet-service-dht_neighbours.c.

1448{
1450 target);
1451}

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:

◆ GDS_NEIGHBOURS_handle_reply()

bool 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 
)

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

1460{
1461 struct GNUNET_DHT_PathElement *paths;
1462 size_t msize;
1463 unsigned int ppl = bd->put_path_length;
1464 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1465 enum GNUNET_DHT_RouteOption ro = bd->ro;
1466 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1467 const struct GNUNET_PeerIdentity *trunc_peer
1468 = truncated
1469 ? &bd->trunc_peer
1470 : NULL;
1471 bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1472#if SANITY_CHECKS > 1
1473 unsigned int failure_offset;
1474
1475 failure_offset
1477 bd->data_size,
1478 bd->expiration_time,
1479 trunc_peer,
1480 put_path,
1481 ppl,
1482 get_path,
1483 get_path_length,
1485 if (0 != failure_offset)
1486 {
1487 GNUNET_assert (failure_offset <= ppl + get_path_length);
1488 GNUNET_break_op (0);
1489 if (failure_offset < ppl)
1490 {
1491 trunc_peer = &put_path[failure_offset - 1].pred;
1492 put_path += failure_offset;
1493 ppl -= failure_offset;
1494 truncated = true;
1496 }
1497 else
1498 {
1499 failure_offset -= ppl;
1500 if (0 == failure_offset)
1501 trunc_peer = &put_path[ppl - 1].pred;
1502 else
1503 trunc_peer = &get_path[failure_offset - 1].pred;
1504 ppl = 0;
1505 put_path = NULL;
1506 truncated = true;
1508 get_path += failure_offset;
1509 get_path_length -= failure_offset;
1510 }
1511 }
1512#endif
1513 msize = bd->data_size + sizeof (struct PeerResultMessage);
1514 if (msize > GNUNET_MAX_MESSAGE_SIZE)
1515 {
1516 GNUNET_break_op (0);
1517 return false;
1518 }
1519 if (truncated)
1520 msize += sizeof (struct GNUNET_PeerIdentity);
1521 if (tracking)
1522 msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
1523 if (msize < bd->data_size)
1524 {
1525 GNUNET_break_op (0);
1526 return false;
1527 }
1528 if ( (GNUNET_MAX_MESSAGE_SIZE - msize)
1529 / sizeof(struct GNUNET_DHT_PathElement)
1530 < (get_path_length + ppl) )
1531 {
1532 get_path_length = 0;
1533 ppl = 0;
1534 }
1535 if ( (get_path_length > UINT16_MAX) ||
1536 (ppl > UINT16_MAX) )
1537 {
1538 GNUNET_break (0);
1539 get_path_length = 0;
1540 ppl = 0;
1541 }
1542 msize += (get_path_length + ppl)
1543 * sizeof(struct GNUNET_DHT_PathElement);
1545 "Forwarding reply for key %s to peer %s\n",
1546 GNUNET_h2s (query_hash),
1547 GNUNET_i2s (&pi->id));
1549 "# RESULT messages queued for transmission",
1550 1,
1551 GNUNET_NO);
1552 {
1553 struct PeerResultMessage *prm;
1554 char buf[msize] GNUNET_ALIGN;
1555 void *data;
1556
1557 prm = (struct PeerResultMessage *) buf;
1559 prm->header.size = htons (sizeof (buf));
1560 prm->type = htonl ((uint32_t) bd->type);
1561 prm->reserved = htons (0);
1562 prm->options = htons ((uint16_t) ro);
1563 prm->put_path_length = htons ((uint16_t) ppl);
1564 prm->get_path_length = htons ((uint16_t) get_path_length);
1566 prm->key = *query_hash;
1567 if (truncated)
1568 {
1569 void *tgt = &prm[1];
1570
1571 GNUNET_memcpy (tgt,
1572 trunc_peer,
1573 sizeof (struct GNUNET_PeerIdentity));
1574 paths = (struct GNUNET_DHT_PathElement *)
1575 (tgt + sizeof (struct GNUNET_PeerIdentity));
1576 }
1577 else
1578 {
1579 paths = (struct GNUNET_DHT_PathElement *) &prm[1];
1580 }
1581 if (NULL != put_path)
1582 {
1583 GNUNET_memcpy (paths,
1584 put_path,
1585 ppl * sizeof(struct GNUNET_DHT_PathElement));
1586 }
1587 else
1588 {
1589 GNUNET_assert (0 == ppl);
1590 }
1591 if (NULL != get_path)
1592 {
1593 GNUNET_memcpy (&paths[ppl],
1594 get_path,
1595 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
1596 }
1597 else
1598 {
1599 GNUNET_assert (0 == get_path_length);
1600 }
1601 if (tracking)
1602 {
1604 void *tgt = &paths[get_path_length + ppl];
1605 const struct GNUNET_PeerIdentity *pred;
1606
1607 if (ppl + get_path_length > 0)
1608 pred = &paths[ppl + get_path_length - 1].pred;
1609 else if (truncated)
1610 pred = trunc_peer;
1611 else
1612 pred = NULL; /* we are first! */
1613 /* Note that the last signature in 'paths' was not initialized before,
1614 so this is crucial to avoid sending garbage. */
1616 bd->data_size,
1618 bd->expiration_time,
1619 pred,
1620 &pi->id,
1621 &sig);
1622 memcpy (tgt,
1623 &sig,
1624 sizeof (sig));
1625 data = tgt + sizeof (sig);
1627 "Signing GET PATH %u/%u of %s => %s\n",
1628 ppl,
1629 get_path_length,
1630 GNUNET_h2s (query_hash),
1631 GNUNET_B2S (&sig));
1632#if SANITY_CHECKS > 1
1633 {
1634 struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
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 = GDS_my_identity;
1641 if (0 !=
1643 bd->data_size,
1644 bd->expiration_time,
1645 trunc_peer,
1646 paths,
1647 ppl,
1648 xpaths,
1649 get_path_length + 1,
1650 &pi->id))
1651 {
1652 GNUNET_break (0);
1653 return false;
1654 }
1655 }
1656#endif
1657 }
1658 else
1659 {
1660 data = &prm[1];
1661 }
1663 bd->data,
1664 bd->data_size);
1665 do_send (pi,
1666 &prm->header);
1667 }
1668 return true;
1669}

References 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_my_identity, GDS_my_private_key, GDS_stats, PeerResultMessage::get_path_length, GNUNET_ALIGN, GNUNET_assert, GNUNET_B2S, 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_MESSAGE_TYPE_DHT_P2P_RESULT, GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_hton(), PeerResultMessage::header, PeerInfo::id, PeerResultMessage::key, PeerResultMessage::options, GNUNET_DHT_PathElement::pred, GNUNET_DATACACHE_Block::put_path, GNUNET_DATACACHE_Block::put_path_length, PeerResultMessage::put_path_length, PeerResultMessage::reserved, GNUNET_DATACACHE_Block::ro, GNUNET_DHT_PathElement::sig, GNUNET_MessageHeader::size, GNUNET_DATACACHE_Block::trunc_peer, 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 1680 of file gnunet-service-dht_neighbours.c.

1682{
1683 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1684 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1685 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1686 uint16_t msize = ntohs (put->header.size);
1687 uint16_t putlen = ntohs (put->put_path_length);
1688 size_t xsize = (has_path
1689 ? sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1690 : 0)
1691 + (truncated
1692 ? sizeof (struct GNUNET_PeerIdentity)
1693 : 0);
1694 size_t var_meta_size
1695 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1696 + xsize;
1697
1698 (void) cls;
1699 if ( (msize <
1700 sizeof (struct PeerPutMessage) + var_meta_size) ||
1701 (putlen >
1702 (GNUNET_MAX_MESSAGE_SIZE
1703 - sizeof (struct PeerPutMessage)
1704 - xsize)
1705 / sizeof(struct GNUNET_DHT_PathElement)) )
1706 {
1707 GNUNET_break_op (0);
1708 return GNUNET_SYSERR;
1709 }
1710 if (GNUNET_BLOCK_TYPE_ANY == htonl (put->type))
1711 {
1712 GNUNET_break_op (0);
1713 return GNUNET_SYSERR;
1714 }
1715 return GNUNET_OK;
1716}

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.

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

1728{
1729 struct Target *t = cls;
1730 struct PeerInfo *peer = t->pi;
1731 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1732 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1733 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1734 uint16_t msize = ntohs (put->header.size);
1735 uint16_t putlen = ntohs (put->put_path_length);
1736 const struct GNUNET_PeerIdentity *trunc_peer
1737 = truncated
1738 ? (const struct GNUNET_PeerIdentity *) &put[1]
1739 : NULL;
1740 const struct GNUNET_DHT_PathElement *put_path
1741 = truncated
1742 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
1743 : (const struct GNUNET_DHT_PathElement *) &put[1];
1744 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
1745 = has_path
1746 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &put_path[putlen]
1747 : NULL;
1748 const char *data
1749 = has_path
1750 ? (const char *) &last_sig[1]
1751 : (const char *) &put_path[putlen];
1752 size_t var_meta_size
1753 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1754 + (has_path ? sizeof (*last_sig) : 0)
1755 + (truncated ? sizeof (*trunc_peer) : 0);
1756 struct GNUNET_DATACACHE_Block bd = {
1757 .key = put->key,
1758 .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
1759 .type = ntohl (put->type),
1760 .ro = ro,
1761 .data_size = msize - sizeof(*put) - var_meta_size,
1762 .data = data
1763 };
1764
1765 if (NULL != trunc_peer)
1766 bd.trunc_peer = *trunc_peer;
1768 "PUT for `%s' from %s with RO (%s/%s)\n",
1769 GNUNET_h2s (&put->key),
1770 GNUNET_i2s (&peer->id),
1771 (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1772 has_path ? "R" : "-");
1774 {
1776 "# Expired PUTs discarded",
1777 1,
1778 GNUNET_NO);
1779 return;
1780 }
1781 {
1782 /* Only call 'check_block' if that keeps our CPU load (from
1783 the cryptography) below 50% on average */
1784 static struct GNUNET_TIME_Relative avg_latency;
1785 static struct GNUNET_TIME_Absolute next_time;
1786
1787 if (GNUNET_TIME_absolute_is_past (next_time))
1788 {
1789 struct GNUNET_TIME_Absolute now
1791 struct GNUNET_TIME_Relative latency;
1793
1794 if (GNUNET_NO ==
1796 bd.type,
1797 bd.data,
1798 bd.data_size))
1799 {
1800 GNUNET_break_op (0);
1801 return;
1802 }
1803 latency = GNUNET_TIME_absolute_get_duration (now);
1804 /* Use *moving average* to estimate check_block latency */
1805 avg_latency
1808 GNUNET_TIME_relative_multiply (avg_latency,
1809 7),
1810 latency),
1811 8);
1812 /* average delay = 50% of avg_latency => 50% CPU load from crypto (at most) */
1815 avg_latency.rel_value_us > 0
1816 ? avg_latency.rel_value_us
1817 : 1LLU);
1819 }
1820 }
1821 if (! has_path)
1822 putlen = 0;
1824 "# P2P PUT requests received",
1825 1,
1826 GNUNET_NO);
1828 "# P2P PUT bytes received",
1829 msize,
1830 GNUNET_NO);
1831 {
1832 struct GNUNET_HashCode test_key;
1834
1836 bd.type,
1837 bd.data,
1838 bd.data_size,
1839 &test_key);
1840 switch (ret)
1841 {
1842 case GNUNET_YES:
1843 if (0 != GNUNET_memcmp (&test_key,
1844 &bd.key))
1845 {
1846 GNUNET_break_op (0);
1847 return;
1848 }
1849 break;
1850 case GNUNET_NO:
1851 /* cannot verify, good luck */
1852 break;
1853 case GNUNET_SYSERR:
1854 /* block type not supported, good luck */
1855 break;
1856 }
1857 }
1858
1859 {
1861 struct GNUNET_DHT_PathElement pp[putlen + 1];
1862
1868 &peer->phash));
1869 /* extend 'put path' by sender */
1870 bd.put_path = pp;
1871 bd.put_path_length = putlen + 1;
1872 if (has_path)
1873 {
1874 unsigned int failure_offset;
1875
1876 GNUNET_memcpy (pp,
1877 put_path,
1878 putlen * sizeof(struct GNUNET_DHT_PathElement));
1879 pp[putlen].pred = peer->id;
1880 pp[putlen].sig = *last_sig;
1881#if SANITY_CHECKS
1882 /* TODO: might want to eventually implement probabilistic
1883 load-based path verification, but for now it is all or nothing */
1884 failure_offset
1886 bd.data_size,
1887 bd.expiration_time,
1888 trunc_peer,
1889 pp,
1890 putlen + 1,
1891 NULL, 0, /* get_path */
1893#else
1894 failure_offset = 0;
1895#endif
1896 if (0 != failure_offset)
1897 {
1898 GNUNET_break_op (0);
1900 "Recorded put path invalid at offset %u, truncating\n",
1901 failure_offset);
1902 GNUNET_assert (failure_offset <= putlen + 1);
1903 bd.put_path = &pp[failure_offset];
1904 bd.put_path_length = (putlen + 1) - failure_offset;
1906 bd.trunc_peer = pp[failure_offset - 1].pred;
1907 }
1908 }
1909 else
1910 {
1911 bd.put_path_length = 0;
1912 }
1913
1914 /* give to local clients */
1916 &bd.key,
1917 0, NULL /* get path */));
1918
1919 /* store locally */
1920 if ( (0 != (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
1921 (GDS_am_closest_peer (&put->key,
1922 bf)) )
1924 {
1925 enum GNUNET_GenericReturnValue forwarded;
1926
1927 /* route to other peers */
1928 forwarded
1930 ntohs (put->desired_replication_level),
1931 ntohs (put->hop_count),
1932 bf);
1933 /* notify monitoring clients */
1934 bd.ro |= ((GNUNET_OK == forwarded)
1936 : 0);
1938 ntohs (put->hop_count),
1939 ntohs (put->desired_replication_level));
1940 }
1942 }
1943}

References PeerPutMessage::bloomfilter, 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, GDS_am_closest_peer(), GDS_block_context, GDS_CLIENTS_handle_reply(), GDS_CLIENTS_process_put(), GDS_DATACACHE_handle_put(), GDS_my_identity, GDS_NEIGHBOURS_handle_put(), 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_LAST_HOP, 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_NO, GNUNET_OK, 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, 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 
)
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 1963 of file gnunet-service-dht_neighbours.c.

1966{
1967
1968 if (NULL == GDS_my_hello)
1969 {
1971 "# FIND PEER requests ignored due to lack of HELLO",
1972 1,
1973 GNUNET_NO);
1974 }
1975 else if (GNUNET_BLOCK_REPLY_OK_MORE ==
1978 bg,
1980 NULL, 0,
1982 ntohs (GDS_my_hello->size)))
1983 {
1984 struct GNUNET_DATACACHE_Block bd = {
1986 .expiration_time
1989 .key = GDS_my_identity_hash,
1990 .data = GDS_my_hello,
1991 .data_size = ntohs (GDS_my_hello->size)
1992 };
1993
1995 &bd,
1996 query_hash,
1997 0, NULL /* get path */));
1998 }
1999 else
2000 {
2002 "# FIND PEER requests ignored due to Bloomfilter",
2003 1,
2004 GNUNET_NO);
2005 }
2006}

References GDS_block_context, GDS_my_hello, GDS_my_identity_hash, GDS_NEIGHBOURS_handle_reply(), GDS_stats, GNUNET_BLOCK_check_reply(), GNUNET_BLOCK_REPLY_OK_MORE, GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_break, GNUNET_HELLO_ADDRESS_EXPIRATION, GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_TIME_relative_to_absolute(), GNUNET_MessageHeader::size, 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 
)
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 2018 of file gnunet-service-dht_neighbours.c.

2021{
2022 /* Force non-random selection by hop count */
2023 struct PeerInfo *peer;
2024
2025 peer = select_peer (query_hash,
2026 NULL,
2027 GDS_NSE_get () + 1);
2028 if ( (NULL != peer->hello) &&
2034 bg,
2035 &peer->phash,
2036 NULL, 0, /* xquery */
2037 peer->hello,
2038 peer->hello_size)) )
2039 {
2040 struct GNUNET_DATACACHE_Block bd = {
2042 .expiration_time = peer->hello_expiration,
2043 .key = peer->phash,
2044 .data = peer->hello,
2045 .data_size = peer->hello_size
2046 };
2047
2049 &bd,
2050 query_hash,
2051 0, NULL /* get path */));
2052 }
2053}

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_break, GNUNET_TIME_absolute_is_past(), PeerInfo::hello, PeerInfo::hello_expiration, PeerInfo::hello_size, PeerInfo::phash, select_peer(), 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_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 2063 of file gnunet-service-dht_neighbours.c.

2065{
2066 struct PeerInfo *peer = cls;
2067
2069 bd,
2070 &bd->key,
2071 0, NULL /* get path */));
2072}

References GDS_NEIGHBOURS_handle_reply(), GNUNET_break, and GNUNET_DATACACHE_Block::key.

Referenced by handle_dht_p2p_get().

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

2085{
2086 uint16_t msize = ntohs (get->header.size);
2087 uint16_t result_filter_size = ntohs (get->result_filter_size);
2088
2089 (void) cls;
2090 if (msize < sizeof(*get) + result_filter_size)
2091 {
2092 GNUNET_break_op (0);
2093 return GNUNET_SYSERR;
2094 }
2095 return GNUNET_OK;
2096}

References get, GNUNET_break_op, GNUNET_OK, and GNUNET_SYSERR.

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

2108{
2109 struct Target *t = cls;
2110 struct PeerInfo *peer = t->pi;
2111 uint16_t msize = ntohs (get->header.size);
2112 uint16_t result_filter_size = ntohs (get->result_filter_size);
2113 uint16_t hop_count = ntohs (get->hop_count);
2114 enum GNUNET_BLOCK_Type type = ntohl (get->type);
2115 enum GNUNET_DHT_RouteOption options = ntohs (get->options);
2117 const void *result_filter = (const void *) &get[1];
2118 const void *xquery = result_filter + result_filter_size;
2119 size_t xquery_size = msize - sizeof (*get) - result_filter_size;
2120
2121 /* parse and validate message */
2123 "# P2P GET requests received",
2124 1,
2125 GNUNET_NO);
2127 "# P2P GET bytes received",
2128 msize,
2129 GNUNET_NO);
2130 if (GNUNET_NO ==
2132 type,
2133 &get->key,
2134 xquery,
2135 xquery_size))
2136 {
2137 /* request invalid */
2138 GNUNET_break_op (0);
2139 return;
2140 }
2141
2142 {
2143 struct GNUNET_BLOCK_Group *bg;
2144 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
2145
2146 peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2149 ;
2152 &peer->phash));
2154 type,
2155 result_filter,
2156 result_filter_size,
2157 "filter-size",
2158 result_filter_size,
2159 NULL);
2161 "GET for %s at %s after %u hops\n",
2162 GNUNET_h2s (&get->key),
2164 (unsigned int) hop_count);
2165 /* local lookup (this may update the bg) */
2167 (GDS_am_closest_peer (&get->key,
2168 peer_bf)) )
2169 {
2172 {
2174 "# P2P HELLO lookup requests processed",
2175 1,
2176 GNUNET_NO);
2178 &get->key,
2179 bg);
2182 &get->key,
2183 bg);
2184 }
2186 {
2188 eval = GDS_DATACACHE_get_closest (&get->key,
2189 type,
2190 xquery,
2191 xquery_size,
2192 bg,
2194 peer);
2195 else
2196 eval = GDS_DATACACHE_handle_get (&get->key,
2197 type,
2198 xquery,
2199 xquery_size,
2200 bg,
2202 peer);
2203 }
2204 }
2205 else
2206 {
2208 "# P2P GET requests ONLY routed",
2209 1,
2210 GNUNET_NO);
2211 }
2212
2213 /* remember request for routing replies
2214 TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2215 */
2216 GDS_ROUTING_add (&peer->id,
2217 type,
2218 bg, /* bg now owned by routing, but valid at least until end of this function! */
2219 options,
2220 &get->key,
2221 xquery,
2222 xquery_size);
2223
2224 /* P2P forwarding */
2225 {
2226 bool forwarded = false;
2227 uint16_t desired_replication_level = ntohs (
2228 get->desired_replication_level);
2229
2230 if (eval != GNUNET_BLOCK_REPLY_OK_LAST)
2231 forwarded = (GNUNET_OK ==
2233 options,
2234 desired_replication_level,
2235 hop_count,
2236 &get->key,
2237 xquery,
2238 xquery_size,
2239 bg,
2240 peer_bf));
2242 options
2243 | (forwarded
2244 ? 0
2246 type,
2247 hop_count,
2248 desired_replication_level,
2249 &get->key);
2250 }
2251 /* clean up; note that 'bg' is owned by routing now! */
2253 }
2254}

References DHT_BLOOM_SIZE, GDS_am_closest_peer(), GDS_block_context, GDS_CLIENTS_process_get(), GDS_DATACACHE_get_closest(), GDS_DATACACHE_handle_get(), GDS_my_identity, GDS_NEIGHBOURS_handle_get(), GDS_ROUTING_add(), GDS_stats, get, GNUNET_BLOCK_check_query(), GNUNET_BLOCK_group_create(), GNUNET_BLOCK_REPLY_OK_LAST, GNUNET_BLOCK_REPLY_OK_MORE, GNUNET_BLOCK_TYPE_ANY, GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_break_op, GNUNET_CONSTANTS_BLOOMFILTER_K, GNUNET_CONTAINER_bloomfilter_free(), GNUNET_CONTAINER_bloomfilter_init(), GNUNET_CONTAINER_bloomfilter_test(), GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, GNUNET_DHT_RO_FIND_APPROXIMATE, GNUNET_DHT_RO_LAST_HOP, GNUNET_ERROR_TYPE_DEBUG, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_OK, GNUNET_STATISTICS_update(), GNUNET_YES, handle_find_local_hello(), handle_find_my_hello(), handle_local_result(), PeerInfo::id, options, PeerInfo::phash, t, and type.

Here is the call graph for this function:

◆ process_reply_with_path()

static bool 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
Returns
true on success

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

2271{
2272 /* forward to local clients */
2274 "Forwarding reply to local clients\n");
2275 if (! GDS_CLIENTS_handle_reply (bd,
2276 query_hash,
2277 get_path_length,
2278 get_path))
2279 {
2280 GNUNET_break (0);
2281 return false;
2282 }
2284 get_path,
2285 get_path_length);
2287 {
2288 struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2289 + bd->put_path_length)];
2290 struct GNUNET_DATACACHE_Block bdx = *bd;
2291
2292 if (NULL != bd->put_path)
2293 GNUNET_memcpy (xput_path,
2294 bd->put_path,
2295 bd->put_path_length * sizeof(struct
2297 GNUNET_memcpy (&xput_path[bd->put_path_length],
2298 get_path,
2299 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2300 bdx.put_path = xput_path;
2301 bdx.put_path_length += get_path_length;
2303 }
2304 /* forward to other peers */
2306 query_hash,
2307 get_path_length,
2308 get_path);
2309 return true;
2310}

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

2323{
2324 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2325 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2326 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2327 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2328
2329 uint16_t get_path_length = ntohs (prm->get_path_length);
2330 uint16_t put_path_length = ntohs (prm->put_path_length);
2331 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2332 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2333
2334 (void) cls;
2335 if ( (msize < vsize) ||
2336 (msize - vsize <
2337 (get_path_length + put_path_length)
2338 * sizeof(struct GNUNET_DHT_PathElement)) ||
2339 (get_path_length >
2340 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2341 (put_path_length >
2342 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2343 {
2344 GNUNET_break_op (0);
2345 return GNUNET_SYSERR;
2346 }
2347 return GNUNET_OK;
2348}

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

2360{
2361 struct Target *t = cls;
2362 struct PeerInfo *peer = t->pi;
2363 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2364 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2365 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2366 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2367 uint16_t get_path_length = ntohs (prm->get_path_length);
2368 uint16_t put_path_length = ntohs (prm->put_path_length);
2369 const struct GNUNET_PeerIdentity *trunc_peer
2370 = truncated
2371 ? (const struct GNUNET_PeerIdentity *) &prm[1]
2372 : NULL;
2373 const struct GNUNET_DHT_PathElement *put_path
2374 = truncated
2375 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2376 : (const struct GNUNET_DHT_PathElement *) &prm[1];
2377 const struct GNUNET_DHT_PathElement *get_path
2378 = &put_path[put_path_length];
2379 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2380 = tracked
2381 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &get_path[get_path_length]
2382 : NULL;
2383 const void *data
2384 = tracked
2385 ? (const void *) &last_sig[1]
2386 : (const void *) &get_path[get_path_length];
2387 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2388 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2389 struct GNUNET_DATACACHE_Block bd = {
2391 .put_path = put_path,
2392 .put_path_length = put_path_length,
2393 .key = prm->key,
2394 .type = ntohl (prm->type),
2395 .ro = ro,
2396 .data = data,
2397 .data_size = msize - vsize - (get_path_length + put_path_length)
2398 * sizeof(struct GNUNET_DHT_PathElement)
2399 };
2400
2401 /* parse and validate message */
2402 if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
2403 {
2405 "# Expired results discarded",
2406 1,
2407 GNUNET_NO);
2408 return;
2409 }
2410 if (GNUNET_OK !=
2412 bd.type,
2413 bd.data,
2414 bd.data_size))
2415 {
2416 GNUNET_break_op (0);
2417 return;
2418 }
2420 "# P2P RESULTS received",
2421 1,
2422 GNUNET_NO);
2424 "# P2P RESULT bytes received",
2425 msize,
2426 GNUNET_NO);
2427 {
2429
2431 bd.type,
2432 bd.data,
2433 bd.data_size,
2434 &bd.key);
2435 if (GNUNET_NO == ret)
2436 bd.key = prm->key;
2437 }
2438
2439 /* if we got a HELLO, consider it for our own routing table */
2440 hello_check (&bd);
2441
2442 /* Need to append 'peer' to 'get_path' */
2443 if (tracked)
2444 {
2445 struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2446 struct GNUNET_DHT_PathElement *gp = xget_path;
2447 unsigned int failure_offset;
2448
2449 GNUNET_memcpy (xget_path,
2450 get_path,
2451 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2452 xget_path[get_path_length].pred = peer->id;
2453 /* use memcpy(), as last_sig may not be aligned */
2454 memcpy (&xget_path[get_path_length].sig,
2455 last_sig,
2456 sizeof (*last_sig));
2457#if SANITY_CHECKS
2458 /* TODO: might want to eventually implement probabilistic
2459 load-based path verification, but for now it is all or nothing */
2460 failure_offset
2461 = GNUNET_DHT_verify_path (bd.data,
2462 bd.data_size,
2463 bd.expiration_time,
2464 trunc_peer,
2465 put_path,
2466 put_path_length,
2467 gp,
2468 get_path_length + 1,
2470#else
2471 failure_offset = 0;
2472#endif
2473 if (0 != failure_offset)
2474 {
2476 "Recorded path invalid at offset %u, truncating\n",
2477 failure_offset);
2478 GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length
2479 + 1);
2480 if (failure_offset < bd.put_path_length)
2481 {
2482 /* failure on put path */
2483 trunc_peer = &bd.put_path[failure_offset - 1].pred;
2484 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2485 bd.put_path = &bd.put_path[failure_offset];
2486 bd.put_path_length -= failure_offset;
2487 truncated = true;
2488 }
2489 else
2490 {
2491 /* failure on get path */
2492 failure_offset -= bd.put_path_length;
2493 if (0 == failure_offset)
2494 trunc_peer = &bd.put_path[bd.put_path_length - 1].pred;
2495 else
2496 trunc_peer = &gp[failure_offset - 1].pred;
2497 get_path_length -= failure_offset;
2498 gp = &gp[failure_offset];
2499 bd.put_path_length = 0;
2500 bd.put_path = NULL;
2501 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2502 truncated = true;
2503 }
2504 }
2506 "Extending GET path of length %u with %s\n",
2507 get_path_length,
2508 GNUNET_i2s (&peer->id));
2509 if (truncated)
2510 {
2511 GNUNET_assert (NULL != trunc_peer);
2512 bd.trunc_peer = *trunc_peer;
2513 }
2515 &prm->key,
2516 get_path_length + 1,
2517 gp));
2518 }
2519 else
2520 {
2521 if (truncated)
2522 {
2523 GNUNET_assert (NULL != trunc_peer);
2524 bd.trunc_peer = *trunc_peer;
2525 }
2527 &prm->key,
2528 0,
2529 NULL));
2530 }
2531}

References data, GNUNET_DATACACHE_Block::expiration_time, PeerResultMessage::expiration_time, GDS_block_context, GDS_my_identity, GDS_stats, PeerResultMessage::get_path_length, GNUNET_assert, GNUNET_BLOCK_check_block(), GNUNET_BLOCK_get_key(), GNUNET_break, 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_STATISTICS_update(), GNUNET_TIME_absolute_is_past(), GNUNET_TIME_absolute_ntoh(), PeerResultMessage::header, hello_check(), PeerInfo::id, PeerResultMessage::key, 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 2542 of file gnunet-service-dht_neighbours.c.

2544{
2545 struct Target *t = cls;
2546 struct PeerInfo *peer = t->pi;
2548 size_t hellob_size;
2549 void *hellob;
2551
2553 &peer->id,
2554 &hellob,
2555 &hellob_size,
2556 &expiration);
2557 GNUNET_free (hellob);
2558 return ret;
2559}

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

2571{
2572 struct Target *t = cls;
2573 struct PeerInfo *peer = t->pi;
2574
2575 GNUNET_free (peer->hello);
2576 peer->hello_size = 0;
2579 &peer->id,
2580 &peer->hello,
2581 &peer->hello_size,
2582 &peer->hello_expiration));
2583}

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

2592{
2593 struct Target *t = *tctx;
2594 struct GNUNET_MQ_MessageHandler core_handlers[] = {
2595 GNUNET_MQ_hd_var_size (dht_p2p_get,
2597 struct PeerGetMessage,
2598 t),
2599 GNUNET_MQ_hd_var_size (dht_p2p_put,
2601 struct PeerPutMessage,
2602 t),
2603 GNUNET_MQ_hd_var_size (dht_p2p_result,
2605 struct PeerResultMessage,
2606 t),
2607 GNUNET_MQ_hd_var_size (dht_p2p_hello,
2609 struct GNUNET_MessageHeader,
2610 t),
2612 };
2613 const struct GNUNET_MessageHeader *mh = message;
2614
2615 (void) cls; /* the 'struct GDS_Underlay' */
2616 (void) sctx; /* our receiver address */
2617 if (NULL == t)
2618 {
2619 /* Received message claiming to originate from myself?
2620 Ignore! */
2621 GNUNET_break_op (0);
2622 return;
2623 }
2624 if (message_size < sizeof (*mh))
2625 {
2626 GNUNET_break_op (0);
2627 return;
2628 }
2629 if (message_size != ntohs (mh->size))
2630 {
2631 GNUNET_break_op (0);
2632 return;
2633 }
2635 "Handling message of type %u from peer %s\n",
2636 ntohs (mh->type),
2637 GNUNET_i2s (&t->pi->id));
2638 if (GNUNET_OK !=
2639 GNUNET_MQ_handle_message (core_handlers,
2640 mh))
2641 {
2642 GNUNET_break_op (0);
2643 return;
2644 }
2645}

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

2659{
2660 struct GNUNET_HashCode phash;
2661 int peer_bucket;
2662 struct PeerBucket *bucket;
2663 (void) cls;
2664
2665 if (0 == GNUNET_memcmp (&GDS_my_identity,
2666 pid))
2667 {
2669 "Got a HELLO for my own PID, ignoring it\n");
2670 return; /* that's us! */
2671 }
2673 sizeof(*pid),
2674 &phash);
2675 peer_bucket = find_bucket (&phash);
2676 GNUNET_assert ( (peer_bucket >= 0) &&
2677 ((unsigned int) peer_bucket < MAX_BUCKETS));
2678 bucket = &k_buckets[peer_bucket];
2679 for (struct PeerInfo *pi = bucket->head;
2680 NULL != pi;
2681 pi = pi->next)
2682 if (0 ==
2683 GNUNET_memcmp (&pi->id,
2684 pid))
2685 {
2686 /* already connected */
2688 uri);
2689 return;
2690 }
2691 if (bucket->peers_size >= bucket_size)
2692 return; /* do not care */
2694 "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
2695 GNUNET_i2s (pid),
2696 uri,
2697 peer_bucket,
2698 bucket->peers_size,
2699 bucket_size);
2700 /* new peer that we like! */
2702 uri);
2703}

References bucket_size, find_bucket(), GDS_my_identity, GDS_u_try_connect(), GNUNET_assert, GNUNET_CRYPTO_hash(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_i2s(), GNUNET_log, GNUNET_memcmp, PeerBucket::head, k_buckets, MAX_BUCKETS, 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 2712 of file gnunet-service-dht_neighbours.c.

2713{
2714 for (unsigned int bc = 0; bc<closest_bucket; bc++)
2715 {
2716 struct PeerBucket *bucket = &k_buckets[bc];
2717 unsigned int count = 0;
2718
2719 for (struct PeerInfo *pos = bucket->head;
2720 NULL != pos;
2721 pos = pos->next)
2722 {
2723 if (count >= bucket_size)
2724 break; /* we only consider first #bucket_size entries per bucket */
2725 count++;
2726 do_send (pos,
2727 msg);
2728 }
2729 }
2730}

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

2735{
2736
2737 unsigned long long temp_config_num;
2738
2741 "DHT",
2742 "DISABLE_TRY_CONNECT");
2743 if (GNUNET_OK ==
2745 "DHT",
2746 "bucket_size",
2747 &temp_config_num))
2748 bucket_size = (unsigned int) temp_config_num;
2751 "DHT",
2752 "CACHE_RESULTS");
2754 GNUNET_YES);
2755 return GNUNET_OK;
2756}

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

struct GNUNET_PeerIdentity * GDS_NEIGHBOURS_get_id ( void  )

Get the ID of the local node.

Returns
identity of the local node

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

2774{
2775 return &GDS_my_identity;
2776}

References GDS_my_identity.

Variable Documentation

◆ cache_results

int cache_results
static

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

Definition at line 351 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 356 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 362 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 367 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 372 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 378 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 388 of file gnunet-service-dht_neighbours.c.

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