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

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

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

Go to the source code of this file.

Data Structures

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

Macros

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

Functions

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

Variables

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

Detailed Description

GNUnet DHT service's bucket and neighbour management code.

Author
Christian Grothoff
Nathan Evans

Definition in file gnunet-service-dht_neighbours.c.

Macro Definition Documentation

◆ LOG_TRAFFIC

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

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

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

◆ SANITY_CHECKS

#define SANITY_CHECKS   2

Enable slow sanity checks to debug issues.

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

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

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

◆ MAX_BUCKETS

#define MAX_BUCKETS   sizeof(struct GNUNET_HashCode) * 8

How many buckets will we allow in total.

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

◆ DEFAULT_BUCKET_SIZE

#define DEFAULT_BUCKET_SIZE   8

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

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

◆ FIND_PEER_REPLICATION_LEVEL

#define FIND_PEER_REPLICATION_LEVEL   4

Desired replication level for FIND PEER requests.

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

◆ MAXIMUM_PENDING_PER_PEER

#define MAXIMUM_PENDING_PER_PEER   64

Maximum allowed number of pending messages per peer.

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

◆ DHT_MINIMUM_FIND_PEER_INTERVAL

#define DHT_MINIMUM_FIND_PEER_INTERVAL
Value:
#define GNUNET_TIME_UNIT_MINUTES
One minute.

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

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

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

◆ DHT_AVG_FIND_PEER_INTERVAL

#define DHT_AVG_FIND_PEER_INTERVAL
Value:
#define GNUNET_TIME_UNIT_SECONDS
One second.

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

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

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

◆ GET_TIMEOUT

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

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

Function Documentation

◆ send_done_cb()

static void send_done_cb ( void *  cls)
static

Function called whenever we finished sending to a target.

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

Parameters
clsa struct Target *

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

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

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

Referenced by do_send().

Here is the caller graph for this function:

◆ do_send()

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

Send msg to pi.

Parameters
piwhere to send the message
msgmessage to send
Returns
true if the message was handed to an underlay, false if it was dropped because no target of pi could take it

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

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

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

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

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

◆ find_bucket()

static int find_bucket ( const struct GNUNET_HashCode hc)
static

Find the optimal bucket for this key.

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

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

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

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

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

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

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

◆ add_known_to_bloom()

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

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

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

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

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

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

547{
548 (void) cls;
549
550 /* Compute when to do this again (and if we should
551 even send a message right now) */
552 {
553 struct GNUNET_TIME_Relative next_send_time;
554 bool done_early;
555
556 find_peer_task = NULL;
557 done_early = (newly_found_peers > bucket_size);
558 /* schedule next round, taking longer if we found more peers
559 in the last round. */
560 next_send_time.rel_value_us =
565 1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
569 GNUNET_SCHEDULER_add_delayed (next_send_time,
571 NULL);
572 if (done_early)
573 return;
574 }
575
576 /* actually send 'find peer' request */
577 {
578 const struct GNUNET_HashCode *my_identity_hash;
579 struct GNUNET_BLOCK_Group *bg;
580 struct GNUNET_CONTAINER_BloomFilter *peer_bf;
581
582 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
583 GNUNET_assert (NULL != my_identity_hash);
584
587 NULL,
588 0,
589 "seen-set-size",
592 NULL);
595 bg);
596 peer_bf
600 if (GNUNET_OK !=
605 0, /* hop count */
606 my_identity_hash,
607 NULL, 0, /* xquery */
608 bg,
609 peer_bf))
610 {
612 "# Failed to initiate FIND PEER lookup",
613 1,
614 GNUNET_NO);
615 }
616 else
617 {
619 "# FIND PEER messages initiated",
620 1,
621 GNUNET_NO);
622 }
625 }
626}

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

Referenced by GDS_u_connect(), and send_find_peer_message().

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

◆ update_hold()

static void update_hold ( struct PeerBucket bucket)
static

The list of the first bucket_size peers of bucket changed.

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

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

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

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

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

666{
667 const struct GNUNET_PeerIdentity *my_identity;
668 struct GDS_Underlay *u = cls;
669 struct PeerInfo *pi;
670 struct PeerBucket *bucket;
671 bool do_hold = false;
672
674 GNUNET_assert (NULL != my_identity);
675
676 /* Check for connect to self message */
677 if (0 == GNUNET_memcmp (my_identity, pid))
678 return;
680 "Connected to peer %s\n",
681 GNUNET_i2s (pid));
683 pid);
684 if (NULL == pi)
685 {
687 "# peers connected",
688 1,
689 GNUNET_NO);
690 pi = GNUNET_new (struct PeerInfo);
691 pi->id = *pid;
693 sizeof(*pid),
694 &pi->phash);
695 pi->peer_bucket = find_bucket (&pi->phash);
696 GNUNET_assert ( (pi->peer_bucket >= 0) &&
697 ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
698 bucket = &k_buckets[pi->peer_bucket];
700 bucket->tail,
701 pi);
702 bucket->peers_size++;
704 (unsigned int) pi->peer_bucket + 1);
707 &pi->id,
708 pi,
710 if (bucket->peers_size <= bucket_size)
711 {
713 do_hold = true;
714 }
717 {
718 /* got a first connection, good time to start with FIND PEER requests... */
721 NULL);
722 }
723 /* A pending GET that found no route is sitting on an exponential
724 back-off of up to 15 minutes; now that we have somewhere to send
725 it, do so immediately. A PUT that found no route was not sent at
726 all and nothing else will ever send it. */
729 }
730 {
731 struct Target *t;
732
733 t = GNUNET_new (struct Target);
734 t->u = u;
735 t->utarget = target;
736 t->pi = pi;
738 pi->t_tail,
739 t);
740 *ctx = t;
741
742 }
743 if (do_hold)
744 update_hold (bucket);
745}

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

Referenced by load_underlay().

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

◆ GDS_u_disconnect()

void GDS_u_disconnect ( void *  ctx)

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

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

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

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

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

827{
828 uint32_t random_value;
829 uint32_t forward_count;
830 float target_value;
831 double rm1;
832 double nse = GDS_NSE_get ();
833
834 /* Guard the divisor below: an NSE of zero would make target_value
835 infinite (or NaN), and the conversion to uint32_t undefined. */
836 if (! (nse >= MINIMUM_LOG_NSE))
838 if (hop_count > nse * 4.0)
839 {
840 /* forcefully terminate */
842 "# requests TTL-dropped",
843 1,
844 GNUNET_NO);
845 return 0;
846 }
847 if (hop_count > nse * 2.0)
848 {
849 /* Once we have reached our ideal number of hops, only forward to 1 peer */
850 return 1;
851 }
852 /* bound by system-wide maximum and minimum */
853 if (0 == target_replication)
854 target_replication = 1; /* 0 is verboten */
855 target_replication =
857 target_replication);
858 rm1 = target_replication - 1.0;
859 target_value =
860 1 + (rm1) / (nse + (rm1 * hop_count));
861
862 /* Set forward count to floor of target_value */
863 forward_count = (uint32_t) target_value;
864 /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
865 target_value = target_value - forward_count;
866 random_value = GNUNET_CRYPTO_random_u32 (UINT32_MAX);
867 if (random_value < (target_value * UINT32_MAX))
868 forward_count++;
869 return GNUNET_MIN (forward_count,
871}

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

