Merge branch 'tcp_server'

This commit is contained in:
irungentoo 2015-05-20 15:52:03 -04:00
commit 7315ad08dd
No known key found for this signature in database
GPG Key ID: 10349DC9BED89E98
13 changed files with 396 additions and 65 deletions

View File

@ -809,6 +809,196 @@ loop_top:
}
END_TEST
#define TCP_RELAY_PORT 33448
START_TEST(test_many_clients_tcp)
{
long long unsigned int cur_time = time(NULL);
Tox *toxes[NUM_TOXES];
uint32_t i, j;
uint32_t to_comp = 974536;
for (i = 0; i < NUM_TOXES; ++i) {
struct Tox_Options opts;
tox_options_default(&opts);
if (i == 0) {
opts.tcp_port = TCP_RELAY_PORT;
} else {
opts.udp_enabled = 0;
}
toxes[i] = tox_new(&opts, 0, 0, 0);
ck_assert_msg(toxes[i] != 0, "Failed to create tox instances %u", i);
tox_callback_friend_request(toxes[i], accept_friend_request, &to_comp);
uint8_t dpk[TOX_PUBLIC_KEY_SIZE];
tox_self_get_dht_id(toxes[0], dpk);
ck_assert_msg(tox_add_tcp_relay(toxes[i], "::1", TCP_RELAY_PORT, dpk, 0), "add relay error");
ck_assert_msg(tox_bootstrap(toxes[i], "::1", 33445, dpk, 0), "Bootstrap error");
}
{
TOX_ERR_GET_PORT error;
ck_assert_msg(tox_self_get_udp_port(toxes[0], &error) == 33445, "First Tox instance did not bind to udp port 33445.\n");
ck_assert_msg(error == TOX_ERR_GET_PORT_OK, "wrong error");
ck_assert_msg(tox_self_get_tcp_port(toxes[0], &error) == TCP_RELAY_PORT,
"First Tox instance did not bind to tcp port %u.\n", TCP_RELAY_PORT);
ck_assert_msg(error == TOX_ERR_GET_PORT_OK, "wrong error");
}
struct {
uint16_t tox1;
uint16_t tox2;
} pairs[NUM_FRIENDS];
uint8_t address[TOX_ADDRESS_SIZE];
for (i = 0; i < NUM_FRIENDS; ++i) {
loop_top:
pairs[i].tox1 = rand() % NUM_TOXES;
pairs[i].tox2 = (pairs[i].tox1 + rand() % (NUM_TOXES - 1) + 1) % NUM_TOXES;
for (j = 0; j < i; ++j) {
if (pairs[j].tox2 == pairs[i].tox1 && pairs[j].tox1 == pairs[i].tox2)
goto loop_top;
}
tox_self_get_address(toxes[pairs[i].tox1], address);
TOX_ERR_FRIEND_ADD test;
uint32_t num = tox_friend_add(toxes[pairs[i].tox2], address, (uint8_t *)"Gentoo", 7, &test);
if (test == TOX_ERR_FRIEND_ADD_ALREADY_SENT) {
goto loop_top;
}
ck_assert_msg(num != UINT32_MAX && test == TOX_ERR_FRIEND_ADD_OK, "Failed to add friend error code: %i", test);
}
while (1) {
uint16_t counter = 0;
for (i = 0; i < NUM_TOXES; ++i) {
for (j = 0; j < tox_self_get_friend_list_size(toxes[i]); ++j)
if (tox_friend_get_connection_status(toxes[i], j, 0) == TOX_CONNECTION_TCP)
++counter;
}
if (counter == NUM_FRIENDS * 2) {
break;
}
for (i = 0; i < NUM_TOXES; ++i) {
tox_iterate(toxes[i]);
}
c_sleep(50);
}
for (i = 0; i < NUM_TOXES; ++i) {
tox_kill(toxes[i]);
}
printf("test_many_clients_tcp succeeded, took %llu seconds\n", time(NULL) - cur_time);
}
END_TEST
#define NUM_TCP_RELAYS 3
START_TEST(test_many_clients_tcp_b)
{
long long unsigned int cur_time = time(NULL);
Tox *toxes[NUM_TOXES];
uint32_t i, j;
uint32_t to_comp = 974536;
for (i = 0; i < NUM_TOXES; ++i) {
struct Tox_Options opts;
tox_options_default(&opts);
if (i < NUM_TCP_RELAYS) {
opts.tcp_port = TCP_RELAY_PORT + i;
} else {
opts.udp_enabled = 0;
}
toxes[i] = tox_new(&opts, 0, 0, 0);
ck_assert_msg(toxes[i] != 0, "Failed to create tox instances %u", i);
tox_callback_friend_request(toxes[i], accept_friend_request, &to_comp);
uint8_t dpk[TOX_PUBLIC_KEY_SIZE];
tox_self_get_dht_id(toxes[(i % NUM_TCP_RELAYS)], dpk);
ck_assert_msg(tox_add_tcp_relay(toxes[i], "::1", TCP_RELAY_PORT + (i % NUM_TCP_RELAYS), dpk, 0), "add relay error");
tox_self_get_dht_id(toxes[0], dpk);
ck_assert_msg(tox_bootstrap(toxes[i], "::1", 33445, dpk, 0), "Bootstrap error");
}
{
TOX_ERR_GET_PORT error;
ck_assert_msg(tox_self_get_udp_port(toxes[0], &error) == 33445, "First Tox instance did not bind to udp port 33445.\n");
ck_assert_msg(error == TOX_ERR_GET_PORT_OK, "wrong error");
ck_assert_msg(tox_self_get_tcp_port(toxes[0], &error) == TCP_RELAY_PORT,
"First Tox instance did not bind to tcp port %u.\n", TCP_RELAY_PORT);
ck_assert_msg(error == TOX_ERR_GET_PORT_OK, "wrong error");
}
struct {
uint16_t tox1;
uint16_t tox2;
} pairs[NUM_FRIENDS];
uint8_t address[TOX_ADDRESS_SIZE];
for (i = 0; i < NUM_FRIENDS; ++i) {
loop_top:
pairs[i].tox1 = rand() % NUM_TOXES;
pairs[i].tox2 = (pairs[i].tox1 + rand() % (NUM_TOXES - 1) + 1) % NUM_TOXES;
for (j = 0; j < i; ++j) {
if (pairs[j].tox2 == pairs[i].tox1 && pairs[j].tox1 == pairs[i].tox2)
goto loop_top;
}
tox_self_get_address(toxes[pairs[i].tox1], address);
TOX_ERR_FRIEND_ADD test;
uint32_t num = tox_friend_add(toxes[pairs[i].tox2], address, (uint8_t *)"Gentoo", 7, &test);
if (test == TOX_ERR_FRIEND_ADD_ALREADY_SENT) {
goto loop_top;
}
ck_assert_msg(num != UINT32_MAX && test == TOX_ERR_FRIEND_ADD_OK, "Failed to add friend error code: %i", test);
}
while (1) {
uint16_t counter = 0;
for (i = 0; i < NUM_TOXES; ++i) {
for (j = 0; j < tox_self_get_friend_list_size(toxes[i]); ++j)
if (tox_friend_get_connection_status(toxes[i], j, 0) == TOX_CONNECTION_TCP)
++counter;
}
if (counter == NUM_FRIENDS * 2) {
break;
}
for (i = 0; i < NUM_TOXES; ++i) {
tox_iterate(toxes[i]);
}
c_sleep(50);
}
for (i = 0; i < NUM_TOXES; ++i) {
tox_kill(toxes[i]);
}
printf("test_many_clients_tcp_b succeeded, took %llu seconds\n", time(NULL) - cur_time);
}
END_TEST
#define NUM_GROUP_TOX 32
void g_accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
@ -996,6 +1186,8 @@ Suite *tox_suite(void)
DEFTESTCASE(one);
DEFTESTCASE_SLOW(few_clients, 50);
DEFTESTCASE_SLOW(many_clients, 150);
DEFTESTCASE_SLOW(many_clients_tcp, 20);
DEFTESTCASE_SLOW(many_clients_tcp_b, 20);
DEFTESTCASE_SLOW(many_group, 100);
return s;
}

