GNUnet  0.20.0
gnunet-service-dht_neighbours.c File Reference

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

#include "platform.h"
#include "gnunet_constants.h"
#include "gnunet_protocols.h"
#include "gnunet_signatures.h"
#include "gnunet_hello_lib.h"
#include "gnunet_hello_uri_lib.h"
#include "gnunet-service-dht.h"
#include "gnunet-service-dht_neighbours.h"
#include "gnunet-service-dht_routing.h"
#include "dht.h"
Include dependency graph for gnunet-service-dht_neighbours.c:

Go to the source code of this file.

Data Structures

struct  PeerPutMessage
 P2P PUT message. More...
 
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...
 

Macros

#define LOG_TRAFFIC(kind, ...)
 
#define SANITY_CHECKS   2
 Enable slow sanity checks to debug issues. More...
 
#define MAX_BUCKETS   sizeof(struct GNUNET_HashCode) * 8
 How many buckets will we allow in total. More...
 
#define DEFAULT_BUCKET_SIZE   8
 What is the maximum number of peers in a given bucket. More...
 
#define FIND_PEER_REPLICATION_LEVEL   4
 Desired replication level for FIND PEER requests. More...
 
#define MAXIMUM_PENDING_PER_PEER   64
 Maximum allowed number of pending messages per peer. More...
 
#define DHT_MINIMUM_FIND_PEER_INTERVAL
 How long at least to wait before sending another find peer request. More...
 
#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). More...
 
#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? More...
 

Functions

static void send_done_cb (void *cls)
 Function called whenever we finished sending to a target. More...
 
static void do_send (struct PeerInfo *pi, const struct GNUNET_MessageHeader *msg)
 Send msg to pi. More...
 
static void sign_path (const void *data, size_t data_size, struct GNUNET_TIME_Absolute exp_time, const struct GNUNET_PeerIdentity *pred, const struct GNUNET_PeerIdentity *succ, struct GNUNET_CRYPTO_EddsaSignature *sig)
 Sign that we are routing a message from pred to succ. More...
 
static int find_bucket (const struct GNUNET_HashCode *hc)
 Find the optimal bucket for this key. More...
 
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. More...
 
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. More...
 
static void update_hold (struct PeerBucket *bucket)
 The list of the first bucket_size peers of bucket changed. More...
 
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. More...
 
void GDS_u_disconnect (void *ctx)
 Function to call when we disconnected from a peer and can henceforth cannot transmit to that peer anymore. More...
 
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). More...
 
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. More...
 
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. More...
 
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. More...
 
static void hello_check (const struct GNUNET_DATACACHE_Block *bd)
 If we got a HELLO, consider it for our own routing table. More...
 
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_handle_put (const struct GNUNET_DATACACHE_Block *bd, uint16_t desired_replication_level, uint16_t hop_count, struct GNUNET_CONTAINER_BloomFilter *bf)
 Perform a PUT operation. More...
 
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. More...
 
struct PeerInfoGDS_NEIGHBOURS_lookup_peer (const struct GNUNET_PeerIdentity *target)
 Lookup peer by peer's identity. More...
 
bool GDS_NEIGHBOURS_handle_reply (struct PeerInfo *pi, const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path)
 Handle a reply (route to origin). More...
 
static enum GNUNET_GenericReturnValue check_dht_p2p_put (void *cls, const struct PeerPutMessage *put)
 Check validity of a p2p put request. More...
 
static void handle_dht_p2p_put (void *cls, const struct PeerPutMessage *put)
 Core handler for p2p put requests. More...
 
static void handle_find_my_hello (struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg)
 We have received a request for a HELLO. More...
 
static void handle_find_local_hello (struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg)
 We have received a request for nearby HELLOs. More...
 
static void handle_local_result (void *cls, const struct GNUNET_DATACACHE_Block *bd)
 Handle an exact result from local datacache for a GET operation. More...
 
static enum GNUNET_GenericReturnValue check_dht_p2p_get (void *cls, const struct PeerGetMessage *get)
 Check validity of p2p get request. More...
 
static void handle_dht_p2p_get (void *cls, const struct PeerGetMessage *get)
 Core handler for p2p get requests. More...
 
static bool process_reply_with_path (const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path)
 Process a reply, after the get_path has been updated. More...
 
static enum GNUNET_GenericReturnValue check_dht_p2p_result (void *cls, const struct PeerResultMessage *prm)
 Check validity of p2p result message. More...
 
static void handle_dht_p2p_result (void *cls, const struct PeerResultMessage *prm)
 Core handler for p2p result messages. More...
 
static enum GNUNET_GenericReturnValue check_dht_p2p_hello (void *cls, const struct GNUNET_MessageHeader *hello)
 Check validity of a p2p hello message. More...
 
static void handle_dht_p2p_hello (void *cls, const struct GNUNET_MessageHeader *hello)
 Core handler for p2p HELLO messages. More...
 
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. More...
 
void GDS_try_connect (void *cls, const char *uri)
 Callback function used to extract URIs from a builder. More...
 
void GDS_NEIGHBOURS_broadcast (const struct GNUNET_MessageHeader *msg)
 Send msg to all peers in our buckets. More...
 
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_init ()
 Initialize neighbours subsystem. More...
 
void GDS_NEIGHBOURS_done ()
 Shutdown neighbours subsystem. More...
 
struct GNUNET_PeerIdentityGDS_NEIGHBOURS_get_id ()
 Get the ID of the local node. More...
 

Variables

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

Detailed Description

GNUnet DHT service's bucket and neighbour management code.

Author
Christian Grothoff
Nathan Evans

Definition in file gnunet-service-dht_neighbours.c.

Macro Definition Documentation

◆ LOG_TRAFFIC

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

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

◆ SANITY_CHECKS

#define SANITY_CHECKS   2

Enable slow sanity checks to debug issues.

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

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

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

◆ MAX_BUCKETS

#define MAX_BUCKETS   sizeof(struct GNUNET_HashCode) * 8

How many buckets will we allow in total.

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

◆ DEFAULT_BUCKET_SIZE

#define DEFAULT_BUCKET_SIZE   8

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

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

◆ FIND_PEER_REPLICATION_LEVEL

#define FIND_PEER_REPLICATION_LEVEL   4

Desired replication level for FIND PEER requests.

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

◆ MAXIMUM_PENDING_PER_PEER

#define MAXIMUM_PENDING_PER_PEER   64

Maximum allowed number of pending messages per peer.

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

◆ DHT_MINIMUM_FIND_PEER_INTERVAL

#define DHT_MINIMUM_FIND_PEER_INTERVAL
Value:
#define GNUNET_TIME_UNIT_MINUTES
One minute.
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:484

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

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

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

◆ DHT_AVG_FIND_PEER_INTERVAL

#define DHT_AVG_FIND_PEER_INTERVAL
Value:
#define GNUNET_TIME_UNIT_SECONDS
One second.

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

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

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

◆ GET_TIMEOUT

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

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

Function Documentation

◆ send_done_cb()

static void send_done_cb ( void *  cls)
static

Function called whenever we finished sending to a target.

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

Parameters
clsa struct Target *

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

459 {
460  struct Target *t = cls;
461  struct PeerInfo *pi = t->pi; /* NULL if t->dropped! */
462 
463  GNUNET_assert (t->load > 0);
464  t->load--;
465  if (0 < t->load)
466  return;
467  if (t->dropped)
468  {
469  GNUNET_free (t);
470  return;
471  }
472  /* move target back to the front */
474  pi->t_tail,
475  t);
477  pi->t_tail,
478  t);
479 }
static struct GNUNET_PEERINFO_Handle * pi
Handle to peerinfo service.
static struct GNUNET_SCHEDULER_Task * t
Main task.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_free(ptr)
Wrapper around free.
Entry for a peer in a bucket.
List of targets that we can use to reach this peer.

References GNUNET_assert, GNUNET_CONTAINER_DLL_insert, GNUNET_CONTAINER_DLL_remove, GNUNET_free, pi, and t.

Referenced by do_send().

Here is the caller graph for this function:

◆ do_send()

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

Send msg to pi.

Parameters
piwhere to send the message
msgmessage to send

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

491 {
492  struct Target *t;
493 
494  for (t = pi->t_head;
495  NULL != t;
496  t = t->next)
497  if (t->load < MAXIMUM_PENDING_PER_PEER)
498  break;
499  if (NULL == t)
500  {
501  /* all targets busy, drop message */
503  "# messages dropped (underlays busy)",
504  1,
505  GNUNET_NO);
506  return;
507  }
508  t->load++;
509  /* rotate busy targets to the end */
510  if (MAXIMUM_PENDING_PER_PEER == t->load)
511  {
513  pi->t_tail,
514  t);
516  pi->t_tail,
517  t);
518  }
519  GDS_u_send (t->u,
520  t->utarget,
521  msg,
522  ntohs (msg->size),
523  &send_done_cb,
524  t);
525 }
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
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.
struct GNUNET_STATISTICS_Handle * GDS_stats
Handle for the statistics service.
#define MAXIMUM_PENDING_PER_PEER
Maximum allowed number of pending messages per peer.
static void send_done_cb(void *cls)
Function called whenever we finished sending to a target.
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
@ GNUNET_NO
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
struct GNUNET_SCHEDULER_Task * next
This is a linked list.
Definition: scheduler.c:140

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, pi, send_done_cb(), GNUNET_MessageHeader::size, and t.

Referenced by check_dht_p2p_put(), and GDS_NEIGHBOURS_broadcast().

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

◆ sign_path()

static void sign_path ( const void *  data,
size_t  data_size,
struct GNUNET_TIME_Absolute  exp_time,
const struct GNUNET_PeerIdentity pred,
const struct GNUNET_PeerIdentity succ,
struct GNUNET_CRYPTO_EddsaSignature sig 
)
static

Sign that we are routing a message from pred to succ.

(So the route is $PRED->us->$SUCC).