Referenced by get_target_peers().

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

◆ GDS_am_closest_peer()

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

Check whether my identity is closer than any known peers.

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

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

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

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

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

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

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

◆ select_peer()

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

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

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

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

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

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

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

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

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

Referenced by get_target_peers(), and handle_find_local_hello().

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

◆ get_target_peers()

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

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

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

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

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

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

Referenced by GDS_NEIGHBOURS_handle_get(), and GDS_NEIGHBOURS_handle_put().

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

◆ hello_check()

static void hello_check ( const struct GNUNET_DATACACHE_Block bd)
static

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

Parameters
bdblock data we got

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

1249{
1250 struct GNUNET_HELLO_Parser *b;
1251
1253 return;
1254
1256 bd->data_size);
1258 {
1261 NULL);
1262 }
1264}

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

Referenced by GDS_NEIGHBOURS_handle_put(), and handle_dht_p2p_result().

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

◆ cb_routing_put_message()

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

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

1289{
1290 struct GDS_RoutingPutCallbackData *gds_routing = cls;
1291 struct PeerInfo *target;
1292
1293 if (NULL == ppm)
1294 {
1295 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1296 if (*(gds_routing->queued) >= gds_routing->target_count)
1297 {
1298 if (gds_routing->cb)
1299 gds_routing->cb (gds_routing->cb_cls,
1300 *(gds_routing->sent)
1301 ? GNUNET_OK
1302 : GNUNET_SYSERR);
1303
1304 GNUNET_free (gds_routing->targets);
1305 GNUNET_free (gds_routing->queued);
1306 GNUNET_free (gds_routing->sent);
1307 }
1308
1309 return true;
1310 }
1311
1312 target = gds_routing->targets[gds_routing->index];
1313
1315 "Routing PUT for %s after %u hops to %s\n",
1316 GNUNET_h2s (&(gds_routing->key)),
1317 (unsigned int) gds_routing->hop_count,
1318 GNUNET_i2s (&target->id));
1319 if (do_send (target,
1320 &ppm->header))
1321 *(gds_routing->sent) = true;
1322 *(gds_routing->queued) = *(gds_routing->queued) + 1;
1323
1324 if (*(gds_routing->queued) >= gds_routing->target_count)
1325 {
1326 /* Report success only if some underlay actually took the message:
1327 otherwise nothing stores this block and the caller has to keep
1328 it and try again. */
1329 if (gds_routing->cb)
1330 gds_routing->cb (gds_routing->cb_cls,
1331 *(gds_routing->sent)
1332 ? GNUNET_OK
1333 : GNUNET_NO);
1334
1335 GNUNET_free (gds_routing->targets);
1337 "# PUT messages queued for transmission",
1338 gds_routing->target_count,
1339 GNUNET_NO);
1340 GNUNET_free (gds_routing->queued);
1341 GNUNET_free (gds_routing->sent);
1342 }
1343
1344 return true;
1345}

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

Referenced by GDS_NEIGHBOURS_handle_put().

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

◆ GDS_NEIGHBOURS_handle_put()

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

Perform a PUT operation.

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

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

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

1355{
1356 const struct GNUNET_PeerIdentity *my_identity;
1357 const struct GNUNET_HashCode *my_identity_hash;
1358 struct GDS_RoutingPutCallbackData gds_routing;
1359 size_t msize;
1360 enum GNUNET_DHT_RouteOption ro = bd->ro;
1361 unsigned int put_path_length = bd->put_path_length;
1362 const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1363 bool truncated = (0 != (bd->ro & GNUNET_DHT_RO_TRUNCATED));
1364 const struct GNUNET_PeerIdentity *trunc_peer
1365 = truncated
1366 ? &bd->trunc_peer
1367 : NULL;
1368 struct GNUNET_PeerIdentity trunc_peer_out;
1370
1372 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1373 GNUNET_assert (NULL != my_identity);
1374
1377 bd->ro, &ro,
1378 bd->expiration_time,
1379 bd->data, bd->data_size,
1380 put_path, put_path_length,
1381 &put_path_length,
1382 trunc_peer,
1383 &trunc_peer_out,
1384 &truncated);
1385 if (truncated)
1386 trunc_peer = &trunc_peer_out;
1387 /* Path may have been truncated by the call above */
1389 "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1391 GNUNET_h2s (&bd->key),
1392 (bd->ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1393 (bd->ro & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1394
1395 /* if we got a HELLO, consider it for our own routing table */
1396 hello_check (bd);
1397 GNUNET_assert ((NULL != bf) && (NULL != my_identity_hash));
1398 GNUNET_CONTAINER_bloomfilter_add (bf, my_identity_hash);
1400 "# PUT requests routed",
1401 1,
1402 GNUNET_NO);
1403 if (GNUNET_OK != ret)
1404 {
1405 if (cb)
1406 cb (cb_cls, ret);
1407 return;
1408 }
1409 gds_routing.target_count
1410 = get_target_peers (&bd->key,
1411 bf,
1412 hop_count,
1413 desired_replication_level,
1414 &(gds_routing.targets));
1415 if (0 == gds_routing.target_count)
1416 {
1418 "Routing PUT for %s terminates after %u hops at %s\n",
1419 GNUNET_h2s (&bd->key),
1420 (unsigned int) hop_count,
1422 if (cb)
1423 cb (cb_cls, GNUNET_NO);
1424 if (gds_routing.targets)
1425 GNUNET_free (gds_routing.targets);
1426 return;
1427 }
1428 GNUNET_memcpy (&(gds_routing.key), &(bd->key),
1429 sizeof (gds_routing.key));
1430 gds_routing.hop_count = hop_count;
1431 /* targets were added to @a bf by get_target_peers() */
1432
1433 gds_routing.queued = GNUNET_new (unsigned int);
1434 *(gds_routing.queued) = 0;
1435 gds_routing.sent = GNUNET_new (bool);
1436 *(gds_routing.sent) = false;
1437
1438 gds_routing.cb = cb;
1439 gds_routing.cb_cls = cb_cls;
1440
1441 for (unsigned int i = 0; i < gds_routing.target_count; i++)
1442 {
1443 struct PeerInfo *target = gds_routing.targets[i];
1444 struct PeerPutMessage *ppm;
1445 char buf[msize] GNUNET_ALIGN;
1446
1447 gds_routing.index = i;
1448
1449 ppm = (struct PeerPutMessage *) buf;
1450 GDS_helper_make_put_message (ppm, msize,
1452 &target->id,
1453 &target->phash,
1454 bf,
1455 &bd->key,
1456 ro,
1457 bd->type,
1458 bd->expiration_time,
1459 bd->data, bd->data_size,
1460 put_path, put_path_length,
1461 hop_count,
1463 trunc_peer,
1465 sizeof (gds_routing),
1466 &gds_routing);
1467 }
1468}

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

