From 66ab386d6fb0200d544eb841a05b68fc7151101e Mon Sep 17 00:00:00 2001 From: "zugz (tox)" Date: Tue, 14 Aug 2018 18:37:32 +0200 Subject: [PATCH] try ipv6 connections even after udp timeout Also adds a test (auto_reconnect_test) which fails without this change. --- CMakeLists.txt | 1 + auto_tests/Makefile.inc | 5 ++ auto_tests/reconnect_test.c | 108 ++++++++++++++++++++++++++++++++++++ toxcore/net_crypto.c | 15 +++++ 4 files changed, 129 insertions(+) create mode 100644 auto_tests/reconnect_test.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 95b12ce0..5090da5b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -427,6 +427,7 @@ auto_test(network) auto_test(onion) auto_test(overflow_recvq) auto_test(overflow_sendq) +auto_test(reconnect) auto_test(save_friend) auto_test(save_load) auto_test(send_message) diff --git a/auto_tests/Makefile.inc b/auto_tests/Makefile.inc index 6df92dcd..3a4b6c7e 100644 --- a/auto_tests/Makefile.inc +++ b/auto_tests/Makefile.inc @@ -24,6 +24,7 @@ TESTS = \ onion_test \ overflow_recvq_test \ overflow_sendq_test \ + reconnect_test \ save_compatibility_test \ save_friend_test \ save_load_test \ @@ -154,6 +155,10 @@ overflow_sendq_test_SOURCES = ../auto_tests/overflow_sendq_test.c overflow_sendq_test_CFLAGS = $(AUTOTEST_CFLAGS) overflow_sendq_test_LDADD = $(AUTOTEST_LDADD) +reconnect_test_SOURCES = ../auto_tests/reconnect_test.c +reconnect_test_CFLAGS = $(AUTO_TEST_CFLAGS) +reconnect_test_LDADD = $(AUTOTEST_LDADD) + save_compatibility_test_SOURCES = ../auto_tests/save_compatibility_test.c save_compatibility_test_CFLAGS = $(AUTOTEST_CFLAGS) save_compatibility_test_LDADD = $(AUTOTEST_LDADD) diff --git a/auto_tests/reconnect_test.c b/auto_tests/reconnect_test.c new file mode 100644 index 00000000..76cabd17 --- /dev/null +++ b/auto_tests/reconnect_test.c @@ -0,0 +1,108 @@ +/* Auto Tests: Reconnection. + * + * This test checks that when a tox instance is suspended for long enough that + * its friend connections time out, those connections are promptly + * re-established when the instance is resumed. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "../testing/misc_tools.h" +#include "../toxcore/friend_connection.h" +#include "../toxcore/tox.h" +#include "../toxcore/util.h" +#include "check_compat.h" + +#define TOX_COUNT 2 +#define RECONNECT_TIME_MAX (FRIEND_CONNECTION_TIMEOUT + 3) + +typedef struct State { + uint32_t index; +} State; + +#include "run_auto_test.h" + +static uint32_t tox_connected_count(uint32_t tox_count, Tox **toxes, State *state, uint32_t index) +{ + const size_t friend_count = tox_self_get_friend_list_size(toxes[index]); + uint32_t connected_count = 0; + + for (size_t j = 0; j < friend_count; j++) { + if (tox_friend_get_connection_status(toxes[index], j, nullptr) != TOX_CONNECTION_NONE) { + ++connected_count; + } + } + + return connected_count; +} + +static bool all_disconnected_from(uint32_t tox_count, Tox **toxes, State *state, uint32_t index) +{ + for (uint32_t i = 0; i < tox_count; i++) { + if (i == index) { + continue; + } + + if (tox_connected_count(tox_count, toxes, state, i) >= tox_count - 1) { + return false; + } + } + + return true; +} + +static void test_reconnect(Tox **toxes, State *state) +{ + const time_t test_start_time = time(nullptr); + + printf("letting connections settle\n"); + + do { + iterate_all(TOX_COUNT, toxes, state); + + c_sleep(ITERATION_INTERVAL); + } while (time(nullptr) - test_start_time < 2); + + uint16_t disconnect = random_u16() % TOX_COUNT; + printf("disconnecting #%u\n", state[disconnect].index); + + do { + for (uint16_t i = 0; i < TOX_COUNT; ++i) { + if (i != disconnect) { + tox_iterate(toxes[i], &state[i]); + } + } + + c_sleep(ITERATION_INTERVAL); + } while (!all_disconnected_from(TOX_COUNT, toxes, state, disconnect)); + + const time_t reconnect_start_time = time(nullptr); + + printf("reconnecting\n"); + + do { + iterate_all(TOX_COUNT, toxes, state); + + c_sleep(ITERATION_INTERVAL); + } while (!all_friends_connected(TOX_COUNT, toxes)); + + const int reconnect_time = (int)(time(nullptr) - reconnect_start_time); + ck_assert_msg(reconnect_time <= RECONNECT_TIME_MAX, "reconnection took %d seconds; expected at most %d seconds", + reconnect_time, RECONNECT_TIME_MAX); + + printf("test_reconnect succeeded, took %d seconds\n", (int)(time(nullptr) - test_start_time)); +} + +int main(void) +{ + setvbuf(stdout, nullptr, _IONBF, 0); + + run_auto_test(TOX_COUNT, test_reconnect); + return 0; +} diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c index 76cd27e7..a64ed970 100644 --- a/toxcore/net_crypto.c +++ b/toxcore/net_crypto.c @@ -634,6 +634,9 @@ static IP_Port return_ip_port_connection(Net_Crypto *c, int crypt_connection_id) v6 = 1; } + /* Prefer IP_Ports which haven't timed out to those which have. + * To break ties, prefer ipv4 lan, then ipv6, then non-lan ipv4. + */ if (v4 && ip_is_lan(conn->ip_portv4.ip)) { return conn->ip_portv4; } @@ -642,6 +645,18 @@ static IP_Port return_ip_port_connection(Net_Crypto *c, int crypt_connection_id) return conn->ip_portv6; } + if (v4 && net_family_is_ipv4(conn->ip_portv4.ip.family)) { + return conn->ip_portv4; + } + + if (ip_is_lan(conn->ip_portv4.ip)) { + return conn->ip_portv4; + } + + if (net_family_is_ipv6(conn->ip_portv6.ip.family)) { + return conn->ip_portv6; + } + if (net_family_is_ipv4(conn->ip_portv4.ip.family)) { return conn->ip_portv4; }