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