Referenced by handle_dht_p2p_put(), and route_pending_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 1472 of file gnunet-service-dht_neighbours.c.

1481{
1482 const struct GNUNET_PeerIdentity *my_identity;
1483 const struct GNUNET_HashCode *my_identity_hash;
1484 unsigned int target_count;
1485 struct PeerInfo **targets;
1486 size_t msize;
1487 size_t result_filter_size;
1488 void *result_filter;
1489 bool sent = false;
1490
1492 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
1493
1494 if (NULL == my_identity_hash)
1495 return GNUNET_NO;
1496
1497 GNUNET_assert (NULL != peer_bf);
1499 "# GET requests routed",
1500 1,
1501 GNUNET_NO);
1502 target_count = get_target_peers (key,
1503 peer_bf,
1504 hop_count,
1505 desired_replication_level,
1506 &targets);
1508 "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1510 GNUNET_h2s (key),
1512 (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1513 GNUNET_assert (NULL != my_identity_hash);
1514 GNUNET_CONTAINER_bloomfilter_add (peer_bf, my_identity_hash);
1515 if (0 == target_count)
1516 {
1518 "Routing GET for %s terminates after %u hops at %s\n",
1519 GNUNET_h2s (key),
1520 (unsigned int) hop_count,
1522 return GNUNET_NO;
1523 }
1524 if (GNUNET_OK !=
1526 &result_filter,
1527 &result_filter_size))
1528 {
1529 result_filter = NULL;
1530 result_filter_size = 0;
1531 }
1532 msize = xquery_size + result_filter_size;
1533 if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1534 {
1535 GNUNET_break (0);
1536 GNUNET_free (result_filter);
1537 GNUNET_free (targets);
1538 return GNUNET_NO;
1539 }
1540 /* targets were added to @a peer_bf by get_target_peers() */
1541 /* forward request */
1542 for (unsigned int i = 0; i < target_count; i++)
1543 {
1544 struct PeerInfo *target = targets[i];
1545 struct PeerGetMessage *pgm;
1546 char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1547 char *rf;
1548
1550 "Routing GET for %s after %u hops to %s\n",
1551 GNUNET_h2s (key),
1552 (unsigned int) hop_count,
1553 GNUNET_i2s (&target->id));
1554 pgm = (struct PeerGetMessage *) buf;
1556 pgm->header.size = htons (sizeof (buf));
1557 pgm->type = htonl (type);
1558 pgm->options = htons (options);
1559 pgm->hop_count = htons (hop_count + 1);
1561 pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1564 pgm->bloomfilter,
1566 pgm->key = *key;
1567 rf = (char *) &pgm[1];
1568 GNUNET_memcpy (rf,
1569 result_filter,
1572 xquery,
1573 xquery_size);
1574 if (do_send (target,
1575 &pgm->header))
1576 sent = true;
1577 }
1579 "# GET messages queued for transmission",
1580 target_count,
1581 GNUNET_NO);
1582 GNUNET_free (targets);
1583 GNUNET_free (result_filter);
1584 /* Having picked a target is not the same as having sent to one: if
1585 every underlay dropped the message, the request was not routed and
1586 must go on the fast retry, not on the regular back-off. */
1587 return sent ? GNUNET_OK : GNUNET_NO;
1588}

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

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

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

◆ GDS_NEIGHBOURS_lookup_peer()

struct PeerInfo * GDS_NEIGHBOURS_lookup_peer ( const struct GNUNET_PeerIdentity target)

Lookup peer by peer's identity.

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

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

1593{
1595 target);
1596}

References all_connected_peers, and GNUNET_CONTAINER_multipeermap_get().

Referenced by process().

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

◆ cleanup_neighbours_reply()

static void cleanup_neighbours_reply ( struct GDS_NeighboursReply reply)
static

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

1618{
1619 if (reply->block_data)
1620 GNUNET_free (reply->block_data);
1621 if ((reply->bd.put_path_length > 0) && (reply->put_path))
1622 GNUNET_free (reply->put_path);
1623 if (reply->buf)
1624 GNUNET_free (reply->buf);
1625}

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

Referenced by cb_path_signed().

Here is the caller graph for this function:

◆ safe_neighbours_callback()

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

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

1632{
1633 GNUNET_break (success);
1634 if (cb)
1635 cb (cls);
1636}

References GNUNET_break.

Referenced by cb_path_signed(), and GDS_NEIGHBOURS_handle_reply().

Here is the caller graph for this function:

◆ cb_path_signed()

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

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

1642{
1643 struct GDS_NeighboursReply *reply = cls;
1644 struct PeerResultMessage *prm = reply->prm;
1645 struct GNUNET_DHT_PathElement *paths = reply->paths;
1646 unsigned int ppl = ntohs (prm->put_path_length);
1647 unsigned int get_path_length = ntohs (prm->get_path_length);
1648 void *tgt = &paths[get_path_length + ppl];
1649 void *data;
1650
1651 if (! sig)
1652 {
1654 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1655 return true;
1656 }
1657
1658 memcpy (tgt,
1659 sig,
1660 sizeof (*sig));
1661 data = tgt + sizeof (*sig);
1663 "Signing GET PATH %u/%u of %s => %s\n",
1664 ppl,
1665 get_path_length,
1666 GNUNET_h2s (&prm->key),
1667 GNUNET_B2S (sig));
1668#if SANITY_CHECKS > 1
1669 {
1670 const struct GNUNET_PeerIdentity *my_identity;
1671 struct GNUNET_DHT_PathElement xpaths[get_path_length + 1];
1672 const struct GNUNET_PeerIdentity *trunc_peer = reply->trunc_peer_is_null?
1673 NULL : &reply->trunc_peer_id;
1674
1676 GNUNET_assert (NULL != my_identity);
1677
1678 memcpy (xpaths,
1679 &paths[ppl],
1680 get_path_length * sizeof (struct GNUNET_DHT_PathElement));
1681 xpaths[get_path_length].sig = *sig;
1682 xpaths[get_path_length].pred = *my_identity;
1683 if (0 !=
1685 reply->bd.data_size,
1686 reply->bd.expiration_time,
1687 trunc_peer,
1688 paths,
1689 ppl,
1690 xpaths,
1691 get_path_length + 1,
1692 &reply->pi->id))
1693 {
1694 GNUNET_break (0);
1696 safe_neighbours_callback (reply->cb_cls, reply->cb, false);
1697 return true;
1698 }
1699 }
1700#endif
1702 reply->bd.data,
1703 reply->bd.data_size);
1704 do_send (reply->pi,
1705 &prm->header);
1707 safe_neighbours_callback (reply->cb_cls, reply->cb, true);
1708 return true;
1709}

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