Parameters
datapayload (the block)
data_sizenumber of bytes in data
exp_timeexpiration time of data
predpredecessor peer ID
succsuccessor peer ID
[out]sigwhere to write the signature (of purpose #GNUNET_SIGNATURE_PURPOSE_DHT_PUT_HOP)

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

547 {
548  struct GNUNET_DHT_HopSignature hs = {
550  .purpose.size = htonl (sizeof (hs)),
551  .expiration_time = GNUNET_TIME_absolute_hton (exp_time),
552  .succ = *succ
553  };
554 
555  if (NULL != pred)
556  hs.pred = *pred;
558  data_size,
559  &hs.h_data);
561  &hs,
562  sig);
563 }
#define GNUNET_SIGNATURE_PURPOSE_DHT_HOP
Signature by which a peer affirms that it forwarded a message in the DHT.
static size_t data_size
Number of bytes in data.
Definition: gnunet-abd.c:187
uint32_t data
The data value.
struct GNUNET_CRYPTO_EddsaPrivateKey GDS_my_private_key
Our private key.
#define GNUNET_CRYPTO_eddsa_sign(priv, ps, sig)
EdDSA sign a given block.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:41
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition: time.c:638
uint32_t purpose
What does this signature vouch for? This must contain a GNUNET_SIGNATURE_PURPOSE_XXX constant (from g...
Message signed by a peer when doing path tracking.
struct GNUNET_HashCode h_data
Hash over the payload of the block.
struct GNUNET_CRYPTO_EccSignaturePurpose purpose
Must be GNUNET_SIGNATURE_PURPOSE_DHT_HOP.
struct GNUNET_PeerIdentity pred
Previous hop the message was received from.
struct GNUNET_PeerIdentity succ
Next hop the message was forwarded to.

References data, data_size, GDS_my_private_key, GNUNET_CRYPTO_eddsa_sign, GNUNET_CRYPTO_hash(), GNUNET_SIGNATURE_PURPOSE_DHT_HOP, GNUNET_TIME_absolute_hton(), GNUNET_DHT_HopSignature::h_data, GNUNET_DHT_HopSignature::pred, GNUNET_CRYPTO_EccSignaturePurpose::purpose, GNUNET_DHT_HopSignature::purpose, and GNUNET_DHT_HopSignature::succ.

Referenced by check_dht_p2p_put().

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

◆ find_bucket()

static int find_bucket ( const struct GNUNET_HashCode hc)
static

Find the optimal bucket for this key.

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

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

575 {
576  struct GNUNET_HashCode xor;
577  unsigned int bits;
578 
581  &xor);
583  if (bits == MAX_BUCKETS)
584  {
585  /* How can all bits match? Got my own ID? */
586  GNUNET_break (0);
587  return -1;
588  }
589  return MAX_BUCKETS - bits - 1;
590 }
struct GNUNET_HashCode GDS_my_identity_hash
Hash of the identity of this peer.
#define MAX_BUCKETS
How many buckets will we allow in total.
void GNUNET_CRYPTO_hash_xor(const struct GNUNET_HashCode *a, const struct GNUNET_HashCode *b, struct GNUNET_HashCode *result)
compute result = a ^ b
Definition: crypto_hash.c:135
unsigned int GNUNET_CRYPTO_hash_count_leading_zeros(const struct GNUNET_HashCode *h)
Count the number of leading 0 bits in h.
Definition: crypto_hash.c:177
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
A 512-bit hashcode.
uint32_t bits[512/8/sizeof(uint32_t)]

Referenced by GDS_try_connect(), and GDS_u_connect().

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

606 {
607  struct GNUNET_BLOCK_Group *bg = cls;
608  struct PeerInfo *pi = value;
609 
611  &pi->phash,
612  1);
614  "Adding known peer (%s) to Bloom filter for FIND PEER\n",
615  GNUNET_i2s (key));
616  return GNUNET_YES;
617 }
struct GNUNET_HashCode key
The key used in the DHT.
static char * value
Value of the record to add/remove.
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:363
#define GNUNET_log(kind,...)
@ GNUNET_YES
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
@ GNUNET_ERROR_TYPE_DEBUG
Block group data.

References GNUNET_HashCode::bits, GDS_my_identity_hash, GNUNET_break, GNUNET_CRYPTO_hash_count_leading_zeros(), GNUNET_CRYPTO_hash_xor(), and MAX_BUCKETS.

Referenced by 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 628 of file gnunet-service-dht_neighbours.c.

629 {
630  (void) cls;
631 
632  /* Compute when to do this again (and if we should
633  even send a message right now) */
634  {
635  struct GNUNET_TIME_Relative next_send_time;
636  bool done_early;
637 
638  find_peer_task = NULL;
639  done_early = (newly_found_peers > bucket_size);
640  /* schedule next round, taking longer if we found more peers
641  in the last round. */
642  next_send_time.rel_value_us =
643  DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value_us
648  1 + 100 * (1 + newly_found_peers) / bucket_size).rel_value_us);
649  newly_found_peers = 0;
650  GNUNET_assert (NULL == find_peer_task);
652  GNUNET_SCHEDULER_add_delayed (next_send_time,
654  NULL);
655  if (done_early)
656  return;
657  }
658 
659  /* actually send 'find peer' request */
660  {
661  struct GNUNET_BLOCK_Group *bg;
662  struct GNUNET_CONTAINER_BloomFilter *peer_bf;
663 
666  NULL,
667  0,
668  "set-seen-size",
671  NULL);
674  bg);
675  peer_bf
679  if (GNUNET_OK !=
684  0, /* hop count */
686  NULL, 0, /* xquery */
687  bg,
688  peer_bf))
689  {
691  "# Failed to initiate FIND PEER lookup",
692  1,
693  GNUNET_NO);
694  }
695  else
696  {
698  "# FIND PEER messages initiated",
699  1,
700  GNUNET_NO);
701  }
704  }
705 }
@ GNUNET_BLOCK_TYPE_DHT_HELLO
Type of a block that contains a DHT-NG HELLO for a peer.
#define DHT_BLOOM_SIZE
Size of the bloom filter the DHT uses to filter peers.
Definition: dht.h:34
struct GNUNET_BLOCK_Context * GDS_block_context
Our handle to the BLOCK library.
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 unsigned int newly_found_peers
How many peers have we added since we sent out our last find peer request?
#define FIND_PEER_REPLICATION_LEVEL
Desired replication level for FIND PEER requests.
static struct GNUNET_CONTAINER_MultiPeerMap * all_connected_peers
Hash map of all CORE-connected peers, for easy removal from k_buckets on disconnect.
#define DHT_MINIMUM_FIND_PEER_INTERVAL
How long at least to wait before sending another find peer request.
static struct GNUNET_SCHEDULER_Task * find_peer_task
Task that sends FIND PEER requests.
static enum GNUNET_GenericReturnValue add_known_to_bloom(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Add each of the peers we already know to the Bloom filter of the request so that we don't get duplica...
static unsigned int bucket_size
Maximum size for each bucket.
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.
#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 GNUNET_BLOCK_group_destroy(struct GNUNET_BLOCK_Group *bg)
Destroy resources used by a block group.
Definition: block.c:192
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:247
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_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...
#define GNUNET_CONSTANTS_BLOOMFILTER_K
K-value that must be used for the bloom filters in 'GET' queries.
uint64_t GNUNET_CRYPTO_random_u64(enum GNUNET_CRYPTO_Quality mode, uint64_t max)
Generate a random unsigned 64-bit value.
@ GNUNET_CRYPTO_QUALITY_WEAK
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
@ GNUNET_DHT_RO_RECORD_ROUTE
We should keep track of the route that the message took in the P2P network.
@ GNUNET_DHT_RO_FIND_APPROXIMATE
Approximate results are fine.
int GNUNET_CONTAINER_multipeermap_iterate(struct GNUNET_CONTAINER_MultiPeerMap *map, GNUNET_CONTAINER_PeerMapIterator it, void *it_cls)
Iterate over all entries in the map.
unsigned int GNUNET_CONTAINER_multipeermap_size(const struct GNUNET_CONTAINER_MultiPeerMap *map)
Get the number of key-value pairs in the map.
@ GNUNET_OK
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:1272
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.

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

Referenced by GDS_u_connect().

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

717 {
718  unsigned int off = 0;
719 
720  /* find the peer -- we just go over all of them, should
721  be hardly any more expensive than just finding the 'right'
722  one. */
723  for (struct PeerInfo *pos = bucket->head;
724  NULL != pos;
725  pos = pos->next)
726  {
727  if (off > bucket_size)
728  break; /* We only hold up to #bucket_size peers per bucket */
729  off++;
730  for (struct Target *tp = pos->t_head;
731  NULL != tp;
732  tp = tp->next)
733  if (NULL == tp->ph)
734  tp->ph = GDS_u_hold (tp->u,
735  tp->utarget);
736  }
737 }
struct GNUNET_DHTU_PreferenceHandle * GDS_u_hold(struct GDS_Underlay *u, struct GNUNET_DHTU_Target *target)
Create a hold on target at underlay u.
struct PeerInfo * head
Head of DLL.
struct PeerInfo * next
Next peer entry (DLL)
struct Target * next
Kept in a DLL.

References bucket_size, GDS_u_hold(), PeerBucket::head, Target::next, and PeerInfo::next.

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

745 {
746  struct GDS_Underlay *u = cls;
747  struct PeerInfo *pi;
748  struct PeerBucket *bucket;
749  bool do_hold = false;
750 
751  /* Check for connect to self message */
752  if (0 == GNUNET_memcmp (&GDS_my_identity,
753  pid))
754  return;
756  "Connected to peer %s\n",
757  GNUNET_i2s (pid));
759  pid);
760  if (NULL == pi)
761  {
763  "# peers connected",
764  1,
765  GNUNET_NO);
766  pi = GNUNET_new (struct PeerInfo);
767  pi->id = *pid;
769  sizeof(*pid),
770  &pi->phash);
771  pi->peer_bucket = find_bucket (&pi->phash);
772  GNUNET_assert ( (pi->peer_bucket >= 0) &&
773  ((unsigned int) pi->peer_bucket < MAX_BUCKETS));
774  bucket = &k_buckets[pi->peer_bucket];
776  bucket->tail,
777  pi);
778  bucket->peers_size++;
780  (unsigned int) pi->peer_bucket + 1);
783  &pi->id,
784  pi,
786  if (bucket->peers_size <= bucket_size)
787  {
789  do_hold = true;
790  }
793  {
794  /* got a first connection, good time to start with FIND PEER requests... */
795  GNUNET_assert (NULL == find_peer_task);
797  NULL);
798  }
799  }
800  {
801  struct Target *t;
802 
803  t = GNUNET_new (struct Target);
804  t->u = u;
805  t->utarget = target;
806  t->pi = pi;
808  pi->t_tail,
809  t);
810  *ctx = t;
811 
812  }
813  if (do_hold)
814  update_hold (bucket);
815 }
struct GNUNET_PeerIdentity GDS_my_identity
Identity of this peer.
static int disable_try_connect
Option for testing that disables the 'connect' function of the DHT.
static int find_bucket(const struct GNUNET_HashCode *hc)
Find the optimal bucket for this key.
static unsigned int closest_bucket
The lowest currently used bucket, initially 0 (for 0-bits matching bucket).
static struct PeerBucket k_buckets[sizeof(struct GNUNET_HashCode) *8]
The buckets.
static void update_hold(struct PeerBucket *bucket)
The list of the first bucket_size peers of bucket changed.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
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.
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.
@ 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...
#define GNUNET_MAX(a, b)
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
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:1299
Information we keep per underlay.
Peers are grouped into buckets.
struct PeerInfo * tail
Tail of DLL.
unsigned int peers_size
Number of peers in the bucket.
struct GDS_Underlay * u
Underlay providing this target.