View File

@ -411,6 +411,11 @@ static class options {
* The end port of the inclusive port range to attempt to use.
*/
uint16_t end_port;
/**
* The port to use for the TCP server. If 0, the tcp server is disabled.
*/
uint16_t tcp_port;
}

View File

@ -163,9 +163,15 @@ void send_irc_group(Tox *tox, uint8_t *msg, uint16_t len)
uint8_t req[len];
unsigned int i;
unsigned int spaces = 0;
for (i = 0; i < (len - 1); ++i) {
if (msg[i + 1] == ':') {
break;
if (msg[i + 1] == ' ') {
++spaces;
} else {
if (spaces >= 3 && msg[i + 1] == ':') {
break;
}
}
req[i] = msg[i + 1];
@ -227,11 +233,6 @@ Tox *init_tox(int argc, char *argv[])
tox_callback_group_message(tox, &copy_groupmessage, 0);
tox_callback_group_action(tox, &copy_groupmessage, 0);
uint16_t port = atoi(argv[argvoffset + 2]);
unsigned char *binary_string = hex_string_to_bin(argv[argvoffset + 3]);
tox_bootstrap(tox, argv[argvoffset + 1], port, binary_string, 0);
free(binary_string);
char temp_id[128];
printf("\nEnter the address of irc_syncbots master (38 bytes HEX format):\n");
@ -239,6 +240,11 @@ Tox *init_tox(int argc, char *argv[])
exit (1);
}
uint16_t port = atoi(argv[argvoffset + 2]);
unsigned char *binary_string = hex_string_to_bin(argv[argvoffset + 3]);
tox_bootstrap(tox, argv[argvoffset + 1], port, binary_string, 0);
free(binary_string);
uint8_t *bin_id = hex_string_to_bin(temp_id);
uint32_t num = tox_friend_add(tox, bin_id, (uint8_t *)"Install Gentoo", sizeof("Install Gentoo") - 1, 0);
free(bin_id);

View File

@ -227,17 +227,42 @@ static IP broadcast_ip(sa_family_t family_socket, sa_family_t family_broadcast)
return ip;
}
/* return 0 if ip is a LAN ip.
* return -1 if it is not.
*/
int LAN_ip(IP ip)
/* Is IP a local ip or not. */
_Bool Local_ip(IP ip)
{
if (ip.family == AF_INET) {
IP4 ip4 = ip.ip4;
/* Loopback. */
if (ip4.uint8[0] == 127)
return 0;
return 1;
} else {
/* embedded IPv4-in-IPv6 */
if (IPV6_IPV4_IN_V6(ip.ip6)) {
IP ip4;
ip4.family = AF_INET;
ip4.ip4.uint32 = ip.ip6.uint32[3];
return Local_ip(ip4);
}
/* localhost in IPv6 (::1) */
if (ip.ip6.uint64[0] == 0 && ip.ip6.uint32[2] == 0 && ip.ip6.uint32[3] == htonl(1))
return 1;
}
return 0;
}
/* return 0 if ip is a LAN ip.
* return -1 if it is not.
*/
int LAN_ip(IP ip)
{
if (Local_ip(ip))
return 0;
if (ip.family == AF_INET) {
IP4 ip4 = ip.ip4;
/* 10.0.0.0 to 10.255.255.255 range. */
if (ip4.uint8[0] == 10)
@ -276,10 +301,6 @@ int LAN_ip(IP ip)
ip4.ip4.uint32 = ip.ip6.uint32[3];
return LAN_ip(ip4);
}
/* localhost in IPv6 (::1) */
if (ip.ip6.uint64[0] == 0 && ip.ip6.uint32[2] == 0 && ip.ip6.uint32[3] == htonl(1))
return 0;
}
return -1;