Referenced by GDS_NEIGHBOURS_handle_reply().

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

◆ GDS_NEIGHBOURS_handle_reply()

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

Handle a reply (route to origin).

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

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

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

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

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

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

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

◆ check_dht_p2p_put()

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

Check validity of a p2p put request.

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

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

1944{
1945 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
1946 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1947 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1948 uint16_t msize = ntohs (put->header.size);
1949 uint16_t putlen = ntohs (put->put_path_length);
1950 size_t xsize = (has_path
1951 ? sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1952 : 0)
1953 + (truncated
1954 ? sizeof (struct GNUNET_PeerIdentity)
1955 : 0);
1956 size_t var_meta_size
1957 = putlen * sizeof(struct GNUNET_DHT_PathElement)
1958 + xsize;
1959
1960 (void) cls;
1961 if ( (msize <
1962 sizeof (struct PeerPutMessage) + var_meta_size) ||
1963 (putlen >
1964 (GNUNET_MAX_MESSAGE_SIZE
1965 - sizeof (struct PeerPutMessage)
1966 - xsize)
1967 / sizeof(struct GNUNET_DHT_PathElement)) )
1968 {
1969 GNUNET_break_op (0);
1970 return GNUNET_SYSERR;
1971 }
1972 if (GNUNET_BLOCK_TYPE_ANY == htonl (put->type))
1973 {
1974 GNUNET_break_op (0);
1975 return GNUNET_SYSERR;
1976 }
1977 return GNUNET_OK;
1978}

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

◆ cb_forwarded_dht_p2p_put()

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

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

1996{
1997 struct ForwardedDHTPut *put = cls;
1998
1999 /* notify monitoring clients; we are the last hop exactly when we did
2000 not manage to forward, as in the GET case */
2001 put->block.ro |= ((GNUNET_OK == forwarded)
2002 ? 0
2005 put->hop_count,
2007
2008 if (put->put_path)
2009 GNUNET_free (put->put_path);
2010 GNUNET_free (put->data);
2011 GNUNET_free (put);
2012}

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

Referenced by handle_dht_p2p_put().

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

◆ handle_dht_p2p_put()

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

Core handler for p2p put requests.

Parameters
clsclosure with the struct Target of the sender
putmessage

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

2024{
2025 struct Target *t = cls;
2026 struct PeerInfo *peer = t->pi;
2027 enum GNUNET_DHT_RouteOption ro = ntohs (put->options);
2028 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2029 bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2030 uint16_t msize = ntohs (put->header.size);
2031 uint16_t putlen = ntohs (put->put_path_length);
2032 const struct GNUNET_PeerIdentity *trunc_peer
2033 = truncated
2034 ? (const struct GNUNET_PeerIdentity *) &put[1]
2035 : NULL;
2036 const struct GNUNET_DHT_PathElement *put_path
2037 = truncated
2038 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2039 : (const struct GNUNET_DHT_PathElement *) &put[1];
2040 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2041 = has_path
2042 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &put_path[putlen]
2043 : NULL;
2044 const char *data
2045 = has_path
2046 ? (const char *) &last_sig[1]
2047 : (const char *) &put_path[putlen];
2048 size_t var_meta_size
2049 = putlen * sizeof(struct GNUNET_DHT_PathElement)
2050 + (has_path ? sizeof (*last_sig) : 0)
2051 + (truncated ? sizeof (*trunc_peer) : 0);
2052 struct GNUNET_DATACACHE_Block bd = {
2053 .key = put->key,
2054 .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
2055 .type = ntohl (put->type),
2056 .ro = ro,
2057 .data_size = msize - sizeof(*put) - var_meta_size,
2058 .data = data
2059 };
2060
2061 if (NULL != trunc_peer)
2062 bd.trunc_peer = *trunc_peer;
2064 "PUT for `%s' from %s with RO (%s/%s)\n",
2065 GNUNET_h2s (&put->key),
2066 GNUNET_i2s (&peer->id),
2067 (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
2068 has_path ? "R" : "-");
2070 {
2072 "# Expired PUTs discarded",
2073 1,
2074 GNUNET_NO);
2075 return;
2076 }
2077 {
2078 /* Only call 'check_block' if that keeps our CPU load (from
2079 the cryptography) below 50% on average */
2080 static struct GNUNET_TIME_Relative avg_latency;
2081 static struct GNUNET_TIME_Absolute next_time;
2082
2083 if (GNUNET_TIME_absolute_is_past (next_time))
2084 {
2085 struct GNUNET_TIME_Absolute now
2087 struct GNUNET_TIME_Relative latency;
2089
2090 if (GNUNET_NO ==
2092 bd.type,
2093 bd.data,
2094 bd.data_size))
2095 {
2096 GNUNET_break_op (0);
2097 return;
2098 }
2099 latency = GNUNET_TIME_absolute_get_duration (now);
2100 /* Use *moving average* to estimate check_block latency */
2101 avg_latency
2104 GNUNET_TIME_relative_multiply (avg_latency,
2105 7),
2106 latency),
2107 8);
2108 /* average delay = 50% of avg_latency => 50% CPU load from crypto (at most) */
2110 = GNUNET_CRYPTO_random_u64 (avg_latency.rel_value_us > 0
2111 ? avg_latency.rel_value_us
2112 : 1LLU);
2114 }
2115 }
2116 if (! has_path)
2117 putlen = 0;
2119 "# P2P PUT requests received",
2120 1,
2121 GNUNET_NO);
2123 "# P2P PUT bytes received",
2124 msize,
2125 GNUNET_NO);
2126 {
2127 struct GNUNET_HashCode test_key;
2129
2131 bd.type,
2132 bd.data,
2133 bd.data_size,
2134 &test_key);
2135 switch (ret)
2136 {
2137 case GNUNET_YES:
2138 if (0 != GNUNET_memcmp (&test_key,
2139 &bd.key))
2140 {
2141 GNUNET_break_op (0);
2142 return;
2143 }
2144 break;
2145 case GNUNET_NO:
2146 /* cannot verify, good luck */
2147 break;
2148 case GNUNET_SYSERR:
2149 /* block type not supported, good luck */
2150 break;
2151 }
2152 }
2153
2154 {
2156 struct GNUNET_DHT_PathElement pp[putlen + 1];
2157
2163 &peer->phash));
2164 /* extend 'put path' by sender */
2165 bd.put_path = pp;
2166 bd.put_path_length = putlen + 1;
2167 if (has_path)
2168 {
2169 unsigned int failure_offset;
2170
2171 GNUNET_memcpy (pp,
2172 put_path,
2173 putlen * sizeof(struct GNUNET_DHT_PathElement));
2174 pp[putlen].pred = peer->id;
2175 pp[putlen].sig = *last_sig;
2176#if SANITY_CHECKS
2177 {
2178 const struct GNUNET_PeerIdentity *my_identity;
2180 GNUNET_assert (NULL != my_identity);
2181 /* TODO: might want to eventually implement probabilistic
2182 load-based path verification, but for now it is all or nothing */
2183 failure_offset
2185 bd.data_size,
2186 bd.expiration_time,
2187 trunc_peer,
2188 pp,
2189 putlen + 1,
2190 NULL, 0, /* get_path */
2191 my_identity);
2192 }
2193#else
2194 failure_offset = 0;
2195#endif
2196 if (0 != failure_offset)
2197 {
2198 GNUNET_break_op (0);
2200 "Recorded put path invalid at offset %u, truncating\n",
2201 failure_offset);
2202 GNUNET_assert (failure_offset <= putlen + 1);
2203 bd.put_path = &pp[failure_offset];
2204 bd.put_path_length = (putlen + 1) - failure_offset;
2206 bd.trunc_peer = pp[failure_offset - 1].pred;
2207 }
2208 }
2209 else
2210 {
2211 bd.put_path_length = 0;
2212 }
2213
2214 /* give to local clients */
2216 &bd.key,
2217 0, NULL /* get path */));
2218
2219 /* store locally */
2220 if ( (0 != (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2221 (GDS_am_closest_peer (&put->key,
2222 bf)) )
2224
2225 {
2227 GNUNET_memcpy (&forward->block, &bd, sizeof (bd));
2228
2229 if (bd.put_path_length > 0)
2230 {
2231 forward->put_path = GNUNET_memdup (
2232 bd.put_path,
2233 sizeof (struct GNUNET_DHT_PathElement) * bd.put_path_length);
2234 forward->block.put_path = forward->put_path;
2235 }
2236
2237 forward->data = GNUNET_memdup (bd.data, bd.data_size);
2238 forward->block.data = forward->data;
2239
2240 forward->desired_replication_level = ntohs (put->desired_replication_level
2241 );
2242 forward->hop_count = ntohs (put->hop_count);
2243
2244 /* route to other peers */
2246 forward->desired_replication_level,
2247 forward->hop_count,
2248 bf,
2250 forward);
2251 }
2253 }
2254}

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