References all_connected_peers, bucket_size, closest_bucket, ctx, disable_try_connect, find_bucket(), find_peer_task, GDS_my_identity, GDS_stats, GNUNET_assert, GNUNET_CONTAINER_DLL_insert, GNUNET_CONTAINER_DLL_insert_tail, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CONTAINER_multipeermap_get(), GNUNET_CONTAINER_multipeermap_put(), GNUNET_CONTAINER_multipeermap_size(), GNUNET_CRYPTO_hash(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_MAX, GNUNET_memcmp, GNUNET_new, GNUNET_NO, GNUNET_OK, GNUNET_SCHEDULER_add_now(), GNUNET_STATISTICS_update(), GNUNET_YES, PeerBucket::head, k_buckets, MAX_BUCKETS, newly_found_peers, PeerBucket::peers_size, pi, pid, send_find_peer_message(), t, PeerBucket::tail, Target::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 819 of file gnunet-service-dht_neighbours.c.

820 {
821  struct Target *t = ctx;
822  struct PeerInfo *pi;
823  struct PeerBucket *bucket;
824  bool was_held = false;
825 
826  /* Check for disconnect from self message (on shutdown) */
827  if (NULL == t)
828  return;
829  pi = t->pi;
831  pi->t_tail,
832  t);
833  if (NULL != t->ph)
834  {
835  GDS_u_drop (t->u,
836  t->ph);
837  t->ph = NULL;
838  was_held = true;
839  }
840  if (t->load > 0)
841  {
842  t->dropped = true;
843  t->pi = NULL;
844  }
845  else
846  {
847  GNUNET_free (t);
848  }
849  if (NULL != pi->t_head)
850  return; /* got other connections still */
852  "Disconnected from peer %s\n",
853  GNUNET_i2s (&pi->id));
855  "# peers connected",
856  -1,
857  GNUNET_NO);
860  &pi->id,
861  pi));
864  {
866  find_peer_task = NULL;
867  }
868  GNUNET_assert (pi->peer_bucket >= 0);
869  bucket = &k_buckets[pi->peer_bucket];
871  bucket->tail,
872  pi);
873  GNUNET_assert (bucket->peers_size > 0);
874  bucket->peers_size--;
875  if ( (was_held) &&
876  (bucket->peers_size >= bucket_size - 1) )
877  update_hold (bucket);
878  while ( (closest_bucket > 0) &&
879  (0 == k_buckets[closest_bucket - 1].peers_size))
880  closest_bucket--;
881  GNUNET_free (pi->hello);
882  GNUNET_free (pi);
883 }
void GDS_u_drop(struct GDS_Underlay *u, struct GNUNET_DHTU_PreferenceHandle *ph)
Drop a hold ph from underlay u.
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.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:975

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, k_buckets, PeerBucket::peers_size, pi, t, 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 895 of file gnunet-service-dht_neighbours.c.

897 {
898  uint32_t random_value;
899  uint32_t forward_count;
900  float target_value;
901  float rm1;
902 
903  if (hop_count > GDS_NSE_get () * 4.0)
904  {
905  /* forcefully terminate */
907  "# requests TTL-dropped",
908  1,
909  GNUNET_NO);
910  return 0;
911  }
912  if (hop_count > GDS_NSE_get () * 2.0)
913  {
914  /* Once we have reached our ideal number of hops, only forward to 1 peer */
915  return 1;
916  }
917  /* bound by system-wide maximum and minimum */
918  if (0 == target_replication)
919  target_replication = 1; /* 0 is verboten */
920  target_replication =
922  target_replication);
923  rm1 = target_replication - 1.0;
924  target_value =
925  1 + (rm1) / (GDS_NSE_get () + (rm1 * hop_count));
926 
927  /* Set forward count to floor of target_value */
928  forward_count = (uint32_t) target_value;
929  /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */
930  target_value = target_value - forward_count;
932  UINT32_MAX);
933  if (random_value < (target_value * UINT32_MAX))
934  forward_count++;
935  return GNUNET_MIN (forward_count,
937 }
double GDS_NSE_get(void)
Return the current NSE.
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random value.
#define GNUNET_DHT_MAXIMUM_REPLICATION_LEVEL
Maximum allowed replication level for all requests.
#define GNUNET_MIN(a, b)

Referenced by get_target_peers().

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

953 {
955  key))
956  return GNUNET_YES;
957  for (int bucket_num = find_bucket (key);
958  bucket_num < closest_bucket;
959  bucket_num++)
960  {
961  unsigned int count = 0;
962 
963  GNUNET_assert (bucket_num >= 0);
964  for (struct PeerInfo *pos = k_buckets[bucket_num].head;
965  NULL != pos;
966  pos = pos->next)
967  {
968  if (count >= bucket_size)
969  break; /* we only consider first #bucket_size entries per bucket */
970  count++;
971  if ( (NULL != bloom) &&
972  (GNUNET_YES ==
974  &pos->phash)) )
975  continue; /* Ignore filtered peers */
976  /* All peers in this bucket must be closer than us, as
977  they mismatch with our PID on the pivotal bit. So
978  because an unfiltered peer exists, we are not the
979  closest. */
980  int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
982  key);
983  switch (delta)
984  {
985  case -1: /* pos closer */
986  return GNUNET_NO;
987  case 0: /* identical, impossible! */
988  GNUNET_assert (0);
989  break;
990  case 1: /* I am closer */
991  break;
992  }
993  }
994  }
995  /* No closer (unfiltered) peers found; we must be the closest! */
996  return GNUNET_YES;
997 }
static struct PendingResolutions * head
Head of list of pending resolution requests.
Definition: gnunet-ats.c:230
bool GNUNET_CONTAINER_bloomfilter_test(const struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_HashCode *e)
Test if an element is in the filter.
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).
Definition: crypto_hash.c:243
static struct GNUNET_TIME_Relative delta
Definition: speedup.c:36
struct PendingResolutions * next
Kept in a DLL.
Definition: gnunet-ats.c:159

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

Referenced by 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 1022 of file gnunet-service-dht_neighbours.c.

1025 {
1026  if (0 == closest_bucket)
1027  {
1029  "# Peer selection failed",
1030  1,
1031  GNUNET_NO);
1032  return NULL; /* we have zero connections */
1033  }
1034  if (hops >= GDS_NSE_get ())
1035  {
1036  /* greedy selection (closest peer that is not in Bloom filter) */
1037  struct PeerInfo *chosen = NULL;
1038  int best_bucket;
1039  int bucket_offset;
1040 
1041  {
1042  struct GNUNET_HashCode xor;
1043 
1046  &xor);
1047  best_bucket = GNUNET_CRYPTO_hash_count_leading_zeros (&xor);
1048  }
1049  if (best_bucket >= closest_bucket)
1050  bucket_offset = closest_bucket - 1;
1051  else
1052  bucket_offset = best_bucket;
1053  while (-1 != bucket_offset)
1054  {
1055  struct PeerBucket *bucket = &k_buckets[bucket_offset];
1056  unsigned int count = 0;
1057 
1058  for (struct PeerInfo *pos = bucket->head;
1059  NULL != pos;
1060  pos = pos->next)
1061  {
1062  if (count >= bucket_size)
1063  break; /* we only consider first #bucket_size entries per bucket */
1064  count++;
1065  if ( (NULL != bloom) &&
1066  (GNUNET_YES ==
1068  &pos->phash)) )
1069  {
1071  "Excluded peer `%s' due to BF match in greedy routing for %s\n",
1072  GNUNET_i2s (&pos->id),
1073  GNUNET_h2s (key));
1074  continue;
1075  }
1076  if (NULL == chosen)
1077  {
1078  /* First candidate */
1079  chosen = pos;
1080  }
1081  else
1082  {
1083  int delta = GNUNET_CRYPTO_hash_xorcmp (&pos->phash,
1084  &chosen->phash,
1085  key);
1086  switch (delta)
1087  {
1088  case -1: /* pos closer */
1089  chosen = pos;
1090  break;
1091  case 0: /* identical, impossible! */
1092  GNUNET_assert (0);
1093  break;
1094  case 1: /* chosen closer */
1095  break;
1096  }
1097  }
1098  count++;
1099  } /* for all (#bucket_size) peers in bucket */
1100  if (NULL != chosen)
1101  break;
1102 
1103  /* If we chose nothing in first iteration, first go through deeper
1104  buckets (best chance to find a good match), and if we still found
1105  nothing, then to shallower buckets. Terminate on any match in the
1106  current bucket, as this search order guarantees that it can only get
1107  worse as we keep going. */
1108  if (bucket_offset > best_bucket)
1109  {
1110  /* Go through more deeper buckets */
1111  bucket_offset++;
1112  if (bucket_offset == closest_bucket)
1113  {
1114  /* Can't go any deeper, if nothing selected,
1115  go for shallower buckets */
1116  bucket_offset = best_bucket - 1;
1117  }
1118  }
1119  else
1120  {
1121  /* We're either at the 'best_bucket' or already moving
1122  on to shallower buckets. */
1123  if (bucket_offset == best_bucket)
1124  bucket_offset++; /* go for deeper buckets */
1125  else
1126  bucket_offset--; /* go for shallower buckets */
1127  }
1128  } /* for applicable buckets (starting at best match) */
1129  if (NULL == chosen)
1130  {
1132  "# Peer selection failed",
1133  1,
1134  GNUNET_NO);
1135  return NULL;
1136  }
1138  "Selected peer `%s' in greedy routing for %s\n",
1139  GNUNET_i2s (&chosen->id),
1140  GNUNET_h2s (key));
1141  return chosen;
1142  } /* end of 'greedy' peer selection */
1143 
1144  /* select "random" peer */
1145  /* count number of peers that are available and not filtered,
1146  but limit to at most #bucket_size peers, starting with
1147  those 'furthest' from us. */
1148  {
1149  unsigned int total = 0;
1150  unsigned int selected;
1151 
1152  for (unsigned int bc = 0; bc < closest_bucket; bc++)
1153  {
1154  struct PeerBucket *bucket = &k_buckets[bc];
1155  unsigned int count = 0;
1156 
1157  for (struct PeerInfo *pos = bucket->head;
1158  NULL != pos;
1159  pos = pos->next)
1160  {
1161  count++;
1162  if (count > bucket_size)
1163  break; /* limits search to #bucket_size peers per bucket */
1164  if ( (NULL != bloom) &&
1165  (GNUNET_YES ==
1167  &pos->phash)) )
1168  {
1170  "Excluded peer `%s' due to BF match in random routing for %s\n",
1171  GNUNET_i2s (&pos->id),
1172  GNUNET_h2s (key));
1173  continue; /* Ignore filtered peers */
1174  }
1175  total++;
1176  } /* for all peers in bucket */
1177  } /* for all buckets */
1178  if (0 == total) /* No peers to select from! */
1179  {
1181  "# Peer selection failed",
1182  1,
1183  GNUNET_NO);
1184  return NULL;
1185  }
1186 
1187  /* Now actually choose a peer */
1189  total);
1190  for (unsigned int bc = 0; bc < closest_bucket; bc++)
1191  {
1192  unsigned int count = 0;
1193 
1194  for (struct PeerInfo *pos = k_buckets[bc].head;
1195  pos != NULL;
1196  pos = pos->next)
1197  {
1198  count++;
1199  if (count > bucket_size)
1200  break; /* limits search to #bucket_size peers per bucket */
1201 
1202  if ( (NULL != bloom) &&
1203  (GNUNET_YES ==
1205  &pos->phash)) )
1206  continue; /* Ignore bloomfiltered peers */
1207  if (0 == selected--)
1208  {
1210  "Selected peer `%s' in random routing for %s\n",
1211  GNUNET_i2s (&pos->id),
1212  GNUNET_h2s (key));
1213  return pos;
1214  }
1215  } /* for peers in bucket */
1216  } /* for all buckets */
1217  } /* random peer selection scope */
1218  GNUNET_break (0);
1219  return NULL;
1220 }
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
struct GNUNET_PeerIdentity id
What is the identity of the peer?
struct GNUNET_HashCode phash
Hash of id.

