If a net_crypto connection isn't using the TCP relays, disconnect from them.

TCP_connections can now be put to sleep, a state where they store what they
were connected to without being connected and then resumed from sleep.
This commit is contained in:
irungentoo 2015-04-21 14:30:39 -04:00
parent e4ae993a80
commit 0a0ed45202
No known key found for this signature in database
GPG Key ID: 10349DC9BED89E98
3 changed files with 240 additions and 13 deletions

View File

@ -333,6 +333,9 @@ int tcp_send_oob_packet(TCP_Connections *tcp_c, unsigned int tcp_connections_num
if (!tcp_con)
return -1;
if (tcp_con->status != TCP_CONN_CONNECTED)
return -1;
int ret = send_oob_packet(tcp_con->connection, public_key, packet, length);
if (ret == 1)
@ -404,8 +407,14 @@ static int find_tcp_connection_relay(TCP_Connections *tcp_c, const uint8_t *rela
TCP_con *tcp_con = get_tcp_connection(tcp_c, i);
if (tcp_con) {
if (memcmp(tcp_con->connection->public_key, relay_pk, crypto_box_PUBLICKEYBYTES) == 0) {
return i;
if (tcp_con->status == TCP_CONN_SLEEPING) {
if (memcmp(tcp_con->relay_pk, relay_pk, crypto_box_PUBLICKEYBYTES) == 0) {
return i;
}
} else {
if (memcmp(tcp_con->connection->public_key, relay_pk, crypto_box_PUBLICKEYBYTES) == 0) {
return i;
}
}
}
}
@ -465,6 +474,10 @@ int kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number)
if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) {
--tcp_con->lock_count;
if (con_to->status == TCP_CONN_SLEEPING) {
--tcp_con->sleep_count;
}
}
}
}
@ -472,6 +485,72 @@ int kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number)
return wipe_connection(tcp_c, connections_number);
}
/* Set connection status.
*
* status of 1 means we are using the connection.
* status of 0 means we are not using it.
*
* Unused tcp connections will be disconnected from but kept in case they are needed.
*
* return 0 on success.
* return -1 on failure.
*/
int set_tcp_connection_to_status(TCP_Connections *tcp_c, int connections_number, _Bool status)
{
TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);
if (!con_to)
return -1;
if (status) {
/* Conection is unsleeping. */
if (con_to->status != TCP_CONN_SLEEPING)
return -1;
unsigned int i;
for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
if (con_to->connections[i].tcp_connection) {
unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1;
TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
if (!tcp_con)
continue;
if (tcp_con->status == TCP_CONN_SLEEPING) {
tcp_con->unsleep = 1;
}
}
}
con_to->status = TCP_CONN_VALID;
return 0;
} else {
/* Conection is going to sleep. */
if (con_to->status != TCP_CONN_VALID)
return -1;
unsigned int i;
for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
if (con_to->connections[i].tcp_connection) {
unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1;
TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
if (!tcp_con)
continue;
if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) {
++tcp_con->sleep_count;
}
}
}
con_to->status = TCP_CONN_SLEEPING;
return 0;
}
}
static _Bool tcp_connection_in_conn(TCP_Connection_to *con_to, int tcp_connections_number)
{
unsigned int i;
@ -606,6 +685,9 @@ static int reconnect_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connec
if (!tcp_con)
return -1;
if (tcp_con->status == TCP_CONN_SLEEPING)
return -1;
IP_Port ip_port = tcp_con->connection->ip_port;
uint8_t relay_pk[crypto_box_PUBLICKEYBYTES];
memcpy(relay_pk, tcp_con->connection->public_key, crypto_box_PUBLICKEYBYTES);
@ -634,12 +716,83 @@ static int reconnect_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connec
}
tcp_con->lock_count = 0;
tcp_con->sleep_count = 0;
tcp_con->connected_time = 0;
tcp_con->status = TCP_CONN_VALID;
tcp_con->unsleep = 0;
return 0;
}
static int sleep_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number)
{
TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
if (!tcp_con)
return -1;
if (tcp_con->status != TCP_CONN_CONNECTED)
return -1;
if (tcp_con->lock_count != tcp_con->sleep_count)
return -1;
tcp_con->ip_port = tcp_con->connection->ip_port;
memcpy(tcp_con->relay_pk, tcp_con->connection->public_key, crypto_box_PUBLICKEYBYTES);
kill_TCP_connection(tcp_con->connection);
tcp_con->connection = NULL;
unsigned int i;
for (i = 0; i < tcp_c->connections_length; ++i) {
TCP_Connection_to *con_to = get_connection(tcp_c, i);
if (con_to) {
set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_NONE, 0);
}
}
if (tcp_con->onion) {
--tcp_c->onion_num_conns;
tcp_con->onion = 0;
}
tcp_con->lock_count = 0;
tcp_con->sleep_count = 0;
tcp_con->connected_time = 0;
tcp_con->status = TCP_CONN_SLEEPING;
tcp_con->unsleep = 0;
return 0;
}
static int unsleep_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number)
{
TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
if (!tcp_con)
return -1;
if (tcp_con->status != TCP_CONN_SLEEPING)
return -1;
tcp_con->connection = new_TCP_connection(tcp_con->ip_port, tcp_con->relay_pk, tcp_c->dht->self_public_key,
tcp_c->dht->self_secret_key, &tcp_c->proxy_info);
if (!tcp_con->connection) {
kill_tcp_relay_connection(tcp_c, tcp_connections_number);
return -1;
}
tcp_con->lock_count = 0;
tcp_con->sleep_count = 0;
tcp_con->connected_time = 0;
tcp_con->status = TCP_CONN_VALID;
tcp_con->unsleep = 0;
return 0;
}
/* Send a TCP routing request.
*
* return 0 on success.
@ -652,6 +805,9 @@ static int send_tcp_relay_routing_request(TCP_Connections *tcp_c, int tcp_connec
if (!tcp_con)
return -1;
if (tcp_con->status == TCP_CONN_SLEEPING)
return -1;
if (send_routing_request(tcp_con->connection, public_key) != 1)
return -1;
@ -704,11 +860,19 @@ static int tcp_status_callback(void *object, uint32_t number, uint8_t connection
return -1;
--tcp_con->lock_count;
if (con_to->status == TCP_CONN_SLEEPING) {
--tcp_con->sleep_count;
}
} else if (status == 2) {
if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_ONLINE, connection_id) == -1)
return -1;
++tcp_con->lock_count;
if (con_to->status == TCP_CONN_SLEEPING) {
++tcp_con->sleep_count;
}
}
return 0;
@ -906,6 +1070,10 @@ int add_tcp_number_relay_connection(TCP_Connections *tcp_c, int connections_numb
if (!tcp_con)
return -1;
if (con_to->status != TCP_CONN_SLEEPING && tcp_con->status == TCP_CONN_SLEEPING) {
tcp_con->unsleep = 1;
}
if (add_tcp_connection_to_conn(con_to, tcp_connections_number) == -1)
return -1;
@ -1012,23 +1180,35 @@ static void do_tcp_conns(TCP_Connections *tcp_c)
TCP_con *tcp_con = get_tcp_connection(tcp_c, i);
if (tcp_con) {
do_TCP_connection(tcp_con->connection);
if (tcp_con->status != TCP_CONN_SLEEPING) {
do_TCP_connection(tcp_con->connection);
/* callbacks can change TCP connection address. */
tcp_con = get_tcp_connection(tcp_c, i);
/* callbacks can change TCP connection address. */
tcp_con = get_tcp_connection(tcp_c, i);
if (tcp_con->connection->status == TCP_CLIENT_DISCONNECTED) {
if (tcp_con->status == TCP_CONN_CONNECTED) {
reconnect_tcp_relay_connection(tcp_c, i);
} else {
kill_tcp_relay_connection(tcp_c, i);
if (tcp_con->connection->status == TCP_CLIENT_DISCONNECTED) {
if (tcp_con->status == TCP_CONN_CONNECTED) {
reconnect_tcp_relay_connection(tcp_c, i);
} else {
kill_tcp_relay_connection(tcp_c, i);
}
continue;
}
continue;
if (tcp_con->status == TCP_CONN_VALID && tcp_con->connection->status == TCP_CLIENT_CONFIRMED) {
tcp_relay_on_online(tcp_c, i);
}
if (tcp_con->status == TCP_CONN_CONNECTED && !tcp_con->onion && tcp_con->lock_count
&& tcp_con->lock_count == tcp_con->sleep_count
&& is_timeout(tcp_con->connected_time, TCP_CONNECTION_ANNOUNCE_TIMEOUT)) {
sleep_tcp_relay_connection(tcp_c, i);
}
}
if (tcp_con->status == TCP_CONN_VALID && tcp_con->connection->status == TCP_CLIENT_CONFIRMED) {
tcp_relay_on_online(tcp_c, i);
if (tcp_con->status == TCP_CONN_SLEEPING && tcp_con->unsleep) {
unsleep_tcp_relay_connection(tcp_c, i);
}
}
}