Here is the call graph for this function:

◆ handle_find_my_hello()

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

We have received a request for a HELLO.

Sends our HELLO back.

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

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

2279{
2280 const struct GNUNET_HashCode *my_identity_hash;
2281 const struct GNUNET_PeerIdentity *my_identity;
2282 struct GNUNET_TIME_Absolute block_expiration;
2283 size_t block_size;
2284 void *block;
2285
2286 my_identity_hash = GNUNET_PILS_get_identity_hash (GDS_pils);
2289 "Handle finding my own HELLO %s\n",
2290 GNUNET_h2s (my_identity_hash));
2291 if (NULL == GDS_my_hello)
2292 {
2294 "# FIND PEER requests ignored due to lack of HELLO",
2295 1,
2296 GNUNET_NO);
2297 if (cb)
2298 cb (cb_cls);
2299 return;
2300 }
2301
2304 &block,
2305 &block_size,
2306 &block_expiration))
2307 {
2308 if (cb)
2309 cb (cb_cls);
2310 return;
2311 }
2312
2316 bg,
2317 my_identity_hash,
2318 NULL, 0,
2319 block,
2320 block_size))
2321 {
2322 struct GNUNET_DATACACHE_Block bd = {
2324 .expiration_time
2327 .key = *my_identity_hash,
2328 .data = block,
2329 .data_size = block_size
2330 };
2331
2333 &bd,
2334 query_hash,
2335 0, NULL /* get path */,
2336 cb,
2337 cb_cls);
2338 }
2339 else
2340 {
2342 "# FIND PEER requests ignored due to Bloomfilter",
2343 1,
2344 GNUNET_NO);
2345 if (cb)
2346 cb (cb_cls);
2347 }
2348
2349 GNUNET_free (block);
2350}

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

Referenced by handle_dht_p2p_get().

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

◆ handle_find_local_hello()

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

We have received a request for nearby HELLOs.

Sends matching HELLOs back.

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

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

2367{
2368 /* Force non-random selection by hop count */
2369 struct PeerInfo *peer;
2370
2371 peer = select_peer (query_hash,
2372 NULL,
2373 GDS_NSE_get () + 1);
2374 if (NULL == peer)
2375 {
2376 /* no neighbour at all, nothing to answer with */
2377 if (cb)
2378 cb (cb_cls);
2379 return;
2380 }
2382 "Handle finding local HELLO %s\n",
2383 GNUNET_h2s (&peer->phash));
2384 if ( (NULL != peer->hello) &&
2390 bg,
2391 &peer->phash,
2392 NULL, 0, /* xquery */
2393 peer->hello,
2394 peer->hello_size)) )
2395 {
2396 struct GNUNET_DATACACHE_Block bd = {
2398 .expiration_time = peer->hello_expiration,
2399 .key = peer->phash,
2400 .data = peer->hello,
2401 .data_size = peer->hello_size
2402 };
2403
2405 &bd,
2406 query_hash,
2407 0, NULL /* get path */,
2408 cb,
2409 cb_cls);
2410 }
2411 else if (cb)
2412 cb (cb_cls);
2413}

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

Referenced by cb_handle_dht_p2p_get_my_hello().

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

◆ handle_local_result()

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

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

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

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

2425{
2426 struct PeerInfo *peer = cls;
2427
2429 bd,
2430 &bd->key,
2431 0, NULL /* get path */,
2432 NULL,
2433 NULL);
2434}

References GDS_NEIGHBOURS_handle_reply(), and GNUNET_DATACACHE_Block::key.

Referenced by cb_handle_dht_p2p_get_local_hello().

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

◆ check_dht_p2p_get()

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

Check validity of p2p get request.

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

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