References bucket_size, closest_bucket, delta, GDS_my_identity_hash, GDS_NSE_get(), GDS_stats, GNUNET_assert, GNUNET_break, GNUNET_CONTAINER_bloomfilter_test(), GNUNET_CRYPTO_hash_count_leading_zeros(), GNUNET_CRYPTO_hash_xor(), GNUNET_CRYPTO_hash_xorcmp(), GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CRYPTO_random_u32(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_YES, head, PeerBucket::head, PeerInfo::id, k_buckets, key, PendingResolutions::next, 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 1237 of file gnunet-service-dht_neighbours.c.

1242 {
1243  unsigned int target;
1244  unsigned int off;
1245  struct PeerInfo **rtargets;
1246 
1247  GNUNET_assert (NULL != bloom);
1248  target = get_forward_count (hop_count,
1249  target_replication);
1250  if (0 == target)
1251  {
1252  *targets = NULL;
1253  return 0;
1254  }
1255  rtargets = GNUNET_new_array (target,
1256  struct PeerInfo *);
1257  for (off = 0; off < target; off++)
1258  {
1259  struct PeerInfo *nxt;
1260 
1261  nxt = select_peer (key,
1262  bloom,
1263  hop_count);
1264  if (NULL == nxt)
1265  break;
1266  rtargets[off] = nxt;
1269  &nxt->phash));
1271  &nxt->phash);
1272  }
1274  "Selected %u/%u peers at hop %u for %s (target was %u)\n",
1275  off,
1277  (unsigned int) hop_count,
1278  GNUNET_h2s (key),
1279  target);
1280  if (0 == off)
1281  {
1282  GNUNET_free (rtargets);
1283  *targets = NULL;
1284  return 0;
1285  }
1286  *targets = rtargets;
1288  "Forwarding query `%s' to %u peers (goal was %u peers)\n",
1289  GNUNET_h2s (key),
1290  off,
1291  target);
1292  return off;
1293 }
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 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...
void GNUNET_CONTAINER_bloomfilter_add(struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_HashCode *e)
Add an element to the filter.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.

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

Here is the call 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 1302 of file gnunet-service-dht_neighbours.c.

1303 {
1304  struct GNUNET_PeerIdentity pid;
1305  struct GNUNET_HELLO_Builder *b;
1306 
1307  if (GNUNET_BLOCK_TYPE_DHT_HELLO != bd->type)
1308  return;
1309 
1311  bd->data_size);
1314  &pid,
1315  &GDS_try_connect,
1316  &pid);
1318 }
void GDS_try_connect(void *cls, const char *uri)
Callback function used to extract URIs from a builder.
struct GNUNET_HELLO_Builder * GNUNET_HELLO_builder_from_block(const void *block, size_t block_size)
Parse block into builder.
Definition: hello-uri.c:360
void GNUNET_HELLO_builder_free(struct GNUNET_HELLO_Builder *builder)
Release resources of a builder.
Definition: hello-uri.c:319
void GNUNET_HELLO_builder_iterate(const struct GNUNET_HELLO_Builder *builder, struct GNUNET_PeerIdentity *pid, GNUNET_HELLO_UriCallback uc, void *uc_cls)
Iterate over URIs in a builder.
Definition: hello-uri.c:822
enum GNUNET_BLOCK_Type type
Type of the block.
const void * data
Actual block data.
size_t data_size
Number of bytes in data.
Context for building (or parsing) HELLO URIs.
Definition: hello-uri.c:184
The identity of the host (wraps the signing key of the peer).

Referenced by check_dht_p2p_hello().

Here is the caller graph for this function:

◆ GDS_NEIGHBOURS_handle_put()

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

Perform a PUT operation.

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

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

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

1326 {
1327  unsigned int target_count;
1328  struct PeerInfo **targets;
1329  size_t msize;
1330  unsigned int skip_count;
1331  enum GNUNET_DHT_RouteOption ro = bd->ro;
1332  unsigned int put_path_length = bd->put_path_length;
1333  const struct GNUNET_DHT_PathElement *put_path = bd->put_path;
1334  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1335  bool tracking = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1336  const struct GNUNET_PeerIdentity *trunc_peer
1337  = truncated
1338  ? &bd->trunc_peer
1339  : NULL;
1340 
1341 #if SANITY_CHECKS > 1
1342  unsigned int failure_offset;
1343 
1344  failure_offset
1346  bd->data_size,
1347  bd->expiration_time,
1348  trunc_peer,
1349  put_path,
1350  put_path_length,
1351  NULL, 0, /* get_path */
1352  &GDS_my_identity);
1353  if (0 != failure_offset)
1354  {
1355  GNUNET_break_op (0);
1356  truncated = true;
1357  trunc_peer = &put_path[failure_offset - 1].pred;
1358  put_path = &put_path[failure_offset];
1359  put_path_length = put_path_length - failure_offset;
1361  }
1362 #endif
1364  "Adding myself (%s) to PUT bloomfilter for %s with RO(%s/%s)\n",
1366  GNUNET_h2s (&bd->key),
1367  (bd->ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1368  (bd->ro & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1369 
1370  /* if we got a HELLO, consider it for our own routing table */
1371  hello_check (bd);
1372  GNUNET_assert (NULL != bf);
1376  "# PUT requests routed",
1377  1,
1378  GNUNET_NO);
1379  if (bd->data_size
1381  - sizeof(struct PeerPutMessage))
1382  {
1383  GNUNET_break (0);
1384  return GNUNET_SYSERR;
1385  }
1386  msize = bd->data_size + sizeof(struct PeerPutMessage);
1387  if (tracking)
1388  {
1389  if (msize + sizeof (struct GNUNET_CRYPTO_EddsaSignature)
1391  {
1393  "Discarding message that is too large due to tracking\n");
1394  return GNUNET_NO;
1395  }
1396  msize += sizeof (struct GNUNET_CRYPTO_EddsaSignature);
1397  }
1398  else
1399  {
1400  /* If tracking is disabled, also discard any path we might have
1401  gotten from some broken peer */
1402  GNUNET_break_op (0 == put_path_length);
1403  put_path_length = 0;
1404  }
1405  if (truncated)
1406  msize += sizeof (struct GNUNET_PeerIdentity);
1407  if (msize + put_path_length * sizeof(struct GNUNET_DHT_PathElement)
1409  {
1410  unsigned int mlen;
1411  unsigned int ppl;
1412 
1414  "Truncating path that is too large due\n");
1416  if (! truncated)
1417  {
1418  /* We need extra space for the truncation, consider that,
1419  too! */
1420  truncated = true;
1421  mlen -= sizeof (struct GNUNET_PeerIdentity);
1422  msize += sizeof (struct GNUNET_PeerIdentity);
1423  }
1424  /* compute maximum length of path we can keep */
1425  ppl = mlen / sizeof (struct GNUNET_DHT_PathElement);
1426  GNUNET_assert (put_path_length - ppl > 0);
1427  trunc_peer = &put_path[put_path_length - ppl - 1].pred;
1428  put_path = &put_path[put_path_length - ppl];
1429  put_path_length = ppl;
1431  }
1432  else
1433  {
1434  msize += bd->put_path_length * sizeof(struct GNUNET_DHT_PathElement);
1435  }
1436  target_count
1437  = get_target_peers (&bd->key,
1438  bf,
1439  hop_count,
1440  desired_replication_level,
1441  &targets);
1442  if (0 == target_count)
1443  {
1445  "Routing PUT for %s terminates after %u hops at %s\n",
1446  GNUNET_h2s (&bd->key),
1447  (unsigned int) hop_count,
1449  return GNUNET_NO;
1450  }
1451  skip_count = 0;
1452  for (unsigned int i = 0; i < target_count; i++)
1453  {
1454  struct PeerInfo *target = targets[i];
1455  struct PeerPutMessage *ppm;
1456  char buf[msize] GNUNET_ALIGN;
1457  struct GNUNET_DHT_PathElement *pp;
1458  void *data;
1459 
1461  "Routing PUT for %s after %u hops to %s\n",
1462  GNUNET_h2s (&bd->key),
1463  (unsigned int) hop_count,
1464  GNUNET_i2s (&target->id));
1465  ppm = (struct PeerPutMessage *) buf;
1467  ppm->header.size = htons (sizeof (buf));
1468  ppm->type = htonl (bd->type);
1469  ppm->options = htons (ro);
1470  ppm->hop_count = htons (hop_count + 1);
1472  ppm->put_path_length = htons (put_path_length);
1476  &target->phash));
1479  ppm->bloomfilter,
1480  DHT_BLOOM_SIZE));
1481  ppm->key = bd->key;
1482  if (truncated)
1483  {
1484  void *tgt = &ppm[1];
1485 
1486  GNUNET_memcpy (tgt,
1487  trunc_peer,
1488  sizeof (struct GNUNET_PeerIdentity));
1489  pp = (struct GNUNET_DHT_PathElement *)
1490  (tgt + sizeof (struct GNUNET_PeerIdentity));
1491  }
1492  else
1493  {
1494  pp = (struct GNUNET_DHT_PathElement *) &ppm[1];
1495  }
1496  GNUNET_memcpy (pp,
1497  put_path,
1498  sizeof (struct GNUNET_DHT_PathElement) * put_path_length);
1499  if (tracking)
1500  {
1501  void *tgt = &pp[put_path_length];
1502  struct GNUNET_CRYPTO_EddsaSignature last_sig;
1503 
1504  if (0 == put_path_length)
1505  {
1506  /* Note that the signature in 'put_path' was not initialized before,
1507  so this is crucial to avoid sending garbage. */
1508  sign_path (bd->data,
1509  bd->data_size,
1510  bd->expiration_time,
1511  trunc_peer,
1512  &target->id,
1513  &last_sig);
1514  }
1515  else
1516  {
1517  sign_path (bd->data,
1518  bd->data_size,
1519  bd->expiration_time,
1520  &pp[put_path_length - 1].pred,
1521  &target->id,
1522  &last_sig);
1523  }
1525  "Signing PUT PATH %u => %s\n",
1526  put_path_length,
1527  GNUNET_B2S (&last_sig));
1528  memcpy (tgt,
1529  &last_sig,
1530  sizeof (last_sig));
1531  data = tgt + sizeof (last_sig);
1532  }
1533  else /* ! tracking */
1534  {
1535  data = &ppm[1];
1536  }
1538  bd->data,
1539  bd->data_size);
1540  do_send (target,
1541  &ppm->header);
1542  }
1543  GNUNET_free (targets);
1545  "# PUT messages queued for transmission",
1546  target_count - skip_count,
1547  GNUNET_NO);
1548  return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1549 }
static void do_send(struct PeerInfo *pi, const struct GNUNET_MessageHeader *msg)
Send msg to pi.
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 sign_path(const void *data, size_t data_size, struct GNUNET_TIME_Absolute exp_time, const struct GNUNET_PeerIdentity *pred, const struct GNUNET_PeerIdentity *succ, struct GNUNET_CRYPTO_EddsaSignature *sig)
Sign that we are routing a message from pred to succ.
static char buf[2048]
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.
#define GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE
What is the maximum size for encrypted messages? Note that this number imposes a clear limit on the m...
GNUNET_DHT_RouteOption
Options for routing.
unsigned int GNUNET_DHT_verify_path(const void *data, size_t data_size, struct GNUNET_TIME_Absolute exp_time, const struct GNUNET_PeerIdentity *bpid, 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:1353
@ GNUNET_DHT_RO_TRUNCATED
Flag set if the path was truncated.
@ 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_B2S(obj)
Convert a fixed-sized object to a string using GNUNET_b2s().
#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_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_MESSAGE_TYPE_DHT_P2P_PUT
Peer is storing data in DHT.
an ECC signature using EdDSA.
const struct GNUNET_DHT_PathElement * put_path
PUT path taken by the block, array of peer identities.
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.
unsigned int put_path_length
Length of the put_path array.
struct GNUNET_TIME_Absolute expiration_time
When does the block expire?
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).
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
uint16_t desired_replication_level
Replication level for this message.
uint16_t hop_count
Hop count.
uint32_t type
Content type, must not be zero.
char bloomfilter[128]
Bloomfilter (for peer identities) to stop circular routes.
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_DHT_P2P_PUT.
struct GNUNET_HashCode key
The key we are storing under.
uint16_t options
Processing options.
struct GNUNET_TIME_AbsoluteNBO expiration_time
When does the content expire?
uint16_t put_path_length
Length of the PUT path that follows (if tracked).