View File

@ -28,8 +28,13 @@
#define TCP_CONN_NONE 0
#define TCP_CONN_VALID 1
/* NOTE: only used by TCP_con */
#define TCP_CONN_CONNECTED 2
/* Connection is not connected but can be quickly reconnected in case it is needed. */
#define TCP_CONN_SLEEPING 3
#define TCP_CONNECTIONS_STATUS_NONE 0
#define TCP_CONNECTIONS_STATUS_REGISTERED 1
#define TCP_CONNECTIONS_STATUS_ONLINE 2
@ -64,7 +69,13 @@ typedef struct {
TCP_Client_Connection *connection;
uint64_t connected_time;
uint32_t lock_count;
uint32_t sleep_count;
_Bool onion;
/* Only used when connection is sleeping. */
IP_Port ip_port;
uint8_t relay_pk[crypto_box_PUBLICKEYBYTES];
_Bool unsleep; /* set to 1 to unsleep connection. */
} TCP_con;
typedef struct {
@ -153,6 +164,18 @@ int new_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key, int
*/
int kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number);
/* Set connection status.
*
* status of 1 means we are using the connection.
* status of 0 means we are not using it.
*
* Unused tcp connections will be disconnected from but kept in case they are needed.
*
* return 0 on success.
* return -1 on failure.
*/
int set_tcp_connection_to_status(TCP_Connections *tcp_c, int connections_number, _Bool status);
/* Add a TCP relay tied to a connection.
*
* NOTE: This can only be used during the tcp_oob_callback.

View File

@ -1798,6 +1798,30 @@ static void do_tcp(Net_Crypto *c)
pthread_mutex_lock(&c->tcp_mutex);
do_tcp_connections(c->tcp_c);
pthread_mutex_unlock(&c->tcp_mutex);
uint32_t i;
for (i = 0; i < c->crypto_connections_length; ++i) {
Crypto_Connection *conn = get_crypto_connection(c, i);
if (conn == 0)
return;
if (conn->status == CRYPTO_CONN_ESTABLISHED) {
uint8_t direct_connected = 0;
crypto_connection_status(c, i, &direct_connected);
if (direct_connected) {
pthread_mutex_lock(&c->tcp_mutex);
set_tcp_connection_to_status(c->tcp_c, conn->connection_number_tcp, 0);
pthread_mutex_unlock(&c->tcp_mutex);
} else {
pthread_mutex_lock(&c->tcp_mutex);
set_tcp_connection_to_status(c->tcp_c, conn->connection_number_tcp, 1);
pthread_mutex_unlock(&c->tcp_mutex);
}
}
}
}
/* Set function to be called when connection with crypt_connection_id goes connects/disconnects.