mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Merge pull request #590 from FullName/ipv6.yield50%toipv4
reserve half of client lists for ipv4 (take #2)
This commit is contained in:
commit
64150f4bde
155
toxcore/DHT.c
155
toxcore/DHT.c
|
@ -134,14 +134,32 @@ static int is_timeout(uint64_t time_now, uint64_t timestamp, uint64_t timeout)
|
|||
*
|
||||
* return True(1) or False(0)
|
||||
*/
|
||||
static int client_in_list(Client_data *list, uint32_t length, uint8_t *client_id, IP_Port ip_port)
|
||||
static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t *client_id, IP_Port ip_port)
|
||||
{
|
||||
uint32_t i;
|
||||
uint64_t temp_time = unix_time();
|
||||
|
||||
uint8_t candropipv4 = 1;
|
||||
if (ip_port.ip.family == AF_INET6) {
|
||||
uint8_t ipv6cnt = 0;
|
||||
|
||||
/* ipv6: count how many spots are used */
|
||||
for(i = 0; i < length; i++)
|
||||
if (list[i].ip_port.ip.family == AF_INET6)
|
||||
ipv6cnt++;
|
||||
|
||||
/* more than half the list filled with ipv6: block ipv4->ipv6 overwrite */
|
||||
if (ipv6cnt > length / 2)
|
||||
candropipv4 = 0;
|
||||
}
|
||||
|
||||
/* if client_id is in list, find it and maybe overwrite ip_port */
|
||||
for (i = 0; i < length; ++i)
|
||||
if (id_equal(list[i].client_id, client_id)) {
|
||||
/* if we got "too many" ipv6 addresses already, keep the ipv4 address */
|
||||
if (!candropipv4 && (list[i].ip_port.ip.family == AF_INET))
|
||||
return 1;
|
||||
|
||||
/* Refresh the client timestamp. */
|
||||
list[i].timestamp = temp_time;
|
||||
list[i].ip_port = ip_port;
|
||||
|
@ -302,15 +320,31 @@ static int replace_bad( Client_data *list,
|
|||
uint32_t i;
|
||||
uint64_t temp_time = unix_time();
|
||||
|
||||
uint8_t candropipv4 = 1;
|
||||
if (ip_port.ip.family == AF_INET6) {
|
||||
uint32_t ipv6cnt = 0;
|
||||
|
||||
/* ipv6: count how many spots are used */
|
||||
for(i = 0; i < length; i++)
|
||||
if (list[i].ip_port.ip.family == AF_INET6)
|
||||
ipv6cnt++;
|
||||
|
||||
/* more than half the list filled with ipv6: block ipv4->ipv6 overwrite */
|
||||
if (ipv6cnt > length / 2)
|
||||
candropipv4 = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; ++i) {
|
||||
/* If node is bad */
|
||||
if (is_timeout(temp_time, list[i].timestamp, BAD_NODE_TIMEOUT)) {
|
||||
memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
|
||||
list[i].ip_port = ip_port;
|
||||
list[i].timestamp = temp_time;
|
||||
ip_reset(&list[i].ret_ip_port.ip);
|
||||
list[i].ret_ip_port.port = 0;
|
||||
list[i].ret_timestamp = 0;
|
||||
Client_data *client = &list[i];
|
||||
if ((candropipv4 || (client->ip_port.ip.family == AF_INET6)) &&
|
||||
is_timeout(temp_time, client->timestamp, BAD_NODE_TIMEOUT)) {
|
||||
memcpy(client->client_id, client_id, CLIENT_ID_SIZE);
|
||||
client->ip_port = ip_port;
|
||||
client->timestamp = temp_time;
|
||||
ip_reset(&client->ret_ip_port.ip);
|
||||
client->ret_ip_port.port = 0;
|
||||
client->ret_timestamp = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -347,20 +381,69 @@ static int replace_good( Client_data *list,
|
|||
IP_Port ip_port,
|
||||
uint8_t *comp_client_id )
|
||||
{
|
||||
uint32_t i;
|
||||
uint64_t temp_time = unix_time();
|
||||
sort_list(list, length, comp_client_id);
|
||||
|
||||
for (i = 0; i < length; ++i)
|
||||
if (id_closest(comp_client_id, list[i].client_id, client_id) == 2) {
|
||||
memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
|
||||
list[i].ip_port = ip_port;
|
||||
list[i].timestamp = temp_time;
|
||||
ip_reset(&list[i].ret_ip_port.ip);
|
||||
list[i].ret_ip_port.port = 0;
|
||||
list[i].ret_timestamp = 0;
|
||||
return 0;
|
||||
uint8_t candropipv4 = 1;
|
||||
if (ip_port.ip.family == AF_INET6) {
|
||||
uint32_t i, ipv6cnt = 0;
|
||||
|
||||
/* ipv6: count how many spots are used */
|
||||
for(i = 0; i < length; i++)
|
||||
if (list[i].ip_port.ip.family == AF_INET6)
|
||||
ipv6cnt++;
|
||||
|
||||
/* more than half the list filled with ipv6: block ipv4->ipv6 overwrite */
|
||||
if (ipv6cnt > length / 2)
|
||||
candropipv4 = 0;
|
||||
}
|
||||
|
||||
int8_t replace = -1;
|
||||
uint32_t i;
|
||||
|
||||
if (candropipv4) {
|
||||
/* either we got an ipv4 address, or we're "allowed" to push out an ipv4
|
||||
* address in favor of an ipv6 one
|
||||
*
|
||||
* because the list is sorted, we can simply check the client_id at the
|
||||
* border, either it is closer, then every other one is as well, or it is
|
||||
* further, then it gets pushed out in favor of the new address, which
|
||||
* will with the next sort() move to its "rightful" position
|
||||
*
|
||||
* CAVEAT: weirdly enough, the list is sorted DESCENDING in distance
|
||||
* so the furthest element is the first, NOT the last (at least that's
|
||||
* what the comment above sort_list() claims)
|
||||
*/
|
||||
if (id_closest(comp_client_id, list[0].client_id, client_id) == 2)
|
||||
replace = 0;
|
||||
} else {
|
||||
/* ipv6 case without a right to push out an ipv4: only look for ipv6
|
||||
* addresses, the first one we find is either closer (then we can skip
|
||||
* out like above) or further (then we can replace it, like above)
|
||||
*/
|
||||
for (i = 0; i < length; i++) {
|
||||
Client_data *client = &list[i];
|
||||
if (client->ip_port.ip.family == AF_INET6) {
|
||||
if (id_closest(comp_client_id, list[i].client_id, client_id) == 2)
|
||||
replace = i;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (replace != -1) {
|
||||
#ifdef DEBUG
|
||||
assert(replace >= 0 && replace < length);
|
||||
#endif
|
||||
Client_data *client = &list[replace];
|
||||
memcpy(client->client_id, client_id, CLIENT_ID_SIZE);
|
||||
client->ip_port = ip_port;
|
||||
client->timestamp = unix_time();
|
||||
ip_reset(&client->ret_ip_port.ip);
|
||||
client->ret_ip_port.port = 0;
|
||||
client->ret_timestamp = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -372,36 +455,32 @@ void addto_lists(DHT *dht, IP_Port ip_port, uint8_t *client_id)
|
|||
{
|
||||
uint32_t i;
|
||||
|
||||
/* convert IPv4-in-IPv6 to IPv4 */
|
||||
if ((ip_port.ip.family == AF_INET6) && IN6_IS_ADDR_V4MAPPED(&ip_port.ip.ip6)) {
|
||||
ip_port.ip.family = AF_INET;
|
||||
ip_port.ip.ip4.uint32 = ip_port.ip.ip6.uint32[3];
|
||||
}
|
||||
|
||||
/* NOTE: Current behavior if there are two clients with the same id is
|
||||
* to replace the first ip by the second.
|
||||
*/
|
||||
if (!client_in_list(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) {
|
||||
if (!client_or_ip_port_in_list(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) {
|
||||
if (replace_bad(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) {
|
||||
/* If we can't replace bad nodes we try replacing good ones. */
|
||||
replace_good( dht->close_clientlist,
|
||||
LCLIENT_LIST,
|
||||
client_id,
|
||||
ip_port,
|
||||
dht->c->self_public_key );
|
||||
replace_good(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port,
|
||||
dht->c->self_public_key);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dht->num_friends; ++i) {
|
||||
if (!client_in_list( dht->friends_list[i].client_list,
|
||||
MAX_FRIEND_CLIENTS,
|
||||
client_id,
|
||||
ip_port )) {
|
||||
if (!client_or_ip_port_in_list(dht->friends_list[i].client_list,
|
||||
MAX_FRIEND_CLIENTS, client_id, ip_port)) {
|
||||
|
||||
if (replace_bad( dht->friends_list[i].client_list,
|
||||
MAX_FRIEND_CLIENTS,
|
||||
client_id,
|
||||
ip_port )) {
|
||||
if (replace_bad(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS,
|
||||
client_id, ip_port)) {
|
||||
/* If we can't replace bad nodes we try replacing good ones. */
|
||||
replace_good( dht->friends_list[i].client_list,
|
||||
MAX_FRIEND_CLIENTS,
|
||||
client_id,
|
||||
ip_port,
|
||||
dht->friends_list[i].client_id );
|
||||
replace_good(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS,
|
||||
client_id, ip_port, dht->friends_list[i].client_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user