Skip to content

Commit

Permalink
Merge 3155508 into 7418174
Browse files Browse the repository at this point in the history
  • Loading branch information
zugz committed Aug 16, 2019
2 parents 7418174 + 3155508 commit 417f08d
Show file tree
Hide file tree
Showing 22 changed files with 1,100 additions and 48 deletions.
7 changes: 6 additions & 1 deletion CMakeLists.txt
Expand Up @@ -206,7 +206,11 @@ set(toxcore_SOURCES ${toxcore_SOURCES}
toxcore/onion_announce.c
toxcore/onion_announce.h
toxcore/onion_client.c
toxcore/onion_client.h)
toxcore/onion_client.h
toxcore/forwarding.c
toxcore/forwarding.h
toxcore/forwarders.c
toxcore/forwarders.h)

# LAYER 5: Friend requests and connections
# ----------------------------------------
Expand Down Expand Up @@ -405,6 +409,7 @@ auto_test(dht MSVC_DONT_BUILD)
auto_test(encryptsave)
auto_test(file_transfer)
auto_test(file_saving)
auto_test(forwarding)
auto_test(friend_connection)
auto_test(friend_request)
auto_test(invalid_tcp_proxy)
Expand Down
5 changes: 5 additions & 0 deletions auto_tests/Makefile.inc
Expand Up @@ -12,6 +12,7 @@ TESTS = \
encryptsave_test \
file_saving_test \
file_transfer_test \
forwarding_test \
friend_connection_test \
friend_request_test \
invalid_tcp_proxy_test \
Expand Down Expand Up @@ -107,6 +108,10 @@ file_transfer_test_SOURCES = ../auto_tests/file_transfer_test.c
file_transfer_test_CFLAGS = $(AUTOTEST_CFLAGS)
file_transfer_test_LDADD = $(AUTOTEST_LDADD)

forwarding_test_SOURCES = ../auto_tests/forwarding_test.c
forwarding_test_CFLAGS = $(AUTOTEST_CFLAGS)
forwarding_test_LDADD = $(AUTOTEST_LDADD)

friend_connection_test_SOURCES = ../auto_tests/friend_connection_test.c
friend_connection_test_CFLAGS = $(AUTOTEST_CFLAGS)
friend_connection_test_LDADD = $(AUTOTEST_LDADD)
Expand Down
195 changes: 195 additions & 0 deletions auto_tests/forwarding_test.c
@@ -0,0 +1,195 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include "../toxcore/tox.h"
#include "../testing/misc_tools.h"
#include "../toxcore/mono_time.h"
#include "../toxcore/forwarding.h"
#include "../toxcore/forwarders.h"
#include "../toxcore/util.h"
#include "check_compat.h"

#ifndef USE_IPV6
#define USE_IPV6 1
#endif

static inline IP get_loopback(void)
{
IP ip;
#if USE_IPV6
ip.family = net_family_ipv6;
ip.ip.v6 = get_ip6_loopback();
#else
ip.family = net_family_ipv4;
ip.ip.v4 = get_ip4_loopback();
#endif
return ip;
}

#define NUM_FORWARDER 5
#define FORWARDER_TCP_RELAY_PORT 36570
#define FORWARDING_BASE_PORT 36571

typedef struct Test_Data {
Forwarders *forwarders;
uint32_t send_back;
bool sent;
bool returned;
} Test_Data;

static bool test_forwarded_cb(void *object, IP_Port sender, IP_Port forwarder,
const uint8_t *data, uint16_t length, void *userdata)
{
Test_Data *test_data = (Test_Data *)object;
uint8_t *index = (uint8_t *)userdata;

if (length == 11 && memcmp("hello: ", data, 7) == 0) {
uint8_t reply[11];
memcpy(reply, "reply: ", 7);
memcpy(reply + 7, data + 7, 4);
send_forward_request_to(test_data->forwarders, forwarder, sender, reply, 11);
return false;
}

if (length == 11 && memcmp("reply: ", data, 7) == 0) {
ck_assert_msg(memcmp(&test_data->send_back, data + 7, 4) == 0,
"[%u] got unexpected reply: %u", *index, *(const uint32_t *)(data + 7));
printf("[%u] got reply\n", *index);
test_data->returned = true;
return true;
}

printf("[%u] got unexpected data\n", *index);
return false;
}

static bool all_returned(Test_Data *test_data)
{
for (uint32_t i = 0; i < NUM_FORWARDER; ++i) {
if (!test_data[i].returned) {
return false;
}
}

return true;
}

