Merge pull request #590 from FullName/ipv6.yield50%toipv4

reserve half of client lists for ipv4 (take #2)
This commit is contained in:
irungentoo 2013-09-22 09:17:16 -07:00
commit 64150f4bde

View File

@ -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);
}
}
}