diff options
Diffstat (limited to 'toxcore/DHT.c')
-rw-r--r-- | toxcore/DHT.c | 157 |
1 files changed, 118 insertions, 39 deletions
diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 84c00c70..cabd96c2 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c | |||
@@ -134,14 +134,32 @@ static int is_timeout(uint64_t time_now, uint64_t timestamp, uint64_t timeout) | |||
134 | * | 134 | * |
135 | * return True(1) or False(0) | 135 | * return True(1) or False(0) |
136 | */ | 136 | */ |
137 | static int client_in_list(Client_data *list, uint32_t length, uint8_t *client_id, IP_Port ip_port) | 137 | static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t *client_id, IP_Port ip_port) |
138 | { | 138 | { |
139 | uint32_t i; | 139 | uint32_t i; |
140 | uint64_t temp_time = unix_time(); | 140 | uint64_t temp_time = unix_time(); |
141 | 141 | ||
142 | uint8_t candropipv4 = 1; | ||
143 | if (ip_port.ip.family == AF_INET6) { | ||
144 | uint8_t ipv6cnt = 0; | ||
145 | |||
146 | /* ipv6: count how many spots are used */ | ||
147 | for(i = 0; i < length; i++) | ||
148 | if (list[i].ip_port.ip.family == AF_INET6) | ||
149 | ipv6cnt++; | ||
150 | |||
151 | /* more than half the list filled with ipv6: block ipv4->ipv6 overwrite */ | ||
152 | if (ipv6cnt > length / 2) | ||
153 | candropipv4 = 0; | ||
154 | } | ||
155 | |||
142 | /* if client_id is in list, find it and maybe overwrite ip_port */ | 156 | /* if client_id is in list, find it and maybe overwrite ip_port */ |
143 | for (i = 0; i < length; ++i) | 157 | for (i = 0; i < length; ++i) |
144 | if (id_equal(list[i].client_id, client_id)) { | 158 | if (id_equal(list[i].client_id, client_id)) { |
159 | /* if we got "too many" ipv6 addresses already, keep the ipv4 address */ | ||
160 | if (!candropipv4 && (list[i].ip_port.ip.family == AF_INET)) | ||
161 | return 1; | ||
162 | |||
145 | /* Refresh the client timestamp. */ | 163 | /* Refresh the client timestamp. */ |
146 | list[i].timestamp = temp_time; | 164 | list[i].timestamp = temp_time; |
147 | list[i].ip_port = ip_port; | 165 | list[i].ip_port = ip_port; |
@@ -302,15 +320,31 @@ static int replace_bad( Client_data *list, | |||
302 | uint32_t i; | 320 | uint32_t i; |
303 | uint64_t temp_time = unix_time(); | 321 | uint64_t temp_time = unix_time(); |
304 | 322 | ||
323 | uint8_t candropipv4 = 1; | ||
324 | if (ip_port.ip.family == AF_INET6) { | ||
325 | uint32_t ipv6cnt = 0; | ||
326 | |||
327 | /* ipv6: count how many spots are used */ | ||
328 | for(i = 0; i < length; i++) | ||
329 | if (list[i].ip_port.ip.family == AF_INET6) | ||
330 | ipv6cnt++; | ||
331 | |||
332 | /* more than half the list filled with ipv6: block ipv4->ipv6 overwrite */ | ||
333 | if (ipv6cnt > length / 2) | ||
334 | candropipv4 = 0; | ||
335 | } | ||
336 | |||
305 | for (i = 0; i < length; ++i) { | 337 | for (i = 0; i < length; ++i) { |
306 | /* If node is bad */ | 338 | /* If node is bad */ |
307 | if (is_timeout(temp_time, list[i].timestamp, BAD_NODE_TIMEOUT)) { | 339 | Client_data *client = &list[i]; |
308 | memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); | 340 | if ((candropipv4 || (client->ip_port.ip.family == AF_INET6)) && |
309 | list[i].ip_port = ip_port; | 341 | is_timeout(temp_time, client->timestamp, BAD_NODE_TIMEOUT)) { |
310 | list[i].timestamp = temp_time; | 342 | memcpy(client->client_id, client_id, CLIENT_ID_SIZE); |
311 | ip_reset(&list[i].ret_ip_port.ip); | 343 | client->ip_port = ip_port; |
312 | list[i].ret_ip_port.port = 0; | 344 | client->timestamp = temp_time; |
313 | list[i].ret_timestamp = 0; | 345 | ip_reset(&client->ret_ip_port.ip); |
346 | client->ret_ip_port.port = 0; | ||
347 | client->ret_timestamp = 0; | ||
314 | return 0; | 348 | return 0; |
315 | } | 349 | } |
316 | } | 350 | } |
@@ -347,20 +381,69 @@ static int replace_good( Client_data *list, | |||
347 | IP_Port ip_port, | 381 | IP_Port ip_port, |
348 | uint8_t *comp_client_id ) | 382 | uint8_t *comp_client_id ) |
349 | { | 383 | { |
350 | uint32_t i; | ||
351 | uint64_t temp_time = unix_time(); | ||
352 | sort_list(list, length, comp_client_id); | 384 | sort_list(list, length, comp_client_id); |
353 | 385 | ||
354 | for (i = 0; i < length; ++i) | 386 | uint8_t candropipv4 = 1; |
355 | if (id_closest(comp_client_id, list[i].client_id, client_id) == 2) { | 387 | if (ip_port.ip.family == AF_INET6) { |
356 | memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); | 388 | uint32_t i, ipv6cnt = 0; |
357 | list[i].ip_port = ip_port; | 389 | |
358 | list[i].timestamp = temp_time; | 390 | /* ipv6: count how many spots are used */ |
359 | ip_reset(&list[i].ret_ip_port.ip); | 391 | for(i = 0; i < length; i++) |
360 | list[i].ret_ip_port.port = 0; | 392 | if (list[i].ip_port.ip.family == AF_INET6) |
361 | list[i].ret_timestamp = 0; | 393 | ipv6cnt++; |
362 | return 0; | 394 | |
395 | /* more than half the list filled with ipv6: block ipv4->ipv6 overwrite */ | ||
396 | if (ipv6cnt > length / 2) | ||
397 | candropipv4 = 0; | ||
398 | } | ||
399 | |||
400 | int8_t replace = -1; | ||
401 | uint32_t i; | ||
402 | |||
403 | if (candropipv4) { | ||
404 | /* either we got an ipv4 address, or we're "allowed" to push out an ipv4 | ||
405 | * address in favor of an ipv6 one | ||
406 | * | ||
407 | * because the list is sorted, we can simply check the last client_id, | ||
408 | * either it is closer, then every other one is as well, or it is further, | ||
409 | * then it gets pushed out in favor of the new address, which will with | ||
410 | * the next sort() move to its "rightful" position | ||
411 | * | ||
412 | * we should NOT replace the best worse client_id (original implementation), | ||
413 | * because that one was still better than any later in the field, and | ||
414 | * we don't want to lose it, but the worst | ||
415 | */ | ||
416 | if (id_closest(comp_client_id, list[length - 1].client_id, client_id) == 2) | ||
417 | replace = length - 1; | ||
418 | } else { | ||
419 | /* ipv6 case without a right to push out an ipv4: only look for ipv6 | ||
420 | * addresses, the first one we find is either closer (then we can skip | ||
421 | * out like above) or further (then we can replace it, like above) | ||
422 | */ | ||
423 | for (i = length - 1; i < length; i--) { | ||
424 | Client_data *client = &list[i]; | ||
425 | if (client->ip_port.ip.family == AF_INET6) { | ||
426 | if (id_closest(comp_client_id, list[i].client_id, client_id) == 2) | ||
427 | replace = i; | ||
428 | |||
429 | break; | ||
430 | } | ||
363 | } | 431 | } |
432 | } | ||
433 | |||
434 | if (replace != -1) { | ||
435 | #ifdef DEBUG | ||
436 | assert(replace >= 0 && replace < length); | ||
437 | #endif | ||
438 | Client_data *client = &list[replace]; | ||
439 | memcpy(client->client_id, client_id, CLIENT_ID_SIZE); | ||
440 | client->ip_port = ip_port; | ||
441 | client->timestamp = unix_time(); | ||
442 | ip_reset(&client->ret_ip_port.ip); | ||
443 | client->ret_ip_port.port = 0; | ||
444 | client->ret_timestamp = 0; | ||
445 | return 0; | ||
446 | } | ||
364 | 447 | ||
365 | return 1; | 448 | return 1; |
366 | } | 449 | } |
@@ -372,36 +455,32 @@ void addto_lists(DHT *dht, IP_Port ip_port, uint8_t *client_id) | |||
372 | { | 455 | { |
373 | uint32_t i; | 456 | uint32_t i; |
374 | 457 | ||
458 | /* convert IPv4-in-IPv6 to IPv4 */ | ||
459 | if ((ip_port.ip.family == AF_INET6) && IN6_IS_ADDR_V4MAPPED(&ip_port.ip.ip6)) { | ||
460 | ip_port.ip.family = AF_INET; | ||
461 | ip_port.ip.ip4.uint32 = ip_port.ip.ip6.uint32[3]; | ||
462 | } | ||
463 | |||
375 | /* NOTE: Current behavior if there are two clients with the same id is | 464 | /* NOTE: Current behavior if there are two clients with the same id is |
376 | * to replace the first ip by the second. | 465 | * to replace the first ip by the second. |
377 | */ | 466 | */ |
378 | if (!client_in_list(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) { | 467 | if (!client_or_ip_port_in_list(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) { |
379 | if (replace_bad(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) { | 468 | if (replace_bad(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) { |
380 | /* If we can't replace bad nodes we try replacing good ones. */ | 469 | /* If we can't replace bad nodes we try replacing good ones. */ |
381 | replace_good( dht->close_clientlist, | 470 | replace_good(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port, |
382 | LCLIENT_LIST, | 471 | dht->c->self_public_key); |
383 | client_id, | ||
384 | ip_port, | ||
385 | dht->c->self_public_key ); | ||
386 | } | 472 | } |
387 | } | 473 | } |
388 | 474 | ||
389 | for (i = 0; i < dht->num_friends; ++i) { | 475 | for (i = 0; i < dht->num_friends; ++i) { |
390 | if (!client_in_list( dht->friends_list[i].client_list, | 476 | if (!client_or_ip_port_in_list(dht->friends_list[i].client_list, |
391 | MAX_FRIEND_CLIENTS, | 477 | MAX_FRIEND_CLIENTS, client_id, ip_port)) { |
392 | client_id, | 478 | |
393 | ip_port )) { | 479 | if (replace_bad(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, |
394 | 480 | client_id, ip_port)) { | |
395 | if (replace_bad( dht->friends_list[i].client_list, | ||
396 | MAX_FRIEND_CLIENTS, | ||
397 | client_id, | ||
398 | ip_port )) { | ||
399 | /* If we can't replace bad nodes we try replacing good ones. */ | 481 | /* If we can't replace bad nodes we try replacing good ones. */ |
400 | replace_good( dht->friends_list[i].client_list, | 482 | replace_good(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, |
401 | MAX_FRIEND_CLIENTS, | 483 | client_id, ip_port, dht->friends_list[i].client_id); |
402 | client_id, | ||
403 | ip_port, | ||
404 | dht->friends_list[i].client_id ); | ||
405 | } | 484 | } |
406 | } | 485 | } |
407 | } | 486 | } |