static void test_forwarding(void)
{
assert(sizeof(char) == 1);

uint32_t index[NUM_FORWARDER];
Logger *logs[NUM_FORWARDER];
Mono_Time *mono_times[NUM_FORWARDER];
Networking_Core *nets[NUM_FORWARDER];
DHT *dhts[NUM_FORWARDER];
Net_Crypto *cs[NUM_FORWARDER];
Forwarding *forwardings[NUM_FORWARDER];
Forwarders *forwarderses[NUM_FORWARDER];

Test_Data test_data[NUM_FORWARDER];

IP ip = get_loopback();
TCP_Proxy_Info inf = {{{{0}}}};

for (uint32_t i = 0; i < NUM_FORWARDER; ++i) {
index[i] = i + 1;
logs[i] = logger_new();
logger_callback_log(logs[i], (logger_cb *)print_debug_log, nullptr, &index[i]);
mono_times[i] = mono_time_new();

nets[i] = new_networking(logs[i], ip, FORWARDING_BASE_PORT + i);

dhts[i] = new_dht(logs[i], mono_times[i], nets[i], true);
cs[i] = new_net_crypto(logs[i], mono_times[i], dhts[i], &inf);
forwardings[i] = new_forwarding(nets[i]);
forwarderses[i] = new_forwarders(mono_times[i], dhts[i], cs[i]);
ck_assert_msg((forwarderses[i] != nullptr), "Forwarders failed initializing.");

test_data[i].forwarders = forwarderses[i];
test_data[i].send_back = 0;
test_data[i].sent = false;
test_data[i].returned = false;
set_callback_forwarded(forwarderses[i], test_forwarded_cb, &test_data[i]);
}

printf("testing forwarding via tcp relays and dht\n");
struct Tox_Options *opts = tox_options_new(nullptr);
tox_options_set_tcp_port(opts, FORWARDER_TCP_RELAY_PORT);
IP_Port relay_ipport_tcp = {ip, net_htons(FORWARDER_TCP_RELAY_PORT)};
Tox *relay = tox_new_log(opts, nullptr, nullptr);
ck_assert_msg(relay != nullptr, "Failed to create TCP relay");
uint8_t dpk[TOX_PUBLIC_KEY_SIZE];
tox_self_get_dht_id(relay, dpk);

printf("1-%d connected only to TCP server; %d-%d connected only to DHT\n",
NUM_FORWARDER / 2, NUM_FORWARDER / 2 + 1, NUM_FORWARDER);

for (uint32_t i = 0; i < NUM_FORWARDER / 2; ++i) {
set_tcp_onion_status(nc_get_tcp_c(cs[i]), 1);
ck_assert_msg(add_tcp_relay(cs[i], relay_ipport_tcp, dpk) == 0,
"Failed to add TCP relay");
};

IP_Port relay_ipport_udp = {ip, net_htons(tox_self_get_udp_port(relay, nullptr))};

for (uint32_t i = NUM_FORWARDER / 2; i < NUM_FORWARDER; ++i) {
dht_bootstrap(dhts[i % NUM_FORWARDER], relay_ipport_udp, dpk);
}

do {
for (uint32_t i = 0; i < NUM_FORWARDER; ++i) {
if (!test_data[i].sent) {
uint32_t dest_i = random_u32() % NUM_FORWARDER;
IP_Port dest = {ip, net_htons(FORWARDING_BASE_PORT + dest_i)};
uint8_t data[11];

memcpy(data, "hello: ", 7);
test_data[i].send_back = random_u32();
*(uint32_t *)(data + 7) = test_data[i].send_back;

if (send_forward_request(forwarderses[i], dest, data, 11)) {
printf("%u --> ? --> %u\n", i + 1, dest_i + 1);
test_data[i].sent = true;
}
}

mono_time_update(mono_times[i]);
networking_poll(nets[i], &index[i]);
do_net_crypto(cs[i], &index[i]);
do_dht(dhts[i]);
}

tox_iterate(relay, nullptr);

c_sleep(50);
} while (!all_returned(test_data));


for (uint32_t i = 0; i < NUM_FORWARDER; ++i) {
kill_forwarders(forwarderses[i]);
kill_forwarding(forwardings[i]);
kill_net_crypto(cs[i]);
kill_dht(dhts[i]);
kill_networking(nets[i]);
mono_time_free(mono_times[i]);
logger_kill(logs[i]);
}

tox_kill(relay);
}