View File

@ -40,6 +40,9 @@ void LANdiscovery_init(DHT *dht);
/* Clear packet handlers. */
void LANdiscovery_kill(DHT *dht);
/* Is IP a local ip or not. */
_Bool Local_ip(IP ip);
/* checks if a given IP isn't routable
*
* return 0 if ip is a LAN ip.

View File

@ -1807,6 +1807,27 @@ Messenger *new_messenger(Messenger_Options *options, unsigned int *error)
return NULL;
}
if (options->tcp_server_port) {
m->tcp_server = new_TCP_server(options->ipv6enabled, 1, &options->tcp_server_port, m->dht->self_public_key,
m->dht->self_secret_key, m->onion);
if (m->tcp_server == NULL) {
kill_friend_connections(m->fr_c);
kill_onion(m->onion);
kill_onion_announce(m->onion_a);
kill_onion_client(m->onion_c);
kill_DHT(m->dht);
kill_net_crypto(m->net_crypto);
kill_networking(m->net);
free(m);
if (error)
*error = MESSENGER_ERROR_TCP_SERVER;
return NULL;
}
}
m->options = *options;
friendreq_init(&(m->fr), m->fr_c);
set_nospam(&(m->fr), random_int());
@ -1826,6 +1847,10 @@ void kill_messenger(Messenger *m)
uint32_t i;
if (m->tcp_server) {
kill_TCP_server(m->tcp_server);
}
kill_friend_connections(m->fr_c);
kill_onion(m->onion);
kill_onion_announce(m->onion_a);
@ -2261,6 +2286,15 @@ void do_messenger(Messenger *m)
for (i = 0; i < NUM_SAVED_TCP_RELAYS; ++i) {
add_tcp_relay(m->net_crypto, m->loaded_relays[i].ip_port, m->loaded_relays[i].public_key);
}
if (m->tcp_server) {
/* Add self tcp server. */
IP_Port local_ip_port;
local_ip_port.port = m->options.tcp_server_port;
local_ip_port.ip.family = AF_INET;
local_ip_port.ip.ip4.uint32 = INADDR_LOOPBACK;
add_tcp_relay(m->net_crypto, local_ip_port, m->tcp_server->public_key);
}
}
unix_time_update();
@ -2270,6 +2304,10 @@ void do_messenger(Messenger *m)
do_DHT(m->dht);
}
if (m->tcp_server) {
do_TCP_server(m->tcp_server);
}
do_net_crypto(m->net_crypto);
do_onion_client(m->onion_c);
do_friend_connections(m->fr_c);