2447{
2448 uint16_t msize = ntohs (get->header.size);
2449 uint16_t result_filter_size = ntohs (get->result_filter_size);
2450
2451 (void) cls;
2452 if (msize < sizeof(*get) + result_filter_size)
2453 {
2454 GNUNET_break_op (0);
2455 return GNUNET_SYSERR;
2456 }
2457 return GNUNET_OK;
2458}

References get, GNUNET_break_op, GNUNET_OK, and GNUNET_SYSERR.

◆ cb_handle_dht_p2p_get_local_result()

static void cb_handle_dht_p2p_get_local_result ( void *  cls)
static

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

2473{
2474 struct HandleCallbackGet *handle = cls;
2475 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2476 enum GNUNET_BLOCK_Type type = ntohl (handle->get->type);
2477 const void *result_filter = (const void *) &handle->get[1];
2478 uint16_t msize = ntohs (handle->get->header.size);
2479 uint16_t result_filter_size = ntohs (handle->get->result_filter_size);
2480 const void *xquery = result_filter + result_filter_size;
2481 size_t xquery_size = msize - sizeof (*handle->get) - result_filter_size;
2482
2483 /* remember request for routing replies
2484 TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2485 */
2486 GDS_ROUTING_add (&handle->t->pi->id,
2487 type,
2488 handle->bg, /* bg now owned by routing, but valid at least until end of this function! */
2489 options,
2490 &handle->get->key,
2491 xquery,
2492 xquery_size);
2493
2494 /* P2P forwarding */
2495 {
2496 bool forwarded = false;
2497 uint16_t desired_replication_level = ntohs (
2498 handle->get->desired_replication_level);
2499 uint16_t hop_count = ntohs (handle->get->hop_count);
2500
2502 forwarded = (GNUNET_OK ==
2504 options,
2505 desired_replication_level,
2506 hop_count,
2507 &handle->get->key,
2508 xquery,
2509 xquery_size,
2510 handle->bg,
2511 handle->peer_bf));
2513 options
2514 | (forwarded
2515 ? 0
2517 type,
2518 hop_count,
2519 desired_replication_level,
2520 &handle->get->key);
2521 }
2522 /* clean up; note that 'bg' is owned by routing now! */
2524
2525 GNUNET_free (handle->get);
2527}

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

Referenced by cb_handle_dht_p2p_get_local_hello(), and handle_dht_p2p_get().

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

◆ cb_handle_dht_p2p_get_local_hello()

static void cb_handle_dht_p2p_get_local_hello ( void *  cls)
static

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

2532{
2533 struct HandleCallbackGet *handle = cls;
2534 enum GNUNET_BLOCK_Type type = ntohl (handle->get->type);
2535
2537 "Handle getting local HELLO %s of type %u\n",
2538 GNUNET_h2s (&handle->get->key),
2539 type);
2540
2542 {
2543 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2544 const void *result_filter = (const void *) &handle->get[1];
2545 uint16_t msize = ntohs (handle->get->header.size);
2546 uint16_t result_filter_size = ntohs (handle->get->result_filter_size);
2547 const void *xquery = result_filter + result_filter_size;
2548 size_t xquery_size = msize - sizeof (*handle->get) - result_filter_size;
2549 /* The datacache callback runs once per *result*, never on completion,
2550 so it must not carry the continuation: no result would drop the
2551 request, several would run the continuation several times. Both
2552 lookups below are synchronous. */
2554 handle->eval = GDS_DATACACHE_get_closest (&handle->get->key,
2555 type,
2556 xquery,
2557 xquery_size,
2558 handle->bg,
2560 handle->t->pi);
2561 else
2562 handle->eval = GDS_DATACACHE_handle_get (&handle->get->key,
2563 type,
2564 xquery,
2565 xquery_size,
2566 handle->bg,
2568 handle->t->pi);
2569 }
2571}

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

Referenced by cb_handle_dht_p2p_get_my_hello(), and handle_dht_p2p_get().

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

◆ cb_handle_dht_p2p_get_my_hello()

static void cb_handle_dht_p2p_get_my_hello ( void *  cls)
static

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

2576{
2577 struct HandleCallbackGet *handle = cls;
2578 enum GNUNET_DHT_RouteOption options = ntohs (handle->get->options);
2579
2582 &handle->get->key,
2583 handle->bg,
2585 handle);
2586 else
2588}

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

Referenced by handle_dht_p2p_get().

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

◆ handle_dht_p2p_get()

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

Core handler for p2p get requests.

Parameters
clsclosure with the struct Target of the sender
getthe message

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

2600{
2601 struct Target *t = cls;
2602 struct PeerInfo *peer = t->pi;
2603 uint16_t msize = ntohs (get->header.size);
2604 uint16_t result_filter_size = ntohs (get->result_filter_size);
2605 uint16_t hop_count = ntohs (get->hop_count);
2606 enum GNUNET_BLOCK_Type type = ntohl (get->type);
2607 enum GNUNET_DHT_RouteOption options = ntohs (get->options);
2608 const void *result_filter = (const void *) &get[1];
2609 const void *xquery = result_filter + result_filter_size;
2610 size_t xquery_size = msize - sizeof (*get) - result_filter_size;
2611
2612 /* parse and validate message */
2614 "# P2P GET requests received",
2615 1,
2616 GNUNET_NO);
2618 "# P2P GET bytes received",
2619 msize,
2620 GNUNET_NO);
2621 if (GNUNET_NO ==
2623 type,
2624 &get->key,
2625 xquery,
2626 xquery_size))
2627 {
2628 /* request invalid */
2629 GNUNET_break_op (0);
2630 return;
2631 }
2632
2633 {
2634 const struct GNUNET_PeerIdentity *my_identity;
2635 struct HandleCallbackGet *handle;
2636
2638 handle->t = t;
2639 handle->get = GNUNET_memdup (get, msize);
2641
2643 GNUNET_assert (NULL != my_identity);
2644
2645 handle->peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2650 &peer->phash));
2652 type,
2653 result_filter,
2654 result_filter_size,
2655 "filter-size",
2656 result_filter_size,
2657 NULL);
2659 "GET for %s at %s after %u hops\n",
2660 GNUNET_h2s (&get->key),
2662 (unsigned int) hop_count);
2663 /* local lookup (this may update the bg) */
2665 (GDS_am_closest_peer (&get->key,
2666 handle->peer_bf)) )
2667 {
2670 {
2672 "# P2P HELLO lookup requests processed",
2673 1,
2674 GNUNET_NO);
2676 &get->key,
2677 handle->bg,
2679 handle);
2680 }
2681 else
2683 }
2684 else
2685 {
2687 "# P2P GET requests ONLY routed",
2688 1,
2689 GNUNET_NO);
2691 }
2692 }
2693}

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

Here is the call graph for this function:

◆ process_reply_with_path()

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

Process a reply, after the get_path has been updated.

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

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

