summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpyruvate <d.pyruvate.kinase@gmail.com>2014-08-09 10:50:43 +0300
committerpyruvate <d.pyruvate.kinase@gmail.com>2014-08-09 11:33:20 +0300
commitbdf1c972735f4a6518f24d3770729fab142020fe (patch)
tree6ffac5b785f20c8f8e6a479d08784316e537eae5
parenta460b9fbd0bd262b7e9c6d2b3f8d835a6b973093 (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.c4
-rw-r--r--toxcore/DHT.c245
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. */
69typedef struct {
70 Client_data c1;
71 Client_data c2;
72} ClientPair;
73
74/* Create the declaration for a quick sort for ClientPair structures. */
75declare_quick_sort(ClientPair);
76/* Create the quicksort function. See misc_tools.h for the definition. */
77make_quick_sort(ClientPair);
78
79Client_data *DHT_get_close_list(DHT *dht) 68Client_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 */
113static 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.
637static int replace_bad( Client_data *list, 619 *
620 * returns True(1) when the item was stored, False(0) otherwise */
621static 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 */
687static 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 */
711static 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;
767static 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++;