diff --git a/toxcore/DHT.c b/toxcore/DHT.c index f49858bc..5dfcc64a 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c @@ -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 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); } diff --git a/toxcore/assoc.c b/toxcore/assoc.c index 5bafdcdb..5a44003c 100644 --- a/toxcore/assoc.c +++ b/toxcore/assoc.c @@ -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++; } diff --git a/toxcore/assoc.h b/toxcore/assoc.h index ee9e5e21..2184e525 100644 --- a/toxcore/assoc.h +++ b/toxcore/assoc.h @@ -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;