2709{
2710 /* forward to local clients */
2712 "Forwarding reply to local clients\n");
2713 if (! GDS_CLIENTS_handle_reply (bd,
2714 query_hash,
2715 get_path_length,
2716 get_path))
2717 {
2718 GNUNET_break (0);
2719 return;
2720 }
2722 get_path,
2723 get_path_length);
2725 {
2726 struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2727 + bd->put_path_length)];
2728 struct GNUNET_DATACACHE_Block bdx = *bd;
2729
2730 if (NULL != bd->put_path)
2731 GNUNET_memcpy (xput_path,
2732 bd->put_path,
2733 bd->put_path_length * sizeof(struct
2735 GNUNET_memcpy (&xput_path[bd->put_path_length],
2736 get_path,
2737 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2738 bdx.put_path = xput_path;
2739 bdx.put_path_length += get_path_length;
2741 }
2742 /* forward to other peers */
2744 query_hash,
2745 get_path_length,
2746 get_path);
2747}

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

2760{
2761 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2762 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2763 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2764 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2765
2766 uint16_t get_path_length = ntohs (prm->get_path_length);
2767 uint16_t put_path_length = ntohs (prm->put_path_length);
2768 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2769 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2770
2771 (void) cls;
2772 if ( (msize < vsize) ||
2773 (msize - vsize <
2774 (get_path_length + put_path_length)
2775 * sizeof(struct GNUNET_DHT_PathElement)) ||
2776 (get_path_length >
2777 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2778 (put_path_length >
2779 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2780 {
2781 GNUNET_break_op (0);
2782 return GNUNET_SYSERR;
2783 }
2784 return GNUNET_OK;
2785}

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

2797{
2798 struct Target *t = cls;
2799 struct PeerInfo *peer = t->pi;
2800 uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2801 enum GNUNET_DHT_RouteOption ro = ntohs (prm->options);
2802 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2803 bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2804 uint16_t get_path_length = ntohs (prm->get_path_length);
2805 uint16_t put_path_length = ntohs (prm->put_path_length);
2806 const struct GNUNET_PeerIdentity *trunc_peer
2807 = truncated
2808 ? (const struct GNUNET_PeerIdentity *) &prm[1]
2809 : NULL;
2810 const struct GNUNET_DHT_PathElement *put_path
2811 = truncated
2812 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2813 : (const struct GNUNET_DHT_PathElement *) &prm[1];
2814 const struct GNUNET_DHT_PathElement *get_path
2815 = &put_path[put_path_length];
2816 const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2817 = tracked
2818 ? (const struct GNUNET_CRYPTO_EddsaSignature *) &get_path[get_path_length]
2819 : NULL;
2820 const void *data
2821 = tracked
2822 ? (const void *) &last_sig[1]
2823 : (const void *) &get_path[get_path_length];
2824 size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2825 + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2826 struct GNUNET_DATACACHE_Block bd = {
2828 .put_path = put_path,
2829 .put_path_length = put_path_length,
2830 .key = prm->key,
2831 .type = ntohl (prm->type),
2832 .ro = ro,
2833 .data = data,
2834 .data_size = msize - vsize - (get_path_length + put_path_length)
2835 * sizeof(struct GNUNET_DHT_PathElement)
2836 };
2837
2838 /* parse and validate message */
2839 if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
2840 {
2842 "# Expired results discarded",
2843 1,
2844 GNUNET_NO);
2845 return;
2846 }
2847 if (GNUNET_OK !=
2849 bd.type,
2850 bd.data,
2851 bd.data_size))
2852 {
2853 GNUNET_break_op (0);
2854 return;
2855 }
2857 "# P2P RESULTS received",
2858 1,
2859 GNUNET_NO);
2861 "# P2P RESULT bytes received",
2862 msize,
2863 GNUNET_NO);
2864 {
2866
2868 bd.type,
2869 bd.data,
2870 bd.data_size,
2871 &bd.key);
2872 if (GNUNET_NO == ret)
2873 bd.key = prm->key;
2874 }
2875
2876 /* if we got a HELLO, consider it for our own routing table */
2877 hello_check (&bd);
2878
2879 /* Need to append 'peer' to 'get_path' */
2880 if (tracked)
2881 {
2882 struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2883 struct GNUNET_DHT_PathElement *gp = xget_path;
2884 unsigned int failure_offset;
2885
2886 GNUNET_memcpy (xget_path,
2887 get_path,
2888 get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2889 xget_path[get_path_length].pred = peer->id;
2890 /* use memcpy(), as last_sig may not be aligned */
2891 memcpy (&xget_path[get_path_length].sig,
2892 last_sig,
2893 sizeof (*last_sig));
2894#if SANITY_CHECKS
2895 {
2896 const struct GNUNET_PeerIdentity *my_identity;
2898 GNUNET_assert (NULL != my_identity);
2899 /* TODO: might want to eventually implement probabilistic
2900 load-based path verification, but for now it is all or nothing */
2901 failure_offset
2902 = GNUNET_DHT_verify_path (bd.data,
2903 bd.data_size,
2904 bd.expiration_time,
2905 trunc_peer,
2906 put_path,
2907 put_path_length,
2908 gp,
2909 get_path_length + 1,
2910 my_identity);
2911 }
2912#else
2913 failure_offset = 0;
2914#endif
2915 if (0 != failure_offset)
2916 {
2918 "Recorded path invalid at offset %u, truncating\n",
2919 failure_offset);
2920 GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length
2921 + 1);
2922 if (failure_offset < bd.put_path_length)
2923 {
2924 /* failure on put path */
2925 trunc_peer = &bd.put_path[failure_offset - 1].pred;
2926 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2927 bd.put_path = &bd.put_path[failure_offset];
2928 bd.put_path_length -= failure_offset;
2929 truncated = true;
2930 }
2931 else
2932 {
2933 /* failure on get path */
2934 failure_offset -= bd.put_path_length;
2935 if (0 == failure_offset)
2936 trunc_peer = &bd.put_path[bd.put_path_length - 1].pred;
2937 else
2938 trunc_peer = &gp[failure_offset - 1].pred;
2939 get_path_length -= failure_offset;
2940 gp = &gp[failure_offset];
2941 bd.put_path_length = 0;
2942 bd.put_path = NULL;
2943 bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2944 truncated = true;
2945 }
2946 }
2948 "Extending GET path of length %u with %s\n",
2949 get_path_length,
2950 GNUNET_i2s (&peer->id));
2951 if (truncated)
2952 {
2953 GNUNET_assert (NULL != trunc_peer);
2954 bd.trunc_peer = *trunc_peer;
2955 }
2957 &prm->key,
2958 get_path_length + 1,
2959 gp);
2960 }
2961 else
2962 {
2963 if (truncated)
2964 {
2965 GNUNET_assert (NULL != trunc_peer);
2966 bd.trunc_peer = *trunc_peer;
2967 }
2969 &prm->key,
2970 0,
2971 NULL);
2972 }
2973}

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