Referenced by handle_dht_local_put(), and handle_dht_p2p_put().

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

1562 {
1563  unsigned int target_count;
1564  struct PeerInfo **targets;
1565  size_t msize;
1566  size_t result_filter_size;
1567  void *result_filter;
1568  unsigned int skip_count;
1569 
1570  GNUNET_assert (NULL != peer_bf);
1572  "# GET requests routed",
1573  1,
1574  GNUNET_NO);
1575  target_count = get_target_peers (key,
1576  peer_bf,
1577  hop_count,
1578  desired_replication_level,
1579  &targets);
1581  "Adding myself (%s) to GET bloomfilter for %s with RO(%s/%s)\n",
1583  GNUNET_h2s (key),
1585  (options & GNUNET_DHT_RO_RECORD_ROUTE) ? "R" : "-");
1586 
1589  if (0 == target_count)
1590  {
1592  "Routing GET for %s terminates after %u hops at %s\n",
1593  GNUNET_h2s (key),
1594  (unsigned int) hop_count,
1596  return GNUNET_NO;
1597  }
1598  if (GNUNET_OK !=
1600  &result_filter,
1601  &result_filter_size))
1602  {
1603  result_filter = NULL;
1604  result_filter_size = 0;
1605  }
1606  msize = xquery_size + result_filter_size;
1607  if (msize + sizeof(struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
1608  {
1609  GNUNET_break (0);
1610  GNUNET_free (result_filter);
1611  GNUNET_free (targets);
1612  return GNUNET_NO;
1613  }
1614  /* forward request */
1615  skip_count = 0;
1616  for (unsigned int i = 0; i < target_count; i++)
1617  {
1618  struct PeerInfo *target = targets[i];
1619  struct PeerGetMessage *pgm;
1620  char buf[sizeof (*pgm) + msize] GNUNET_ALIGN;
1621  char *rf;
1622 
1624  "Routing GET for %s after %u hops to %s\n",
1625  GNUNET_h2s (key),
1626  (unsigned int) hop_count,
1627  GNUNET_i2s (&target->id));
1628  pgm = (struct PeerGetMessage *) buf;
1630  pgm->header.size = htons (sizeof (buf));
1631  pgm->type = htonl (type);
1632  pgm->options = htons (options);
1633  pgm->hop_count = htons (hop_count + 1);
1635  pgm->result_filter_size = htons ((uint16_t) result_filter_size);
1638  &target->phash));
1641  pgm->bloomfilter,
1642  DHT_BLOOM_SIZE));
1643  pgm->key = *key;
1644  rf = (char *) &pgm[1];
1645  GNUNET_memcpy (rf,
1646  result_filter,
1649  xquery,
1650  xquery_size);
1651  do_send (target,
1652  &pgm->header);
1653  }
1655  "# GET messages queued for transmission",
1656  target_count - skip_count,
1657  GNUNET_NO);
1658  GNUNET_free (targets);
1659  GNUNET_free (result_filter);
1660  return (skip_count < target_count) ? GNUNET_OK : GNUNET_NO;
1661 }
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
#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_serialize(struct GNUNET_BLOCK_Group *bg, void **raw_data, size_t *raw_data_size)
Serialize state of a block group.
Definition: block.c:175
#define GNUNET_MESSAGE_TYPE_DHT_P2P_GET
Peer tries to find data in DHT.
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 hop_count
Hop count.
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.
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model

References GNUNET_DATACACHE_Block::data, GNUNET_DATACACHE_Block::data_size, disable_try_connect, GDS_try_connect(), GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_HELLO_builder_free(), GNUNET_HELLO_builder_from_block(), GNUNET_HELLO_builder_iterate(), GNUNET_YES, pid, and GNUNET_DATACACHE_Block::type.

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

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

◆ GDS_NEIGHBOURS_lookup_peer()

struct PeerInfo* GDS_NEIGHBOURS_lookup_peer ( const struct GNUNET_PeerIdentity target)

Lookup peer by peer's identity.

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

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

1666 {
1668  target);
1669 }

References all_connected_peers, and GNUNET_CONTAINER_multipeermap_get().

Here is the call graph for this function:

◆ GDS_NEIGHBOURS_handle_reply()

bool GDS_NEIGHBOURS_handle_reply ( struct PeerInfo pi,
const struct GNUNET_DATACACHE_Block bd,
const struct GNUNET_HashCode query_hash,
unsigned int  get_path_length,
const struct GNUNET_DHT_PathElement get_path 
)

Handle a reply (route to origin).

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

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

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

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

Referenced by check_dht_p2p_get(), handle_find_local_hello(), and handle_find_my_hello().

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

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

