diff options
author | Coren[m] <Break@Ocean> | 2013-09-21 01:22:42 +0200 |
---|---|---|
committer | Coren[m] <Break@Ocean> | 2013-09-21 01:22:42 +0200 |
commit | 13bd6aab187d481e51f45f74f64f5b92c7acf935 (patch) | |
tree | 38f86cbdbd3a366d1cfb6e133f95a58a2916dcdd | |
parent | f10c94a17ad6b4a29ea60ed80148019810de0f5a (diff) |
reserving 50%+ for ipv4, take 2
DHT.c:
- we have to actually count the number of addresses in the field, because sort_list() will move the stuff around
- improved replace_good() substantially by throwing away the "furthest" client_id, not the one just a bit worse than the new one (but better than all the later ones in the field!)
-rw-r--r-- | toxcore/DHT.c | 127 |
1 files changed, 101 insertions, 26 deletions
diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 894458a3..cecfb2ce 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c | |||
@@ -139,9 +139,27 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t | |||
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; |
@@ -299,22 +317,34 @@ static int replace_bad( Client_data *list, | |||
299 | uint8_t *client_id, | 317 | uint8_t *client_id, |
300 | IP_Port ip_port ) | 318 | IP_Port ip_port ) |
301 | { | 319 | { |
302 | uint32_t i = 0; | 320 | uint32_t i; |
303 | uint64_t temp_time = unix_time(); | 321 | uint64_t temp_time = unix_time(); |
304 | 322 | ||
305 | /* reserve the lower end to IPv4 for now */ | 323 | uint8_t candropipv4 = 1; |
306 | if (ip_port.ip.family == AF_INET6) | 324 | if (ip_port.ip.family == AF_INET6) { |
307 | i = length / 2; | 325 | uint32_t ipv6cnt = 0; |
308 | 326 | ||
309 | for (; i < length; ++i) { | 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 | |||
337 | for (i = 0; i < length; ++i) { | ||
310 | /* If node is bad */ | 338 | /* If node is bad */ |
311 | if (is_timeout(temp_time, list[i].timestamp, BAD_NODE_TIMEOUT)) { | 339 | Client_data *client = &list[i]; |
312 | memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); | 340 | if ((candropipv4 || (client->ip_port.ip.family == AF_INET6)) && |
313 | list[i].ip_port = ip_port; | 341 | is_timeout(temp_time, client->timestamp, BAD_NODE_TIMEOUT)) { |
314 | list[i].timestamp = temp_time; | 342 | memcpy(client->client_id, client_id, CLIENT_ID_SIZE); |
315 | ip_reset(&list[i].ret_ip_port.ip); | 343 | client->ip_port = ip_port; |
316 | list[i].ret_ip_port.port = 0; | 344 | client->timestamp = temp_time; |
317 | 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; | ||
318 | return 0; | 348 | return 0; |
319 | } | 349 | } |
320 | } | 350 | } |
@@ -351,24 +381,69 @@ static int replace_good( Client_data *list, | |||
351 | IP_Port ip_port, | 381 | IP_Port ip_port, |
352 | uint8_t *comp_client_id ) | 382 | uint8_t *comp_client_id ) |
353 | { | 383 | { |
354 | uint32_t i = 0; | ||
355 | uint64_t temp_time = unix_time(); | ||
356 | sort_list(list, length, comp_client_id); | 384 | sort_list(list, length, comp_client_id); |
357 | 385 | ||
358 | /* reserve the lower end to IPv4 for now */ | 386 | uint8_t candropipv4 = 1; |
359 | if (ip_port.ip.family == AF_INET6) | 387 | if (ip_port.ip.family == AF_INET6) { |
360 | i = length / 2; | 388 | uint32_t i, ipv6cnt = 0; |
361 | 389 | ||
362 | for (; i < length; ++i) | 390 | /* ipv6: count how many spots are used */ |
363 | if (id_closest(comp_client_id, list[i].client_id, client_id) == 2) { | 391 | for(i = 0; i < length; i++) |
364 | memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); | 392 | if (list[i].ip_port.ip.family == AF_INET6) |
365 | list[i].ip_port = ip_port; | 393 | ipv6cnt++; |
366 | list[i].timestamp = temp_time; | 394 | |
367 | ip_reset(&list[i].ret_ip_port.ip); | 395 | /* more than half the list filled with ipv6: block ipv4->ipv6 overwrite */ |
368 | list[i].ret_ip_port.port = 0; | 396 | if (ipv6cnt > length / 2) |
369 | list[i].ret_timestamp = 0; | 397 | candropipv4 = 0; |
370 | return 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 | } | ||
371 | } | 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 | } | ||
372 | 447 | ||
373 | return 1; | 448 | return 1; |
374 | } | 449 | } |