Here is the call graph for this function:

◆ check_dht_p2p_hello()

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

Check validity of a p2p hello message.

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

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

2986{
2987 struct Target *t = cls;
2988 struct PeerInfo *peer = t->pi;
2990 size_t hellob_size;
2991 void *hellob;
2993
2995 &peer->id,
2996 &hellob,
2997 &hellob_size,
2998 &expiration);
2999 GNUNET_free (hellob);
3000 return ret;
3001}

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

3013{
3014 struct Target *t = cls;
3015 struct PeerInfo *peer = t->pi;
3016
3017 GNUNET_free (peer->hello);
3018 peer->hello_size = 0;
3021 &peer->id,
3022 &peer->hello,
3023 &peer->hello_size,
3024 &peer->hello_expiration));
3025}

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

3034{
3035 struct Target *t = *tctx;
3036 struct GNUNET_MQ_MessageHandler core_handlers[] = {
3037 GNUNET_MQ_hd_var_size (dht_p2p_get,
3039 struct PeerGetMessage,
3040 t),
3041 GNUNET_MQ_hd_var_size (dht_p2p_put,
3043 struct PeerPutMessage,
3044 t),
3045 GNUNET_MQ_hd_var_size (dht_p2p_result,
3047 struct PeerResultMessage,
3048 t),
3049 GNUNET_MQ_hd_var_size (dht_p2p_hello,
3051 struct GNUNET_MessageHeader,
3052 t),
3054 };
3055 const struct GNUNET_MessageHeader *mh = message;
3056
3057 (void) cls; /* the 'struct GDS_Underlay' */
3058 (void) sctx; /* our receiver address */
3059 if (NULL == t)
3060 {
3061 /* Received message claiming to originate from myself?
3062 Ignore! */
3063 GNUNET_break_op (0);
3064 return;
3065 }
3066 if (message_size < sizeof (*mh))
3067 {
3068 GNUNET_break_op (0);
3069 return;
3070 }
3071 if (message_size != ntohs (mh->size))
3072 {
3073 GNUNET_break_op (0);
3074 return;
3075 }
3077 "Handling message of type %u from peer %s\n",
3078 ntohs (mh->type),
3079 GNUNET_i2s (&t->pi->id));
3080 if (GNUNET_OK !=
3081 GNUNET_MQ_handle_message (core_handlers,
3082 mh))
3083 {
3084 GNUNET_break_op (0);
3085 return;
3086 }
3087}

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

3101{
3102 const struct GNUNET_PeerIdentity *my_identity;
3103 struct GNUNET_HashCode phash;
3104 int peer_bucket;
3105 struct PeerBucket *bucket;
3106 (void) cls;
3107
3109 GNUNET_assert (NULL != my_identity);
3110
3111 if (0 == GNUNET_memcmp (my_identity, pid))
3112 {
3114 "Got a HELLO for my own PID, ignoring it\n");
3115 return; /* that's us! */
3116 }
3117 GNUNET_CRYPTO_hash (pid,
3118 sizeof(*pid),
3119 &phash);
3120 peer_bucket = find_bucket (&phash);
3121 GNUNET_assert ( (peer_bucket >= 0) &&
3122 ((unsigned int) peer_bucket < MAX_BUCKETS));
3123 bucket = &k_buckets[peer_bucket];
3124 for (struct PeerInfo *pi = bucket->head;
3125 NULL != pi;
3126 pi = pi->next)
3127 if (0 ==
3128 GNUNET_memcmp (&pi->id,
3129 pid))
3130 {
3131 /* already connected */
3132 GDS_u_try_connect (pid,
3133 uri);
3134 return;
3135 }
3136 if (bucket->peers_size >= bucket_size)
3137 return; /* do not care */
3139 "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
3140 GNUNET_i2s (pid),
3141 uri,
3142 peer_bucket,
3143 bucket->peers_size,
3144 bucket_size);
3145 /* new peer that we like! */
3146 GDS_u_try_connect (pid,
3147 uri);
3148}

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

Referenced by handle_dht_local_hello_offer(), and hello_check().

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

◆ GDS_NEIGHBOURS_broadcast()

void GDS_NEIGHBOURS_broadcast ( const struct GNUNET_MessageHeader msg)

Send msg to all peers in our buckets.

Parameters
msgmessage to broadcast

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

3158{
3159 for (unsigned int bc = 0; bc<closest_bucket; bc++)
3160 {
3161 struct PeerBucket *bucket = &k_buckets[bc];
3162 unsigned int count = 0;
3163
3164 for (struct PeerInfo *pos = bucket->head;
3165 NULL != pos;
3166 pos = pos->next)
3167 {
3168 if (count >= bucket_size)
3169 break; /* we only consider first #bucket_size entries per bucket */
3170 count++;
3171 do_send (pos,
3172 msg);
3173 }
3174 }
3175}

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

3180{
3181
3182 unsigned long long temp_config_num;
3183
3186 "DHT",
3187 "DISABLE_TRY_CONNECT");
3188 if (GNUNET_OK ==
3190 "DHT",
3191 "bucket_size",
3192 &temp_config_num))
3193 bucket_size = (unsigned int) temp_config_num;
3196 "DHT",
3197 "CACHE_RESULTS");
3199 GNUNET_YES);
3200 return GNUNET_OK;
3201}

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

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

Referenced by shutdown_task().

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

◆ GDS_NEIGHBOURS_get_id()

const struct GNUNET_PeerIdentity * GDS_NEIGHBOURS_get_id ( void  )

Get the ID of the local node.

Returns
identity of the local node

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

3219{
3221}

References GDS_pils, and GNUNET_PILS_get_identity().

Here is the call graph for this function:

Variable Documentation

◆ cache_results

int cache_results
static

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

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

Referenced by GDS_NEIGHBOURS_init(), and process_reply_with_path().

◆ closest_bucket

unsigned int closest_bucket
static

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

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

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

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

◆ newly_found_peers

unsigned int newly_found_peers
static

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

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

Referenced by GDS_u_connect(), and send_find_peer_message().

◆ disable_try_connect

int disable_try_connect
static

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

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

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

◆ k_buckets

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

The buckets.

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

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

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

◆ all_connected_peers

struct GNUNET_CONTAINER_MultiPeerMap* all_connected_peers
static

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

Values are of type struct PeerInfo.

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

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

◆ bucket_size

◆ find_peer_task

struct GNUNET_SCHEDULER_Task* find_peer_task
static

Task that sends FIND PEER requests.

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

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