int main(void)
{
setvbuf(stdout, nullptr, _IONBF, 0);

test_forwarding();

return 0;
}
60 changes: 54 additions & 6 deletions toxcore/DHT.c
Expand Up @@ -413,7 +413,7 @@ int packed_node_size(Family ip_family)
* Returns size of packed IP_Port data on success
* Return -1 on failure.
*/
int pack_ip_port(uint8_t *data, uint16_t length, const IP_Port *ip_port)
int pack_ip_port(uint8_t *data, uint16_t length, const IP_Port *ip_port, bool any_family)
{
if (data == nullptr) {
return -1;
Expand All @@ -436,7 +436,12 @@ int pack_ip_port(uint8_t *data, uint16_t length, const IP_Port *ip_port)
is_ipv4 = false;
net_family = TOX_TCP_INET6;
} else {
return -1;
if (any_family) {
is_ipv4 = false;
net_family = ip_port->ip.family.value;
} else {
return -1;
}
}

if (is_ipv4) {
Expand Down Expand Up @@ -491,7 +496,7 @@ static int dht_create_packet(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE],
* Return size of unpacked ip_port on success.
* Return -1 on failure.
*/
int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, bool tcp_enabled)
int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, bool tcp_enabled, bool any_family)
{
if (data == nullptr) {
return -1;
Expand Down Expand Up @@ -521,7 +526,12 @@ int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, bool
is_ipv4 = false;
host_family = net_family_tcp_ipv6;
} else {
return -1;
if (any_family) {
is_ipv4 = false;
host_family.value = data[0];
} else {
return -1;
}
}

if (is_ipv4) {
Expand Down Expand Up @@ -559,7 +569,7 @@ int pack_nodes(uint8_t *data, uint16_t length, const Node_format *nodes, uint16_
uint32_t packed_length = 0;

for (uint32_t i = 0; i < number && packed_length < length; ++i) {
const int ipp_size = pack_ip_port(data + packed_length, length - packed_length, &nodes[i].ip_port);
const int ipp_size = pack_ip_port(data + packed_length, length - packed_length, &nodes[i].ip_port, false);

if (ipp_size == -1) {
return -1;
Expand Down Expand Up @@ -596,7 +606,8 @@ int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed
uint32_t num = 0, len_processed = 0;

while (num < max_num_nodes && len_processed < length) {
const int ipp_size = unpack_ip_port(&nodes[num].ip_port, data + len_processed, length - len_processed, tcp_enabled);
const int ipp_size = unpack_ip_port(&nodes[num].ip_port, data + len_processed, length - len_processed, tcp_enabled,
false);

if (ipp_size == -1) {
return -1;
Expand Down Expand Up @@ -2560,6 +2571,43 @@ static uint16_t list_nodes(Client_data *list, size_t length, const Mono_Time *mo
return count;
}

/* Put ip_port for a random node in ip_port.
* May fail (with low probability) even if there are nodes available.
*
* return true on success, false otherwise.
*/
bool random_dht_node_ip_port(const DHT *dht, IP_Port *ip_port)
{
const uint32_t max_num_nodes = LCLIENT_LIST + dht->num_friends * MAX_FRIEND_CLIENTS;
bool found = false;

for (uint32_t n = 0; !found && n < max_num_nodes; ++n) {
uint32_t i = random_u32() % max_num_nodes;
const Client_data *client_list = dht->close_clientlist;

if (i >= LCLIENT_LIST) {
client_list = dht->friends_list[(i - LCLIENT_LIST) / MAX_FRIEND_CLIENTS].client_list;
i = (i - LCLIENT_LIST) % MAX_FRIEND_CLIENTS;
}

const Client_data *client = &client_list[i];

if (!mono_time_is_timeout(dht->mono_time, client->assoc4.timestamp, BAD_NODE_TIMEOUT)) {
*ip_port = client->assoc4.ip_port;
found = true;
}

if (!mono_time_is_timeout(dht->mono_time, client->assoc6.timestamp, BAD_NODE_TIMEOUT)) {
if (!found || (random_u08() % 2)) {
*ip_port = client->assoc6.ip_port;
found = true;
}
}
}

return found;
}

/* Put up to max_num nodes in nodes from the random friends.
*
* return the number of nodes.
Expand Down
10 changes: 8 additions & 2 deletions toxcore/DHT.h
Expand Up @@ -167,14 +167,14 @@ int packed_node_size(Family ip_family);
* Returns size of packed IP_Port data on success
* Return -1 on failure.
*/
int pack_ip_port(uint8_t *data, uint16_t length, const IP_Port *ip_port);
int pack_ip_port(uint8_t *data, uint16_t length, const IP_Port *ip_port, bool any_family);

/* Unpack IP_Port structure from data of max size length into ip_port.
*
* Return size of unpacked ip_port on success.
* Return -1 on failure.
*/
int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, bool tcp_enabled);
int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, bool tcp_enabled, bool any_family);

/* Pack number of nodes into data of maxlength length.
*
Expand Down Expand Up @@ -327,6 +327,12 @@ bool node_addable_to_close_list(DHT *dht, const uint8_t *public_key, IP_Port ip_
int get_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list, Family sa_family,
bool is_LAN, uint8_t want_good);

/* Put ip_port for a random node in ip_port.
* May fail (with low probability) even if there are nodes available.
*
* return true on success, false otherwise.
*/
bool random_dht_node_ip_port(const DHT *dht, IP_Port *ip_port);

/* Put up to max_num nodes in nodes from the random friends.
*
Expand Down
4 changes: 4 additions & 0 deletions toxcore/Makefile.inc
Expand Up @@ -46,6 +46,10 @@ libtoxcore_la_SOURCES = ../toxcore/ccompat.h \
../toxcore/onion_announce.c \
../toxcore/onion_client.h \
../toxcore/onion_client.c \
../toxcore/forwarders.h \
../toxcore/forwarders.c \
../toxcore/forwarding.h \
../toxcore/forwarding.c \
../toxcore/TCP_client.h \
../toxcore/TCP_client.c \
../toxcore/TCP_server.h \
Expand Down

0 comments on commit 417f08d

Please sign in to comment.