View File

@ -70,6 +70,7 @@ typedef struct {
uint8_t udp_disabled;
TCP_Proxy_Info proxy_info;
uint16_t port_range[2];
uint16_t tcp_server_port;
} Messenger_Options;
@ -219,6 +220,7 @@ struct Messenger {
Friend_Connections *fr_c;
TCP_Server *tcp_server;
Friend_Requests fr;
uint8_t name[MAX_NAME_LENGTH];
uint16_t name_length;
@ -727,6 +729,7 @@ int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const
enum {
MESSENGER_ERROR_NONE,
MESSENGER_ERROR_PORT,
MESSENGER_ERROR_TCP_SERVER,
MESSENGER_ERROR_OTHER
};

View File

@ -158,6 +158,15 @@ int friend_add_tcp_relay(Friend_Connections *fr_c, int friendcon_id, IP_Port ip_
if (!friend_con)
return -1;
/* Local ip and same pk means that they are hosting a TCP relay. */
if (Local_ip(ip_port.ip) && memcmp(friend_con->dht_temp_pk, public_key, crypto_box_PUBLICKEYBYTES) == 0) {
if (friend_con->dht_ip_port.ip.family != 0) {
ip_port.ip = friend_con->dht_ip_port.ip;
} else {
friend_con->hosting_tcp_relay = 0;
}
}
unsigned int i;
uint16_t index = friend_con->tcp_relay_counter % FRIEND_MAX_STORED_TCP_RELAYS;
@ -268,6 +277,11 @@ static void dht_ip_callback(void *object, int32_t number, IP_Port ip_port)
set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, 1);
friend_con->dht_ip_port = ip_port;
friend_con->dht_ip_port_lastrecv = unix_time();
if (friend_con->hosting_tcp_relay) {
friend_add_tcp_relay(fr_c, number, ip_port, friend_con->dht_temp_pk);
friend_con->hosting_tcp_relay = 0;
}
}
static void change_dht_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_public_key)
@ -317,6 +331,7 @@ static int handle_status(void *object, int number, uint8_t status)
friend_con->status = FRIENDCONN_STATUS_CONNECTING;
friend_con->crypt_connection_id = -1;
friend_con->hosting_tcp_relay = 0;
}
if (call_cb) {

View File

@ -96,6 +96,8 @@ typedef struct {
Node_format tcp_relays[FRIEND_MAX_STORED_TCP_RELAYS];
uint16_t tcp_relay_counter;
_Bool hosting_tcp_relay;
} Friend_Conn;

View File

@ -25,7 +25,7 @@
#include "onion.h"
#define ONION_ANNOUNCE_MAX_ENTRIES 64
#define ONION_ANNOUNCE_MAX_ENTRIES 96
#define ONION_ANNOUNCE_TIMEOUT 300
#define ONION_PING_ID_SIZE crypto_hash_sha256_BYTES

View File

@ -1204,7 +1204,7 @@ static void populate_path_nodes_tcp(Onion_Client *onion_c)
unsigned int i;
for (i = 0; i < num_nodes; ++i) {
onion_add_path_node(onion_c, nodes_list[i].ip_port, nodes_list[i].public_key);
onion_add_bs_path_node(onion_c, nodes_list[i].ip_port, nodes_list[i].public_key);
}
}

View File