References buf, GNUNET_DATACACHE_Block::data, data, data_size, GNUNET_DATACACHE_Block::data_size, do_send(), PeerResultMessage::expiration_time, GNUNET_DATACACHE_Block::expiration_time, GDS_my_identity, GDS_stats, PeerResultMessage::get_path_length, GNUNET_ALIGN, GNUNET_assert, GNUNET_B2S, GNUNET_break, GNUNET_break_op, GNUNET_DHT_RO_RECORD_ROUTE, GNUNET_DHT_RO_TRUNCATED, GNUNET_DHT_verify_path(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_MAX_MESSAGE_SIZE, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT, GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_hton(), PeerResultMessage::header, PeerResultMessage::key, PeerResultMessage::options, pi, GNUNET_DHT_PathElement::pred, GNUNET_DATACACHE_Block::put_path, PeerResultMessage::put_path_length, GNUNET_DATACACHE_Block::put_path_length, PeerResultMessage::reserved, GNUNET_DATACACHE_Block::ro, GNUNET_DHT_PathElement::sig, sign_path(), GNUNET_MessageHeader::size, GNUNET_DATACACHE_Block::trunc_peer, PeerResultMessage::type, GNUNET_MessageHeader::type, and GNUNET_DATACACHE_Block::type.

Here is the call 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 1944 of file gnunet-service-dht_neighbours.c.

1946 {
1947  struct Target *t = cls;
1948  struct PeerInfo *peer = t->pi;
1949  enum GNUNET_DHT_RouteOption ro
1950  = (enum GNUNET_DHT_RouteOption) ntohs (put->options);
1951  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
1952  bool has_path = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
1953  uint16_t msize = ntohs (put->header.size);
1954  uint16_t putlen = ntohs (put->put_path_length);
1955  const struct GNUNET_PeerIdentity *trunc_peer
1956  = truncated
1957  ? (const struct GNUNET_PeerIdentity *) &put[1]
1958  : NULL;
1959  const struct GNUNET_DHT_PathElement *put_path
1960  = truncated
1961  ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
1962  : (const struct GNUNET_DHT_PathElement *) &put[1];
1963  const struct GNUNET_CRYPTO_EddsaSignature *last_sig
1964  = has_path
1965  ? (const struct GNUNET_CRYPTO_EddsaSignature *) &put_path[putlen]
1966  : NULL;
1967  const char *data
1968  = has_path
1969  ? (const char *) &last_sig[1]
1970  : (const char *) &put_path[putlen];
1971  size_t var_meta_size
1972  = putlen * sizeof(struct GNUNET_DHT_PathElement)
1973  + (has_path ? sizeof (*last_sig) : 0)
1974  + (truncated ? sizeof (*trunc_peer) : 0);
1975  struct GNUNET_DATACACHE_Block bd = {
1976  .key = put->key,
1977  .expiration_time = GNUNET_TIME_absolute_ntoh (put->expiration_time),
1978  .type = ntohl (put->type),
1979  .ro = ro,
1980  .data_size = msize - sizeof(*put) - var_meta_size,
1981  .data = data
1982  };
1983 
1984  if (NULL != trunc_peer)
1985  bd.trunc_peer = *trunc_peer;
1987  "PUT for `%s' from %s with RO (%s/%s)\n",
1988  GNUNET_h2s (&put->key),
1989  GNUNET_i2s (&peer->id),
1990  (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE) ? "x" : "-",
1991  has_path ? "R" : "-");
1993  {
1995  "# Expired PUTs discarded",
1996  1,
1997  GNUNET_NO);
1998  return;
1999  }
2000  {
2001  /* Only call 'check_block' if that keeps our CPU load (from
2002  the cryptography) below 50% on average */
2003  static struct GNUNET_TIME_Relative avg_latency;
2004  static struct GNUNET_TIME_Absolute next_time;
2005 
2006  if (GNUNET_TIME_absolute_is_past (next_time))
2007  {
2008  struct GNUNET_TIME_Absolute now
2010  struct GNUNET_TIME_Relative latency;
2011  struct GNUNET_TIME_Relative delta;
2012 
2013  if (GNUNET_NO ==
2015  bd.type,
2016  bd.data,
2017  bd.data_size))
2018  {
2019  GNUNET_break_op (0);
2020  return;
2021  }
2022  latency = GNUNET_TIME_absolute_get_duration (now);
2023  /* Use *moving average* to estimate check_block latency */
2024  avg_latency
2027  GNUNET_TIME_relative_multiply (avg_latency,
2028  7),
2029  latency),
2030  8);
2031  /* average delay = 50% of avg_latency => 50% CPU load from crypto (at most) */
2034  avg_latency.rel_value_us > 0
2035  ? avg_latency.rel_value_us
2036  : 1LLU);
2038  }
2039  }
2040  if (! has_path)
2041  putlen = 0;
2043  "# P2P PUT requests received",
2044  1,
2045  GNUNET_NO);
2047  "# P2P PUT bytes received",
2048  msize,
2049  GNUNET_NO);
2050  {
2051  struct GNUNET_HashCode test_key;
2053 
2055  bd.type,
2056  bd.data,
2057  bd.data_size,
2058  &test_key);
2059  switch (ret)
2060  {
2061  case GNUNET_YES:
2062  if (0 != GNUNET_memcmp (&test_key,
2063  &bd.key))
2064  {
2065  GNUNET_break_op (0);
2066  return;
2067  }
2068  break;
2069  case GNUNET_NO:
2070  /* cannot verify, good luck */
2071  break;
2072  case GNUNET_SYSERR:
2073  /* block type not supported, good luck */
2074  break;
2075  }
2076  }
2077 
2078  {
2079  struct GNUNET_CONTAINER_BloomFilter *bf;
2080  struct GNUNET_DHT_PathElement pp[putlen + 1];
2081 
2087  &peer->phash));
2088  /* extend 'put path' by sender */
2089  bd.put_path = pp;
2090  bd.put_path_length = putlen + 1;
2091  if (has_path)
2092  {
2093  unsigned int failure_offset;
2094 
2095  GNUNET_memcpy (pp,
2096  put_path,
2097  putlen * sizeof(struct GNUNET_DHT_PathElement));
2098  pp[putlen].pred = peer->id;
2099  pp[putlen].sig = *last_sig;
2100 #if SANITY_CHECKS
2101  /* TODO: might want to eventually implement probabilistic
2102  load-based path verification, but for now it is all or nothing */
2103  failure_offset
2105  bd.data_size,
2106  bd.expiration_time,
2107  trunc_peer,
2108  pp,
2109  putlen + 1,
2110  NULL, 0, /* get_path */
2111  &GDS_my_identity);
2112 #else
2113  failure_offset = 0;
2114 #endif
2115  if (0 != failure_offset)
2116  {
2117  GNUNET_break_op (0);
2119  "Recorded put path invalid at offset %u, truncating\n",
2120  failure_offset);
2121  GNUNET_assert (failure_offset <= putlen + 1);
2122  bd.put_path = &pp[failure_offset];
2123  bd.put_path_length = (putlen + 1) - failure_offset;
2125  bd.trunc_peer = pp[failure_offset - 1].pred;
2126  }
2127  }
2128  else
2129  {
2130  bd.put_path_length = 0;
2131  }
2132 
2133  /* give to local clients */
2135  &bd.key,
2136  0, NULL /* get path */));
2137 
2138  /* store locally */
2139  if ( (0 != (bd.ro & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) ||
2140  (GDS_am_closest_peer (&put->key,
2141  bf)) )
2143  {
2144  enum GNUNET_GenericReturnValue forwarded;
2145 
2146  /* route to other peers */
2147  forwarded
2149  ntohs (put->desired_replication_level),
2150  ntohs (put->hop_count),
2151  bf);
2152  /* notify monitoring clients */
2153  bd.ro |= ((GNUNET_OK == forwarded)
2155  : 0);
2157  ntohs (put->hop_count),
2158  ntohs (put->desired_replication_level));
2159  }
2161  }
2162 }
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
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.
void GDS_DATACACHE_handle_put(const struct GNUNET_DATACACHE_Block *bd)
Handle a datum we've received from another peer.
enum GNUNET_GenericReturnValue GDS_NEIGHBOURS_handle_put(const struct GNUNET_DATACACHE_Block *bd, uint16_t desired_replication_level, uint16_t hop_count, struct GNUNET_CONTAINER_BloomFilter *bf)
Perform a PUT operation.
enum GNUNET_GenericReturnValue GDS_am_closest_peer(const struct GNUNET_HashCode *key, const struct GNUNET_CONTAINER_BloomFilter *bloom)
Check whether my identity is closer than any known peers.
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:319
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:276
@ GNUNET_DHT_RO_LAST_HOP
Flag given to monitors if this was the last hop for a GET/PUT.
GNUNET_GenericReturnValue
Named constants for return values.
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:436
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:585
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_divide(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Divide relative time by a given factor.
Definition: time.c:550
bool GNUNET_TIME_absolute_is_past(struct GNUNET_TIME_Absolute abs)
Test if abs is truly in the past (excluding now).
Definition: time.c:669
Information about a block stored in the datacache.
Time for absolute times used by GNUnet, in microseconds.
struct GNUNET_TESTBED_Peer * peer
The peer associated with this model.

References PeerPutMessage::bloomfilter, GNUNET_DATACACHE_Block::data, data, GNUNET_DATACACHE_Block::data_size, delta, PeerPutMessage::desired_replication_level, DHT_BLOOM_SIZE, PeerPutMessage::expiration_time, GNUNET_DATACACHE_Block::expiration_time, GDS_am_closest_peer(), GDS_block_context, GDS_CLIENTS_handle_reply(), GDS_CLIENTS_process_put(), GDS_DATACACHE_handle_put(), GDS_my_identity, GDS_NEIGHBOURS_handle_put(), GDS_stats, GNUNET_assert, GNUNET_BLOCK_check_block(), GNUNET_BLOCK_get_key(), GNUNET_break, GNUNET_break_op, GNUNET_CONSTANTS_BLOOMFILTER_K, GNUNET_CONTAINER_bloomfilter_free(), GNUNET_CONTAINER_bloomfilter_init(), GNUNET_CONTAINER_bloomfilter_test(), GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CRYPTO_random_u64(), GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, GNUNET_DHT_RO_LAST_HOP, GNUNET_DHT_RO_RECORD_ROUTE, GNUNET_DHT_RO_TRUNCATED, GNUNET_DHT_verify_path(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_memcmp, GNUNET_memcpy, GNUNET_NO, GNUNET_OK, GNUNET_STATISTICS_update(), GNUNET_SYSERR, GNUNET_TIME_absolute_get(), GNUNET_TIME_absolute_get_duration(), GNUNET_TIME_absolute_is_past(), GNUNET_TIME_absolute_ntoh(), GNUNET_TIME_relative_add(), GNUNET_TIME_relative_divide(), GNUNET_TIME_relative_multiply(), GNUNET_TIME_relative_to_absolute(), GNUNET_YES, PeerPutMessage::header, PeerPutMessage::hop_count, PeerPutMessage::key, GNUNET_DATACACHE_Block::key, PeerPutMessage::options, peer, GNUNET_DHT_PathElement::pred, GNUNET_DATACACHE_Block::put_path, PeerPutMessage::put_path_length, GNUNET_DATACACHE_Block::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, PeerPutMessage::type, and GNUNET_DATACACHE_Block::type.

Here is the call graph for this function:

◆ handle_find_my_hello()

static void handle_find_my_hello ( struct PeerInfo pi,
const struct GNUNET_HashCode query_hash,
struct GNUNET_BLOCK_Group bg 
)
static

We have received a request for a HELLO.

Sends our HELLO back.

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

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

2177 {
2178  size_t block_size = 0;
2179 
2180  /* TODO: consider caching our HELLO block for a bit, to
2181  avoid signing too often here... */
2185  NULL,
2186  &block_size));
2187  {
2188  char block[block_size];
2189 
2190  if (GNUNET_OK !=
2193  block,
2194  &block_size))
2195  {
2197  "# FIND PEER requests ignored due to lack of HELLO",
2198  1,
2199  GNUNET_NO);
2200  }
2201  else if (GNUNET_BLOCK_REPLY_OK_MORE ==
2204  bg,
2206  NULL, 0,
2207  block,
2208  block_size))
2209  {
2210  struct GNUNET_DATACACHE_Block bd = {
2212  .expiration_time
2215  .key = GDS_my_identity_hash,
2216  .data = block,
2217  .data_size = block_size
2218  };
2219 
2221  &bd,
2222  query_hash,
2223  0, NULL /* get path */));
2224  }
2225  else
2226  {
2228  "# FIND PEER requests ignored due to Bloomfilter",
2229  1,
2230  GNUNET_NO);
2231  }
2232  }
2233 }
struct GNUNET_HELLO_Builder * GDS_my_hello
Our HELLO.
bool GDS_NEIGHBOURS_handle_reply(struct PeerInfo *pi, const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path)
Handle a reply (route to origin).
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:337
@ GNUNET_BLOCK_REPLY_OK_MORE
Valid result, and there may be more.
#define GNUNET_HELLO_ADDRESS_EXPIRATION
For how long are HELLO signatures valid?
enum GNUNET_GenericReturnValue GNUNET_HELLO_builder_to_block(const struct GNUNET_HELLO_Builder *builder, const struct GNUNET_CRYPTO_EddsaPrivateKey *priv, void *block, size_t *block_size)
Generate DHT block from a builder.
Definition: hello-uri.c:699

References GDS_block_context, GDS_my_hello, GDS_my_identity_hash, GDS_my_private_key, GDS_NEIGHBOURS_handle_reply(), GDS_stats, GNUNET_BLOCK_check_reply(), GNUNET_BLOCK_REPLY_OK_MORE, GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_break, GNUNET_HELLO_ADDRESS_EXPIRATION, GNUNET_HELLO_builder_to_block(), GNUNET_NO, GNUNET_OK, GNUNET_STATISTICS_update(), GNUNET_TIME_relative_to_absolute(), pi, and GNUNET_DATACACHE_Block::type.

Referenced by handle_dht_p2p_get().

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

◆ handle_find_local_hello()

static void handle_find_local_hello ( struct PeerInfo pi,
const struct GNUNET_HashCode query_hash,
struct GNUNET_BLOCK_Group bg 
)
static

We have received a request for nearby HELLOs.

Sends matching HELLOs back.

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

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

2248 {
2249  /* Force non-random selection by hop count */
2250  struct PeerInfo *peer;
2251 
2252  peer = select_peer (query_hash,
2253  NULL,
2254  GDS_NSE_get () + 1);
2255  if ( (NULL != peer->hello) &&
2256  (! GNUNET_TIME_absolute_is_past (peer->hello_expiration)) &&
2261  bg,
2262  &peer->phash,
2263  NULL, 0, /* xquery */
2264  peer->hello,
2265  peer->hello_size)) )
2266  {
2267  struct GNUNET_DATACACHE_Block bd = {
2269  .expiration_time = peer->hello_expiration,
2270  .key = peer->phash,
2271  .data = peer->hello,
2272  .data_size = peer->hello_size
2273  };
2274 
2276  &bd,
2277  query_hash,
2278  0, NULL /* get path */));
2279  }
2280 }

References GDS_block_context, GDS_NEIGHBOURS_handle_reply(), GDS_NSE_get(), GNUNET_BLOCK_check_reply(), GNUNET_BLOCK_REPLY_OK_MORE, GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_break, GNUNET_TIME_absolute_is_past(), peer, pi, select_peer(), and GNUNET_DATACACHE_Block::type.

Referenced by handle_dht_p2p_get().

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

◆ handle_local_result()

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

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

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

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

2292 {
2293  struct PeerInfo *peer = cls;
2294 
2296  bd,
2297  &bd->key,
2298  0, NULL /* get path */));
2299 }

Referenced by handle_dht_p2p_get().

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

2312 {
2313  uint16_t msize = ntohs (get->header.size);
2314  uint16_t result_filter_size = ntohs (get->result_filter_size);
2315 
2316  (void) cls;
2317  if (msize < sizeof(*get) + result_filter_size)
2318  {
2319  GNUNET_break_op (0);
2320  return GNUNET_SYSERR;
2321  }
2322  return GNUNET_OK;
2323 }
static int get
Get DID Documement for DID Flag.
Definition: gnunet-did.c:66

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

Here is the call 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 2333 of file gnunet-service-dht_neighbours.c.

