diff options
author | pyruvate <d.pyruvate.kinase@gmail.com> | 2014-08-09 10:50:43 +0300 |
---|---|---|
committer | pyruvate <d.pyruvate.kinase@gmail.com> | 2014-08-09 11:33:20 +0300 |
commit | bdf1c972735f4a6518f24d3770729fab142020fe (patch) | |
tree | 6ffac5b785f20c8f8e6a479d08784316e537eae5 | |
parent | a460b9fbd0bd262b7e9c6d2b3f8d835a6b973093 (diff) |
Refactoring of node replacements in addto_lists function
An index for replacement candidate is searched
in one lookup cycle for all types (bad, possibly bad, good).
Sorting of items has been removed (sorting logic can be substituted
by a maximum search).
-rw-r--r-- | auto_tests/dht_test.c | 4 | ||||
-rw-r--r-- | toxcore/DHT.c | 245 |
2 files changed, 47 insertions, 202 deletions
diff --git a/auto_tests/dht_test.c b/auto_tests/dht_test.c index a5a97233..091b50fb 100644 --- a/auto_tests/dht_test.c +++ b/auto_tests/dht_test.c | |||
@@ -293,8 +293,8 @@ void test_addto_lists(IP ip) | |||
293 | 293 | ||
294 | // check "possibly bad" entries | 294 | // check "possibly bad" entries |
295 | test_addto_lists_possible_bad(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port, dht->self_public_key); | 295 | test_addto_lists_possible_bad(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port, dht->self_public_key); |
296 | // for (i = 0; i < dht->num_friends; ++i) | 296 | for (i = 0; i < dht->num_friends; ++i) |
297 | // test_addto_lists_possible_bad(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port, dht->friends_list[i].client_id); | 297 | test_addto_lists_possible_bad(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port, dht->friends_list[i].client_id); |
298 | 298 | ||
299 | // check "good" entries | 299 | // check "good" entries |
300 | test_addto_lists_good(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port, dht->self_public_key); | 300 | test_addto_lists_good(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port, dht->self_public_key); |
diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 77d126c1..20f4fb82 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c | |||
@@ -65,17 +65,6 @@ | |||
65 | /* Number of get node requests to send to quickly find close nodes. */ | 65 | /* Number of get node requests to send to quickly find close nodes. */ |
66 | #define MAX_BOOTSTRAP_TIMES 10 | 66 | #define MAX_BOOTSTRAP_TIMES 10 |
67 | 67 | ||
68 | /* Used in the comparison function for sorting lists of Client_data. */ | ||
69 | typedef struct { | ||
70 | Client_data c1; | ||
71 | Client_data c2; | ||
72 | } ClientPair; | ||
73 | |||
74 | /* Create the declaration for a quick sort for ClientPair structures. */ | ||
75 | declare_quick_sort(ClientPair); | ||
76 | /* Create the quicksort function. See misc_tools.h for the definition. */ | ||
77 | make_quick_sort(ClientPair); | ||
78 | |||
79 | Client_data *DHT_get_close_list(DHT *dht) | 68 | Client_data *DHT_get_close_list(DHT *dht) |
80 | { | 69 | { |
81 | return dht->close_clientlist; | 70 | return dht->close_clientlist; |
@@ -107,19 +96,6 @@ int id_closest(const uint8_t *id, const uint8_t *id1, const uint8_t *id2) | |||
107 | return 0; | 96 | return 0; |
108 | } | 97 | } |
109 | 98 | ||
110 | /* Turns the result of id_closest into something quick_sort can use. | ||
111 | * Assumes p1->c1 == p2->c1. | ||
112 | */ | ||
113 | static int client_id_cmp(const ClientPair p1, const ClientPair p2) | ||
114 | { | ||
115 | int c = id_closest(p1.c1.client_id, p1.c2.client_id, p2.c2.client_id); | ||
116 | |||
117 | if (c == 2) | ||
118 | return -1; | ||
119 | |||
120 | return c; | ||
121 | } | ||
122 | |||
123 | /* Shared key generations are costly, it is therefor smart to store commonly used | 99 | /* Shared key generations are costly, it is therefor smart to store commonly used |
124 | * ones so that they can re used later without being computed again. | 100 | * ones so that they can re used later without being computed again. |
125 | * | 101 | * |
@@ -629,172 +605,61 @@ int get_close_nodes(const DHT *dht, const uint8_t *client_id, Node_format *nodes | |||
629 | #endif | 605 | #endif |
630 | } | 606 | } |
631 | 607 | ||
632 | /* Replace first bad (or empty) node with this one. | 608 | /* Replace a first bad (or empty) node with this one |
609 | * or replace a possibly bad node (tests failed or not done yet) | ||
610 | * that is further than any other in the list | ||
611 | * from the comp_client_id | ||
612 | * or replace a good node that is further | ||
613 | * than any other in the list from the comp_client_id | ||
614 | * and further than client_id. | ||
633 | * | 615 | * |
634 | * return 0 if successful. | 616 | * Do not replace any node if the list has no bad or possibly bad nodes |
635 | * return 1 if not (list contains no bad nodes). | 617 | * and all nodes in the list are closer to comp_client_id |
636 | */ | 618 | * than client_id. |
637 | static int replace_bad( Client_data *list, | 619 | * |
620 | * returns True(1) when the item was stored, False(0) otherwise */ | ||
621 | static int replace_all( Client_data *list, | ||
638 | uint32_t length, | 622 | uint32_t length, |
639 | const uint8_t *client_id, | 623 | const uint8_t *client_id, |
640 | IP_Port ip_port ) | 624 | IP_Port ip_port, |
625 | const uint8_t *comp_client_id ) | ||
641 | { | 626 | { |
642 | if ((ip_port.ip.family != AF_INET) && (ip_port.ip.family != AF_INET6)) | 627 | if ((ip_port.ip.family != AF_INET) && (ip_port.ip.family != AF_INET6)) |
643 | return 1; | 628 | return 1; |
644 | 629 | ||
645 | uint32_t i; | 630 | uint32_t i, replace = ~0, bad = ~0, possibly_bad = ~0, good = ~0; |
646 | 631 | ||
647 | for (i = 0; i < length; ++i) { | 632 | for (i = 0; i < length; ++i) { |
648 | /* If node is bad */ | ||
649 | Client_data *client = &list[i]; | ||
650 | |||
651 | if (is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) && | ||
652 | is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT)) { | ||
653 | |||
654 | IPPTsPng *ipptp_write = NULL; | ||
655 | IPPTsPng *ipptp_clear = NULL; | ||
656 | |||
657 | if (ip_port.ip.family == AF_INET) { | ||
658 | ipptp_write = &client->assoc4; | ||
659 | ipptp_clear = &client->assoc6; | ||
660 | } else { | ||
661 | ipptp_write = &client->assoc6; | ||
662 | ipptp_clear = &client->assoc4; | ||
663 | } | ||
664 | |||
665 | memcpy(client->client_id, client_id, CLIENT_ID_SIZE); | ||
666 | ipptp_write->ip_port = ip_port; | ||
667 | ipptp_write->timestamp = unix_time(); | ||
668 | |||
669 | ip_reset(&ipptp_write->ret_ip_port.ip); | ||
670 | ipptp_write->ret_ip_port.port = 0; | ||
671 | ipptp_write->ret_timestamp = 0; | ||
672 | 633 | ||
673 | /* zero out other address */ | ||
674 | memset(ipptp_clear, 0, sizeof(*ipptp_clear)); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | } | ||
679 | |||
680 | return 1; | ||
681 | } | ||
682 | |||
683 | |||
684 | /* Sort the list. It will be sorted from furthest to closest. | ||
685 | * Turns list into data that quick sort can use and reverts it back. | ||
686 | */ | ||
687 | static void sort_list(Client_data *list, uint32_t length, const uint8_t *comp_client_id) | ||
688 | { | ||
689 | Client_data cd; | ||
690 | ClientPair pairs[length]; | ||
691 | uint32_t i; | ||
692 | |||
693 | memcpy(cd.client_id, comp_client_id, CLIENT_ID_SIZE); | ||
694 | |||
695 | for (i = 0; i < length; ++i) { | ||
696 | pairs[i].c1 = cd; | ||
697 | pairs[i].c2 = list[i]; | ||
698 | } | ||
699 | |||
700 | ClientPair_quick_sort(pairs, length, client_id_cmp); | ||
701 | |||
702 | for (i = 0; i < length; ++i) | ||
703 | list[i] = pairs[i].c2; | ||
704 | } | ||
705 | |||
706 | /* Replace first node that is possibly bad (tests failed or not done yet.) with this one. | ||
707 | * | ||
708 | * return 0 if successful. | ||
709 | * return 1 if not (list contains no bad nodes). | ||
710 | */ | ||
711 | static int replace_possible_bad( Client_data *list, | ||
712 | uint32_t length, | ||
713 | const uint8_t *client_id, | ||
714 | IP_Port ip_port, | ||
715 | const uint8_t *comp_client_id ) | ||
716 | { | ||
717 | if ((ip_port.ip.family != AF_INET) && (ip_port.ip.family != AF_INET6)) | ||
718 | return 1; | ||
719 | |||
720 | sort_list(list, length, comp_client_id); | ||
721 | |||
722 | /* TODO: decide if the following lines should stay commented or not. | ||
723 | if (id_closest(comp_client_id, list[0].client_id, client_id) == 1) | ||
724 | return 0;*/ | ||
725 | |||
726 | uint32_t i; | ||
727 | |||
728 | for (i = 0; i < length; ++i) { | ||
729 | /* If node is bad */ | ||
730 | Client_data *client = &list[i]; | 634 | Client_data *client = &list[i]; |
731 | 635 | ||
732 | if (hardening_correct(&client->assoc4.hardening) != HARDENING_ALL_OK && | 636 | if (is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) && |
733 | hardening_correct(&client->assoc6.hardening) != HARDENING_ALL_OK) { | 637 | is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT)) { |
734 | 638 | // "bad" node | |
735 | IPPTsPng *ipptp_write = NULL; | 639 | bad = i; |
736 | IPPTsPng *ipptp_clear = NULL; | 640 | break; |
737 | 641 | } else if (hardening_correct(&client->assoc4.hardening) != HARDENING_ALL_OK && | |
738 | if (ip_port.ip.family == AF_INET) { | 642 | hardening_correct(&client->assoc6.hardening) != HARDENING_ALL_OK) { |
739 | ipptp_write = &client->assoc4; | 643 | // "possibly bad" node |
740 | ipptp_clear = &client->assoc6; | 644 | if (possibly_bad == ~0 || |
741 | } else { | 645 | id_closest(comp_client_id, list[possibly_bad].client_id, list[i].client_id) == 1) |
742 | ipptp_write = &client->assoc6; | 646 | possibly_bad = i; |
743 | ipptp_clear = &client->assoc4; | 647 | } else { |
744 | } | 648 | // "good" node |
745 | 649 | if (good == ~0 || | |
746 | memcpy(client->client_id, client_id, CLIENT_ID_SIZE); | 650 | id_closest(comp_client_id, list[good].client_id, list[i].client_id) == 1) |
747 | ipptp_write->ip_port = ip_port; | 651 | good = i; |
748 | ipptp_write->timestamp = unix_time(); | ||
749 | |||
750 | ip_reset(&ipptp_write->ret_ip_port.ip); | ||
751 | ipptp_write->ret_ip_port.port = 0; | ||
752 | ipptp_write->ret_timestamp = 0; | ||
753 | |||
754 | /* zero out other address */ | ||
755 | memset(ipptp_clear, 0, sizeof(*ipptp_clear)); | ||
756 | |||
757 | return 0; | ||
758 | } | 652 | } |
759 | } | 653 | } |
760 | 654 | ||
761 | return 1; | 655 | if (bad != ~0) |
762 | } | 656 | replace = bad; |
763 | 657 | else if (possibly_bad != ~0) | |
764 | /* Replace the first good node that is further to the comp_client_id than that of the client_id in the list | 658 | replace = possibly_bad; |
765 | * | 659 | else if (good != ~0 && id_closest(comp_client_id, list[good].client_id, client_id) == 2) |
766 | * returns 0 when the item was stored, 1 otherwise */ | 660 | replace = good; |
767 | static int replace_good( Client_data *list, | ||
768 | uint32_t length, | ||
769 | const uint8_t *client_id, | ||
770 | IP_Port ip_port, | ||
771 | const uint8_t *comp_client_id ) | ||
772 | { | ||
773 | if ((ip_port.ip.family != AF_INET) && (ip_port.ip.family != AF_INET6)) | ||
774 | return 1; | ||
775 | |||
776 | /* TODO: eventually remove this.*/ | ||
777 | if (length != LCLIENT_LIST) | ||
778 | sort_list(list, length, comp_client_id); | ||
779 | |||
780 | int8_t replace = -1; | ||
781 | 661 | ||
782 | /* Because the list is sorted, we can simply check the client_id at the | 662 | if (replace != ~0) { |
783 | * border, either it is closer, then every other one is as well, or it is | ||
784 | * further, then it gets pushed out in favor of the new address, which | ||
785 | * will with the next sort() move to its "rightful" position | ||
786 | * | ||
787 | * CAVEAT: weirdly enough, the list is sorted DESCENDING in distance | ||
788 | * so the furthest element is the first, NOT the last (at least that's | ||
789 | * what the comment above sort_list() claims) | ||
790 | */ | ||
791 | if (id_closest(comp_client_id, list[0].client_id, client_id) == 2) | ||
792 | replace = 0; | ||
793 | |||
794 | if (replace != -1) { | ||
795 | #ifdef DEBUG | ||
796 | assert(replace >= 0 && replace < length); | ||
797 | #endif | ||
798 | Client_data *client = &list[replace]; | 663 | Client_data *client = &list[replace]; |
799 | IPPTsPng *ipptp_write = NULL; | 664 | IPPTsPng *ipptp_write = NULL; |
800 | IPPTsPng *ipptp_clear = NULL; | 665 | IPPTsPng *ipptp_clear = NULL; |
@@ -807,7 +672,7 @@ static int replace_good( Client_data *list, | |||
807 | ipptp_clear = &client->assoc4; | 672 | ipptp_clear = &client->assoc4; |
808 | } | 673 | } |
809 | 674 | ||
810 | memcpy(client->client_id, client_id, CLIENT_ID_SIZE); | 675 | id_copy(client->client_id, client_id); |
811 | ipptp_write->ip_port = ip_port; | 676 | ipptp_write->ip_port = ip_port; |
812 | ipptp_write->timestamp = unix_time(); | 677 | ipptp_write->timestamp = unix_time(); |
813 | 678 | ||
@@ -818,10 +683,10 @@ static int replace_good( Client_data *list, | |||
818 | /* zero out other address */ | 683 | /* zero out other address */ |
819 | memset(ipptp_clear, 0, sizeof(*ipptp_clear)); | 684 | memset(ipptp_clear, 0, sizeof(*ipptp_clear)); |
820 | 685 | ||
821 | return 0; | 686 | return 1; |
822 | } | 687 | } |
823 | 688 | ||
824 | return 1; | 689 | return 0; |
825 | } | 690 | } |
826 | 691 | ||
827 | /* Attempt to add client with ip_port and client_id to the friends client list | 692 | /* Attempt to add client with ip_port and client_id to the friends client list |
@@ -843,16 +708,7 @@ int addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *client_id) | |||
843 | * to replace the first ip by the second. | 708 | * to replace the first ip by the second. |
844 | */ | 709 | */ |
845 | if (!client_or_ip_port_in_list(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) { | 710 | if (!client_or_ip_port_in_list(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) { |
846 | if (replace_bad(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) { | 711 | if (replace_all(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port, dht->self_public_key)) |
847 | if (replace_possible_bad(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port, | ||
848 | dht->self_public_key)) { | ||
849 | /* If we can't replace bad nodes we try replacing good ones. */ | ||
850 | if (!replace_good(dht->close_clientlist, LCLIENT_LIST, client_id, ip_port, | ||
851 | dht->self_public_key)) | ||
852 | used++; | ||
853 | } else | ||
854 | used++; | ||
855 | } else | ||
856 | used++; | 712 | used++; |
857 | } else | 713 | } else |
858 | used++; | 714 | used++; |
@@ -860,19 +716,8 @@ int addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *client_id) | |||
860 | for (i = 0; i < dht->num_friends; ++i) { | 716 | for (i = 0; i < dht->num_friends; ++i) { |
861 | if (!client_or_ip_port_in_list(dht->friends_list[i].client_list, | 717 | if (!client_or_ip_port_in_list(dht->friends_list[i].client_list, |
862 | MAX_FRIEND_CLIENTS, client_id, ip_port)) { | 718 | MAX_FRIEND_CLIENTS, client_id, ip_port)) { |
863 | 719 | if (replace_all(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, | |
864 | if (replace_bad(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, | 720 | client_id, ip_port, dht->friends_list[i].client_id)) |
865 | client_id, ip_port)) { | ||
866 | /*if (replace_possible_bad(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, | ||
867 | client_id, ip_port, dht->friends_list[i].client_id)) {*/ | ||
868 | /* If we can't replace bad nodes we try replacing good ones. */ | ||
869 | if (!replace_good(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, | ||
870 | client_id, ip_port, dht->friends_list[i].client_id)) | ||
871 | used++; | ||
872 | |||
873 | /*} else | ||
874 | used++;*/ | ||
875 | } else | ||
876 | used++; | 721 | used++; |
877 | } else | 722 | } else |
878 | used++; | 723 | used++; |