@ -152,6 +152,7 @@ Tox *tox_new(const struct Tox_Options *options, const uint8_t *data, size_t leng
m_options.udp_disabled = !options->udp_enabled;
m_options.port_range[0] = options->start_port;
m_options.port_range[1] = options->end_port;
m_options.tcp_server_port = options->tcp_port;
switch (options->proxy_type) {
case TOX_PROXY_TYPE_HTTP:
@ -238,31 +239,6 @@ void tox_get_savedata(const Tox *tox, uint8_t *data)
}
}
static int address_to_ip(Messenger *m, const char *address, IP_Port *ip_port, IP_Port *ip_port_v4)
{
if (!addr_parse_ip(address, &ip_port->ip)) {
if (m->options.udp_disabled) { /* Disable DNS when udp is disabled. */
return -1;
}
IP *ip_extra = NULL;
ip_init(&ip_port->ip, m->options.ipv6enabled);
if (m->options.ipv6enabled && ip_port_v4) {
/* setup for getting BOTH: an IPv6 AND an IPv4 address */
ip_port->ip.family = AF_UNSPEC;
ip_reset(&ip_port_v4->ip);
ip_extra = &ip_port_v4->ip;
}
if (!addr_resolve(address, &ip_port->ip, ip_extra)) {
return -1;
}
}
return 0;
}
bool tox_bootstrap(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error)
{
if (!address || !public_key) {
@ -270,23 +246,53 @@ bool tox_bootstrap(Tox *tox, const char *address, uint16_t port, const uint8_t *
return 0;
}
Messenger *m = tox;
bool ret = tox_add_tcp_relay(tox, address, port, public_key, error);
if (!ret) {
if (port == 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT);
return 0;
}
if (m->options.udp_disabled) {
return ret;
} else { /* DHT only works on UDP. */
if (DHT_bootstrap_from_address(m->dht, address, m->options.ipv6enabled, htons(port), public_key) == 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);
return 0;
struct addrinfo *root, *info;
if (getaddrinfo(address, NULL, NULL, &root) != 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);
return 0;
}
info = root;
unsigned int count = 0;
do {
IP_Port ip_port;
ip_port.port = htons(port);
ip_port.ip.family = info->ai_family;
if (info->ai_socktype && info->ai_socktype != SOCK_DGRAM) {
continue;
}
if (info->ai_family == AF_INET) {
ip_port.ip.ip4.in_addr = ((struct sockaddr_in *)info->ai_addr)->sin_addr;
} else if (info->ai_family == AF_INET6) {
ip_port.ip.ip6.in6_addr = ((struct sockaddr_in6 *)info->ai_addr)->sin6_addr;
} else {
continue;
}
Messenger *m = tox;
onion_add_bs_path_node(m->onion_c, ip_port, public_key);
DHT_bootstrap(m->dht, ip_port, public_key);
++count;
} while ((info = info->ai_next));
freeaddrinfo(root);
if (count) {
SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK);
return 1;
} else {
SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);
return 0;
}
}
@ -298,25 +304,53 @@ bool tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8
return 0;
}
Messenger *m = tox;
IP_Port ip_port, ip_port_v4;
if (port == 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT);
return 0;
}
if (address_to_ip(m, address, &ip_port, &ip_port_v4) == -1) {
struct addrinfo *root, *info;
if (getaddrinfo(address, NULL, NULL, &root) != 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);
return 0;
}
ip_port.port = htons(port);
add_tcp_relay(m->net_crypto, ip_port, public_key);
onion_add_bs_path_node(m->onion_c, ip_port, public_key); //TODO: move this
info = root;
SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK);
return 1;
unsigned int count = 0;
do {
IP_Port ip_port;
ip_port.port = htons(port);
ip_port.ip.family = info->ai_family;
if (info->ai_socktype && info->ai_socktype != SOCK_STREAM) {
continue;
}
if (info->ai_family == AF_INET) {
ip_port.ip.ip4.in_addr = ((struct sockaddr_in *)info->ai_addr)->sin_addr;
} else if (info->ai_family == AF_INET6) {
ip_port.ip.ip6.in6_addr = ((struct sockaddr_in6 *)info->ai_addr)->sin6_addr;
} else {
continue;
}
Messenger *m = tox;
add_tcp_relay(m->net_crypto, ip_port, public_key);
++count;
} while ((info = info->ai_next));
freeaddrinfo(root);
if (count) {
SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK);
return 1;
} else {
SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);
return 0;
}
}
TOX_CONNECTION tox_self_get_connection_status(const Tox *tox)
@ -1205,9 +1239,15 @@ uint16_t tox_self_get_udp_port(const Tox *tox, TOX_ERR_GET_PORT *error)
uint16_t tox_self_get_tcp_port(const Tox *tox, TOX_ERR_GET_PORT *error)
{
/* TCP server not yet implemented in clients. */
SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND);
return 0;
const Messenger *m = tox;
if (m->tcp_server) {
SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK);
return m->options.tcp_server_port;
} else {
SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND);
return 0;
}
}
#include "tox_old_code.h"

View File

@ -426,6 +426,12 @@ struct Tox_Options {
*/
uint16_t end_port;
/**
* The port to use for the TCP server. If 0, the tcp server is disabled.
*/
uint16_t tcp_port;
};