2335 {
2336  struct Target *t = cls;
2337  struct PeerInfo *peer = t->pi;
2338  uint16_t msize = ntohs (get->header.size);
2339  uint16_t result_filter_size = ntohs (get->result_filter_size);
2340  uint16_t hop_count = ntohs (get->hop_count);
2341  enum GNUNET_BLOCK_Type type = (enum GNUNET_BLOCK_Type) ntohl (get->type);
2343  get->options);
2345  const void *result_filter = (const void *) &get[1];
2346  const void *xquery = result_filter + result_filter_size;
2347  size_t xquery_size = msize - sizeof (*get) - result_filter_size;
2348 
2349  /* parse and validate message */
2351  "# P2P GET requests received",
2352  1,
2353  GNUNET_NO);
2355  "# P2P GET bytes received",
2356  msize,
2357  GNUNET_NO);
2358  if (GNUNET_NO ==
2360  type,
2361  &get->key,
2362  xquery,
2363  xquery_size))
2364  {
2365  /* request invalid */
2366  GNUNET_break_op (0);
2367  return;
2368  }
2369 
2370  {
2371  struct GNUNET_BLOCK_Group *bg;
2372  struct GNUNET_CONTAINER_BloomFilter *peer_bf;
2373 
2374  peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter,
2379  &peer->phash));
2381  type,
2382  result_filter,
2383  result_filter_size,
2384  "filter-size",
2385  result_filter_size,
2386  NULL);
2388  "GET for %s at %s after %u hops\n",
2389  GNUNET_h2s (&get->key),
2391  (unsigned int) hop_count);
2392  /* local lookup (this may update the bg) */
2394  (GDS_am_closest_peer (&get->key,
2395  peer_bf)) )
2396  {
2397  if ( (GNUNET_BLOCK_TYPE_DHT_HELLO == type) ||
2399  {
2401  "# P2P HELLO lookup requests processed",
2402  1,
2403  GNUNET_NO);
2405  &get->key,
2406  bg);
2409  &get->key,
2410  bg);
2411  }
2413  {
2415  eval = GDS_DATACACHE_get_closest (&get->key,
2416  type,
2417  xquery,
2418  xquery_size,
2419  bg,
2421  peer);
2422  else
2423  eval = GDS_DATACACHE_handle_get (&get->key,
2424  type,
2425  xquery,
2426  xquery_size,
2427  bg,
2429  peer);
2430  }
2431  }
2432  else
2433  {
2435  "# P2P GET requests ONLY routed",
2436  1,
2437  GNUNET_NO);
2438  }
2439 
2440  /* remember request for routing replies
2441  TODO: why should we do this if GNUNET_BLOCK_REPLY_OK_LAST == eval?
2442  */
2443  GDS_ROUTING_add (&peer->id,
2444  type,
2445  bg, /* bg now owned by routing, but valid at least until end of this function! */
2446  options,
2447  &get->key,
2448  xquery,
2449  xquery_size);
2450 
2451  /* P2P forwarding */
2452  {
2453  bool forwarded = false;
2454  uint16_t desired_replication_level = ntohs (
2455  get->desired_replication_level);
2456 
2457  if (eval != GNUNET_BLOCK_REPLY_OK_LAST)
2458  forwarded = (GNUNET_OK ==
2460  options,
2461  desired_replication_level,
2462  hop_count,
2463  &get->key,
2464  xquery,
2465  xquery_size,
2466  bg,
2467  peer_bf));
2469  options
2470  | (forwarded
2471  ? 0
2473  type,
2474  hop_count,
2475  desired_replication_level,
2476  &get->key);
2477  }
2478  /* clean up; note that 'bg' is owned by routing now! */
2480  }
2481 }
GNUNET_BLOCK_Type
WARNING: This header is generated! In order to add DHT block types, you must register them in GANA,...
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.
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.
static void handle_find_local_hello(struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg)
We have received a request for nearby HELLOs.
static void handle_local_result(void *cls, const struct GNUNET_DATACACHE_Block *bd)
Handle an exact result from local datacache for a GET operation.
static void handle_find_my_hello(struct PeerInfo *pi, const struct GNUNET_HashCode *query_hash, struct GNUNET_BLOCK_Group *bg)
We have received a request for a HELLO.
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.
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:296
GNUNET_BLOCK_ReplyEvaluationResult
Possible ways for how a block may relate to a query.
@ GNUNET_BLOCK_REPLY_OK_LAST
Last possible valid result.

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

Here is the call graph for this function:

◆ process_reply_with_path()

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

Process a reply, after the get_path has been updated.

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

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

2498 {
2499  /* forward to local clients */
2501  "Forwarding reply to local clients\n");
2502  if (! GDS_CLIENTS_handle_reply (bd,
2503  query_hash,
2504  get_path_length,
2505  get_path))
2506  {
2507  GNUNET_break (0);
2508  return false;
2509  }
2511  get_path,
2512  get_path_length);
2513  if (GNUNET_YES == cache_results)
2514  {
2515  struct GNUNET_DHT_PathElement xput_path[GNUNET_NZL (get_path_length
2516  + bd->put_path_length)];
2517  struct GNUNET_DATACACHE_Block bdx = *bd;
2518 
2519  if (NULL != bd->put_path)
2520  GNUNET_memcpy (xput_path,
2521  bd->put_path,
2522  bd->put_path_length * sizeof(struct
2524  GNUNET_memcpy (&xput_path[bd->put_path_length],
2525  get_path,
2526  get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2527  bdx.put_path = xput_path;
2528  bdx.put_path_length += get_path_length;
2529  GDS_DATACACHE_handle_put (&bdx);
2530  }
2531  /* forward to other peers */
2532  GDS_ROUTING_process (bd,
2533  query_hash,
2534  get_path_length,
2535  get_path);
2536  return true;
2537 }
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.
static int cache_results
Do we cache all results that we are routing in the local datacache?
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).
#define GNUNET_NZL(l)
Macro used to avoid using 0 for the length of a variable-size array (Non-Zero-Length).

Referenced by check_dht_p2p_hello().

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

2550 {
2551  uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2552  enum GNUNET_DHT_RouteOption ro
2553  = (enum GNUNET_DHT_RouteOption) ntohs (prm->options);
2554  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2555  bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2556 
2557  uint16_t get_path_length = ntohs (prm->get_path_length);
2558  uint16_t put_path_length = ntohs (prm->put_path_length);
2559  size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2560  + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2561 
2562  (void) cls;
2563  if ( (msize < vsize) ||
2564  (msize - vsize <
2565  (get_path_length + put_path_length)
2566  * sizeof(struct GNUNET_DHT_PathElement)) ||
2567  (get_path_length >
2568  GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
2569  (put_path_length >
2570  GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) )
2571  {
2572  GNUNET_break_op (0);
2573  return GNUNET_SYSERR;
2574  }
2575  return GNUNET_OK;
2576 }

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.

Here is the call graph for this function:

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

2588 {
2589  struct Target *t = cls;
2590  struct PeerInfo *peer = t->pi;
2591  uint16_t msize = ntohs (prm->header.size) - sizeof (*prm);
2592  enum GNUNET_DHT_RouteOption ro
2593  = (enum GNUNET_DHT_RouteOption) ntohs (prm->options);
2594  bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
2595  bool tracked = (0 != (ro & GNUNET_DHT_RO_RECORD_ROUTE));
2596  uint16_t get_path_length = ntohs (prm->get_path_length);
2597  uint16_t put_path_length = ntohs (prm->put_path_length);
2598  const struct GNUNET_PeerIdentity *trunc_peer
2599  = truncated
2600  ? (const struct GNUNET_PeerIdentity *) &prm[1]
2601  : NULL;
2602  const struct GNUNET_DHT_PathElement *put_path
2603  = truncated
2604  ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
2605  : (const struct GNUNET_DHT_PathElement *) &prm[1];
2606  const struct GNUNET_DHT_PathElement *get_path
2607  = &put_path[put_path_length];
2608  const struct GNUNET_CRYPTO_EddsaSignature *last_sig
2609  = tracked
2610  ? (const struct GNUNET_CRYPTO_EddsaSignature *) &get_path[get_path_length]
2611  : NULL;
2612  const void *data
2613  = tracked
2614  ? (const void *) &last_sig[1]
2615  : (const void *) &get_path[get_path_length];
2616  size_t vsize = (truncated ? sizeof (struct GNUNET_PeerIdentity) : 0)
2617  + (tracked ? sizeof (struct GNUNET_CRYPTO_EddsaSignature) : 0);
2618  struct GNUNET_DATACACHE_Block bd = {
2620  .put_path = put_path,
2621  .put_path_length = put_path_length,
2622  .key = prm->key,
2623  .type = ntohl (prm->type),
2624  .ro = ro,
2625  .data = data,
2626  .data_size = msize - vsize - (get_path_length + put_path_length)
2627  * sizeof(struct GNUNET_DHT_PathElement)
2628  };
2629 
2630  /* parse and validate message */
2631  if (GNUNET_TIME_absolute_is_past (bd.expiration_time))
2632  {
2634  "# Expired results discarded",
2635  1,
2636  GNUNET_NO);
2637  return;
2638  }
2639  if (GNUNET_OK !=
2641  bd.type,
2642  bd.data,
2643  bd.data_size))
2644  {
2645  GNUNET_break_op (0);
2646  return;
2647  }
2649  "# P2P RESULTS received",
2650  1,
2651  GNUNET_NO);
2653  "# P2P RESULT bytes received",
2654  msize,
2655  GNUNET_NO);
2656  {
2658 
2660  bd.type,
2661  bd.data,
2662  bd.data_size,
2663  &bd.key);
2664  if (GNUNET_NO == ret)
2665  bd.key = prm->key;
2666  }
2667 
2668  /* if we got a HELLO, consider it for our own routing table */
2669  hello_check (&bd);
2670 
2671  /* Need to append 'peer' to 'get_path' */
2672  if (tracked)
2673  {
2674  struct GNUNET_DHT_PathElement xget_path[get_path_length + 1];
2675  struct GNUNET_DHT_PathElement *gp = xget_path;
2676  unsigned int failure_offset;
2677 
2678  GNUNET_memcpy (xget_path,
2679  get_path,
2680  get_path_length * sizeof(struct GNUNET_DHT_PathElement));
2681  xget_path[get_path_length].pred = peer->id;
2682  /* use memcpy(), as last_sig may not be aligned */
2683  memcpy (&xget_path[get_path_length].sig,
2684  last_sig,
2685  sizeof (*last_sig));
2686 #if SANITY_CHECKS
2687  /* TODO: might want to eventually implement probabilistic
2688  load-based path verification, but for now it is all or nothing */
2689  failure_offset
2690  = GNUNET_DHT_verify_path (bd.data,
2691  bd.data_size,
2692  bd.expiration_time,
2693  trunc_peer,
2694  put_path,
2695  put_path_length,
2696  gp,
2697  get_path_length + 1,
2698  &GDS_my_identity);
2699 #else
2700  failure_offset = 0;
2701 #endif
2702  if (0 != failure_offset)
2703  {
2705  "Recorded path invalid at offset %u, truncating\n",
2706  failure_offset);
2707  GNUNET_assert (failure_offset <= bd.put_path_length + get_path_length
2708  + 1);
2709  if (failure_offset < bd.put_path_length)
2710  {
2711  /* failure on put path */
2712  trunc_peer = &bd.put_path[failure_offset - 1].pred;
2713  bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2714  bd.put_path = &bd.put_path[failure_offset];
2715  bd.put_path_length -= failure_offset;
2716  truncated = true;
2717  }
2718  else
2719  {
2720  /* failure on get path */
2721  failure_offset -= bd.put_path_length;
2722  if (0 == failure_offset)
2723  trunc_peer = &bd.put_path[bd.put_path_length - 1].pred;
2724  else
2725  trunc_peer = &gp[failure_offset - 1].pred;
2726  get_path_length -= failure_offset;
2727  gp = &gp[failure_offset];
2728  bd.put_path_length = 0;
2729  bd.put_path = NULL;
2730  bd.ro |= GNUNET_DHT_RO_TRUNCATED;
2731  truncated = true;
2732  }
2733  }
2735  "Extending GET path of length %u with %s\n",
2736  get_path_length,
2737  GNUNET_i2s (&peer->id));
2738  if (truncated)
2739  {
2740  GNUNET_assert (NULL != trunc_peer);
2741  bd.trunc_peer = *trunc_peer;
2742  }
2744  &prm->key,
2745  get_path_length + 1,
2746  gp));
2747  }
2748  else
2749  {
2750  if (truncated)
2751  {
2752  GNUNET_assert (NULL != trunc_peer);
2753  bd.trunc_peer = *trunc_peer;
2754  }
2756  &prm->key,
2757  0,
2758  NULL));
2759  }
2760 }
static bool process_reply_with_path(const struct GNUNET_DATACACHE_Block *bd, const struct GNUNET_HashCode *query_hash, unsigned int get_path_length, const struct GNUNET_DHT_PathElement *get_path)
Process a reply, after the get_path has been updated.

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

