get_close_nodes(): make use of assoc to find some really close nodes

DHT.c:
- get_close_nodes(): use assoc to find nodes for the requested reference id
- handle_sendnodes*(): set a proper timestamp for "heard" nodes

assoc.*:
- expand Assoc_close_entries by flags for additional restrictions for search
- Assoc_get_close_entries(): honor the new flags
- new_Assoc() prime handling: min. prime is now 5 instead of 3, and up to 25 is handled directly
- Assoc_status(): added address family for seen/heard, print of hash is now fixed width
This commit is contained in:
Coren[m] 2013-12-03 22:35:29 +01:00
parent 2967b67b7f
commit 110a8e889c
No known key found for this signature in database
GPG Key ID: AFA6943800F5DC6D
3 changed files with 116 additions and 28 deletions

View File

@ -333,7 +333,7 @@ static void get_close_nodes_inner(DHT *dht, uint8_t *client_id, Node_format *nod
* TODO: For the love of based <your favorite deity, in doubt use "love"> make
* this function cleaner and much more efficient.
*/
static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family, uint8_t is_LAN)
static int get_somewhat_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family, uint8_t is_LAN)
{
int num_nodes = 0, i;
get_close_nodes_inner(dht, client_id, nodes_list, sa_family,
@ -347,6 +347,53 @@ static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list
return num_nodes;
}
static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family, uint8_t is_LAN)
{
if (!dht->assoc)
return get_somewhat_close_nodes(dht, client_id, nodes_list, sa_family, is_LAN);
Client_data *result[MAX_SENT_NODES];
Assoc_close_entries request;
memset(&request, 0, sizeof(request));
request.count = MAX_SENT_NODES;
request.count_good = MAX_SENT_NODES / 2;
request.result = result;
request.wanted_id = client_id;
request.flags = (is_LAN ? LANOk : 0) + (sa_family == AF_INET ? ProtoIPv4 : ProtoIPv6);
uint8_t num_found = Assoc_get_close_entries(dht->assoc, &request);
if (!num_found)
return get_somewhat_close_nodes(dht, client_id, nodes_list, sa_family, is_LAN);
uint8_t i, num_returned = 0;
for (i = 0; i < num_found; i++) {
Client_data *client = result[i];
if (client) {
id_copy(nodes_list[i].client_id, client->client_id);
if (sa_family == AF_INET)
if (ipport_isset(&client->assoc4.ip_port)) {
nodes_list[i].ip_port = client->assoc4.ip_port;
num_returned++;
continue;
}
if (sa_family == AF_INET6)
if (ipport_isset(&client->assoc6.ip_port)) {
nodes_list[i].ip_port = client->assoc6.ip_port;
num_returned++;
continue;
}
}
}
return num_returned;
}
/* Replace first bad (or empty) node with this one.
*
* return 0 if successful.
@ -884,26 +931,24 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
return 1;
Node4_format *nodes4_list = (Node4_format *)(plain + sizeof(ping_id));
uint32_t i;
IP_Port ipp;
ipp.ip.family = AF_INET;
uint64_t time_now = unix_time();
IPPTs ippts;
ippts.ip_port.ip.family = AF_INET;
ippts.timestamp = time_now;
uint32_t i;
for (i = 0; i < num_nodes; i++)
if ((nodes4_list[i].ip_port.ip.uint32 != 0) && (nodes4_list[i].ip_port.ip.uint32 != (uint32_t)~0)) {
ipp.ip.ip4.uint32 = nodes4_list[i].ip_port.ip.uint32;
ipp.port = nodes4_list[i].ip_port.port;
ippts.ip_port.ip.ip4.uint32 = nodes4_list[i].ip_port.ip.uint32;
ippts.ip_port.port = nodes4_list[i].ip_port.port;
send_ping_request(dht->ping, ipp, nodes4_list[i].client_id);
int used = returnedip_ports(dht, ipp, nodes4_list[i].client_id, packet + 1);
if (dht->assoc) {
IPPTs ippts;
ippts.ip_port = ipp;
ippts.timestamp = 0;
send_ping_request(dht->ping, ippts.ip_port, nodes4_list[i].client_id);
int used = returnedip_ports(dht, ippts.ip_port, nodes4_list[i].client_id, packet + 1);
if (dht->assoc)
Assoc_add_entry(dht->assoc, nodes4_list[i].client_id, &ippts, NULL, used ? 1 : 0);
}
}
return 0;
@ -921,6 +966,7 @@ static int handle_sendnodes_ipv6(void *object, IP_Port source, uint8_t *packet,
return 1;
Node_format *nodes_list = (Node_format *)(plain + sizeof(ping_id));
uint64_t time_now = unix_time();
uint32_t i;
for (i = 0; i < num_nodes; i++)
@ -931,7 +977,7 @@ static int handle_sendnodes_ipv6(void *object, IP_Port source, uint8_t *packet,
if (dht->assoc) {
IPPTs ippts;
ippts.ip_port = nodes_list[i].ip_port;
ippts.timestamp = 0;
ippts.timestamp = time_now;
Assoc_add_entry(dht->assoc, nodes_list[i].client_id, &ippts, NULL, used ? 1 : 0);
}

View File

@ -479,7 +479,7 @@ static uint8_t candidates_create_new(Assoc *assoc, hash_t hash, uint8_t *id, uin
ipp_recv = NULL;
if (ipp_recv) {
entry->seen_at = unix_time();
entry->seen_at = ippts_send->timestamp;
entry->seen_family = ippts_send->ip_port.ip.family;
ipptsp->ip_port = ippts_send->ip_port;
@ -628,6 +628,24 @@ uint8_t Assoc_get_close_entries(Assoc *assoc, Assoc_close_entries *state)
Client_entry *entry = &cnd_bckt->list[i];
if (entry->hash) {
if (state->flags & ProtoIPv4) {
if (!ipport_isset(&entry->client.assoc4.ip_port))
continue;
if (!(state->flags & LANOk))
if (!LAN_ip(entry->client.assoc4.ip_port.ip))
continue;
}
if (state->flags & ProtoIPv6) {
if (!ipport_isset(&entry->client.assoc6.ip_port))
continue;
if (!(state->flags & LANOk))
if (!LAN_ip(entry->client.assoc6.ip_port.ip))
continue;
}
uint64_t dist = state->distance_absolute_func(assoc, state->custom_data, state->wanted_id, entry->client.client_id);
uint32_t index = b * assoc->candidates_bucket_size + i;
dist_list[index] = (dist << DISTANCE_INDEX_INDEX_BITS) | index;
@ -685,7 +703,16 @@ uint8_t Assoc_get_close_entries(Assoc *assoc, Assoc_close_entries *state)
if (client_quota_good >= client_quota_max) {
state->result[pos++] = &entry->client;
taken_last = i;
} else if (!is_timeout(entry->seen_at, BAD_NODE_TIMEOUT)) {
} else {
if (state->flags & (ProtoIPv4 | ProtoIPv6)) {
if ((state->flags & ProtoIPv4) && is_timeout(entry->client.assoc4.timestamp, BAD_NODE_TIMEOUT))
continue;
if ((state->flags & ProtoIPv6) && is_timeout(entry->client.assoc6.timestamp, BAD_NODE_TIMEOUT))
continue;
} else if (is_timeout(entry->seen_at, BAD_NODE_TIMEOUT))
continue;
state->result[pos++] = &entry->client;
client_quota_good++;
taken_last = i;
@ -729,9 +756,8 @@ static uint8_t odd_min9_is_prime(size_t value)
static size_t prime_upto_min9(size_t limit)
{
/* primes besides 2 are odd */
if (!(limit % 2))
limit--;
/* even => odd */
limit = limit - (1 - (limit % 2));
while (!odd_min9_is_prime(limit))
limit -= 2;
@ -762,11 +788,16 @@ Assoc *new_Assoc(size_t bits, size_t entries, uint8_t *public_id)
assoc->candidates_bucket_bits = bits;
assoc->candidates_bucket_count = 1U << bits;
if (entries <= 8) {
if (entries <= 4)
entries = 3;
else if (!(entries % 2)) /* 6, 8 => 5, 7 */
entries--;
if (entries < 25) {
if (entries <= 6)
entries = 5;
else {
entries = entries - (1 - (entries % 2)); /* even => odd */
/* 7..23: all odds but 9&15 are prime */
if (!(entries % 3)) /* 9, 15 */
entries -= 2; /* 7, 13 */
}
} else if (entries > ((1 << 17) - 1)) /* 130k+ */
entries = (1 << 17) - 1;
else {
@ -860,6 +891,8 @@ void Assoc_status(Assoc *assoc)
return;
}
loglog("[b:p] hash => [id...] used, seen, heard\n");
size_t bid, cid, total = 0;
for (bid = 0; bid < assoc->candidates_bucket_count; bid++) {
@ -869,11 +902,13 @@ void Assoc_status(Assoc *assoc)
Client_entry *entry = &bucket->list[cid];
if (entry->hash) {
sprintf(logbuffer, "[%3i:%3i] %x => [%s...] %i, %i, %i\n",
sprintf(logbuffer, "[%3i:%3i] %08x => [%s...] %i, %i(%c), %i(%c)\n",
(int)bid, (int)cid, entry->hash, idpart2str(entry->client.client_id, 8),
entry->used_at ? (int)(unix_time() - entry->used_at) : 0,
entry->seen_at ? (int)(unix_time() - entry->seen_at) : 0,
entry->heard_at ? (int)(unix_time() - entry->heard_at) : 0);
entry->seen_at ? (entry->seen_family == AF_INET ? '4' : (entry->seen_family == AF_INET6 ? '6' : '?')) : '?',
entry->heard_at ? (int)(unix_time() - entry->heard_at) : 0,
entry->heard_at ? (entry->heard_family == AF_INET ? '4' : (entry->heard_family == AF_INET6 ? '6' : '?')) : '?');
loglog(logbuffer);
total++;
}

View File

@ -37,9 +37,16 @@ uint8_t Assoc_add_entry(Assoc *assoc, uint8_t *id, IPPTs *ippts_send, IP_Port *i
/*****************************************************************************/
typedef enum AssocCloseEntriesFlags {
ProtoIPv4 = 1,
ProtoIPv6 = 2,
LANOk = 4,
} AssocCloseEntriesFlags;
typedef struct Assoc_close_entries {
uint8_t *wanted_id; /* the target client_id */
void *custom_data; /* given to distance functions */
uint8_t *wanted_id; /* the target client_id */
uint8_t flags; /* additional flags */
Assoc_distance_relative_callback distance_relative_func;
Assoc_distance_absolute_callback distance_absolute_func;