2773 {
2774  struct Target *t = cls;
2775  struct PeerInfo *peer = t->pi;
2777  size_t hellob_size;
2778  void *hellob;
2780 
2782  &peer->id,
2783  &hellob,
2784  &hellob_size,
2785  &expiration);
2786  GNUNET_free (hellob);
2787  return ret;
2788 }
static char * expiration
Credential TTL.
Definition: gnunet-abd.c:96
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:844

References GNUNET_DATACACHE_Block::data, data, GNUNET_DATACACHE_Block::data_size, PeerResultMessage::expiration_time, GNUNET_DATACACHE_Block::expiration_time, GDS_block_context, GDS_my_identity, GDS_stats, PeerResultMessage::get_path_length, GNUNET_assert, GNUNET_BLOCK_check_block(), GNUNET_BLOCK_get_key(), GNUNET_break, GNUNET_break_op, GNUNET_DHT_RO_RECORD_ROUTE, GNUNET_DHT_RO_TRUNCATED, GNUNET_DHT_verify_path(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_i2s(), GNUNET_log, GNUNET_memcpy, GNUNET_NO, GNUNET_OK, GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_is_past(), GNUNET_TIME_absolute_ntoh(), PeerResultMessage::header, hello_check(), PeerResultMessage::key, GNUNET_DATACACHE_Block::key, PeerResultMessage::options, peer, GNUNET_DHT_PathElement::pred, process_reply_with_path(), GNUNET_DATACACHE_Block::put_path, PeerResultMessage::put_path_length, GNUNET_DATACACHE_Block::put_path_length, ret, GNUNET_DATACACHE_Block::ro, GNUNET_DHT_PathElement::sig, GNUNET_MessageHeader::size, t, GNUNET_DATACACHE_Block::trunc_peer, PeerResultMessage::type, and GNUNET_DATACACHE_Block::type.

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

2800 {
2801  struct Target *t = cls;
2802  struct PeerInfo *peer = t->pi;
2803 
2804  GNUNET_free (peer->hello);
2805  peer->hello_size = 0;
2808  &peer->id,
2809  &peer->hello,
2810  &peer->hello_size,
2811  &peer->hello_expiration));
2812 }
void * hello
Block with a HELLO of this peer.

References GNUNET_break, GNUNET_free, GNUNET_HELLO_dht_msg_to_block(), GNUNET_OK, PeerInfo::hello, peer, 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 2816 of file gnunet-service-dht_neighbours.c.

2821 {
2822  struct Target *t = *tctx;
2823  struct GNUNET_MQ_MessageHandler core_handlers[] = {
2824  GNUNET_MQ_hd_var_size (dht_p2p_get,
2826  struct PeerGetMessage,
2827  t),
2828  GNUNET_MQ_hd_var_size (dht_p2p_put,
2830  struct PeerPutMessage,
2831  t),
2832  GNUNET_MQ_hd_var_size (dht_p2p_result,
2834  struct PeerResultMessage,
2835  t),
2836  GNUNET_MQ_hd_var_size (dht_p2p_hello,
2838  struct GNUNET_MessageHeader,
2839  t),
2841  };
2842  const struct GNUNET_MessageHeader *mh = message;
2843 
2844  (void) cls; /* the 'struct GDS_Underlay' */
2845  (void) sctx; /* our receiver address */
2846  if (NULL == t)
2847  {
2848  /* Received message claiming to originate from myself?
2849  Ignore! */
2850  GNUNET_break_op (0);
2851  return;
2852  }
2853  if (message_size < sizeof (*mh))
2854  {
2855  GNUNET_break_op (0);
2856  return;
2857  }
2858  if (message_size != ntohs (mh->size))
2859  {
2860  GNUNET_break_op (0);
2861  return;
2862  }
2864  "Handling message of type %u from peer %s\n",
2865  ntohs (mh->type),
2866  GNUNET_i2s (&t->pi->id));
2867  if (GNUNET_OK !=
2868  GNUNET_MQ_handle_message (core_handlers,
2869  mh))
2870  {
2871  GNUNET_break_op (0);
2872  return;
2873  }
2874 }
static struct GNUNET_CADET_Handle * mh
Cadet handle.
Definition: gnunet-cadet.c:92
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
enum GNUNET_GenericReturnValue GNUNET_MQ_handle_message(const struct GNUNET_MQ_MessageHandler *handlers, const struct GNUNET_MessageHeader *mh)
Call the message message handler that was registered for the type of the given message in the given h...
Definition: mq.c:205
#define GNUNET_MESSAGE_TYPE_DHT_P2P_HELLO
HELLO advertising a neighbours addresses.
Message handler for a specific message type.
Header for all communications.

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

2887 {
2888  const struct GNUNET_PeerIdentity *pid = cls;
2889  struct GNUNET_HashCode phash;
2890  int peer_bucket;
2891  struct PeerBucket *bucket;
2892 
2893  if (0 == GNUNET_memcmp (&GDS_my_identity,
2894  pid))
2895  {
2897  "Got a HELLO for my own PID, ignoring it\n");
2898  return; /* that's us! */
2899  }
2901  sizeof(*pid),
2902  &phash);
2903  peer_bucket = find_bucket (&phash);
2904  GNUNET_assert ( (peer_bucket >= 0) &&
2905  ((unsigned int) peer_bucket < MAX_BUCKETS));
2906  bucket = &k_buckets[peer_bucket];
2907  for (struct PeerInfo *pi = bucket->head;
2908  NULL != pi;
2909  pi = pi->next)
2910  if (0 ==
2911  GNUNET_memcmp (&pi->id,
2912  pid))
2913  {
2914  /* already connected */
2916  uri);
2917  return;
2918  }
2919  if (bucket->peers_size >= bucket_size)
2920  return; /* do not care */
2922  "Discovered peer %s at %s suitable for bucket %d (%u/%u), trying to connect\n",
2923  GNUNET_i2s (pid),
2924  uri,
2925  peer_bucket,
2926  bucket->peers_size,
2927  bucket_size);
2928  /* new peer that we like! */
2930  uri);
2931 }
static struct GNUNET_FS_Uri * uri
Value of URI provided on command-line (when not publishing a file but just creating UBlocks to refer ...
void GDS_u_try_connect(const struct GNUNET_PeerIdentity *pid, const char *address)
Ask all underlays to connect to peer pid at address.

References bucket_size, find_bucket(), GDS_my_identity, GDS_u_try_connect(), GNUNET_assert, GNUNET_CRYPTO_hash(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_i2s(), GNUNET_log, GNUNET_memcmp, PeerBucket::head, k_buckets, MAX_BUCKETS, PeerBucket::peers_size, pi, pid, and uri.

Referenced by GDS_NEIGHBOURS_handle_get(), and handle_dht_local_hello_offer().

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

2941 {
2942  for (unsigned int bc = 0; bc<closest_bucket; bc++)
2943  {
2944  struct PeerBucket *bucket = &k_buckets[bc];
2945  unsigned int count = 0;
2946 
2947  for (struct PeerInfo *pos = bucket->head;
2948  NULL != pos;
2949  pos = pos->next)
2950  {
2951  if (count >= bucket_size)
2952  break; /* we only consider first #bucket_size entries per bucket */
2953  count++;
2954  do_send (pos,
2955  msg);
2956  }
2957  }
2958 }

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

Referenced by broadcast_hello().

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

2963 {
2964 
2965  unsigned long long temp_config_num;
2966 
2969  "DHT",
2970  "DISABLE_TRY_CONNECT");
2971  if (GNUNET_OK ==
2973  "DHT",
2974  "bucket_size",
2975  &temp_config_num))
2976  bucket_size = (unsigned int) temp_config_num;
2979  "DHT",
2980  "CACHE_RESULTS");
2982  GNUNET_YES);
2983  return GNUNET_OK;
2984 }
const struct GNUNET_CONFIGURATION_Handle * GDS_cfg
Configuration we use.
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".
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).

Referenced by run().

Here is the caller graph for this function:

◆ GDS_NEIGHBOURS_done()

void GDS_NEIGHBOURS_done ( void  )

Shutdown neighbours subsystem.

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

2989 {
2990  if (NULL == all_connected_peers)
2991  return;
2992  GNUNET_assert (0 ==
2995  all_connected_peers = NULL;
2996  GNUNET_assert (NULL == find_peer_task);
2997 }
void GNUNET_CONTAINER_multipeermap_destroy(struct GNUNET_CONTAINER_MultiPeerMap *map)
Destroy a hash map.

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

Referenced by shutdown_task().

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

◆ GDS_NEIGHBOURS_get_id()

struct GNUNET_PeerIdentity* GDS_NEIGHBOURS_get_id ( void  )

Get the ID of the local node.

Returns
identity of the local node

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

3002 {
3003  return &GDS_my_identity;
3004 }

Variable Documentation

◆ cache_results

int cache_results
static

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

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

Referenced by check_dht_p2p_result().

◆ closest_bucket

unsigned int closest_bucket
static

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

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

Referenced by 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 421 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 426 of file gnunet-service-dht_neighbours.c.

Referenced by GDS_NEIGHBOURS_handle_get(), GDS_u_connect(), and GDS_u_disconnect().

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

Referenced by 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 437 of file gnunet-service-dht_neighbours.c.

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

◆ bucket_size

unsigned int bucket_size = 8
static

◆ find_peer_task

struct GNUNET_SCHEDULER_Task* find_peer_task
static

Task that sends FIND PEER requests.

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

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