summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--auto_tests/TCP_test.c1
-rw-r--r--auto_tests/onion_test.c89
-rw-r--r--configure.ac2
-rw-r--r--toxcore/Makefile.inc2
-rw-r--r--toxcore/Messenger.c4
-rw-r--r--toxcore/TCP_client.h6
-rw-r--r--toxcore/TCP_connection.c722
-rw-r--r--toxcore/TCP_connection.h88
-rw-r--r--toxcore/TCP_server.c4
-rw-r--r--toxcore/network.c11
-rw-r--r--toxcore/network.h7
-rw-r--r--toxcore/tox.c2
-rw-r--r--toxcore/tox.h4
13 files changed, 922 insertions, 20 deletions
diff --git a/auto_tests/TCP_test.c b/auto_tests/TCP_test.c
index e222cf01..a03baf92 100644
--- a/auto_tests/TCP_test.c
+++ b/auto_tests/TCP_test.c
@@ -419,6 +419,7 @@ START_TEST(test_client)
419 uint8_t f2_public_key[crypto_box_PUBLICKEYBYTES]; 419 uint8_t f2_public_key[crypto_box_PUBLICKEYBYTES];
420 uint8_t f2_secret_key[crypto_box_SECRETKEYBYTES]; 420 uint8_t f2_secret_key[crypto_box_SECRETKEYBYTES];
421 crypto_box_keypair(f2_public_key, f2_secret_key); 421 crypto_box_keypair(f2_public_key, f2_secret_key);
422 ip_port_tcp_s.port = htons(ports[rand() % NUM_PORTS]);
422 TCP_Client_Connection *conn2 = new_TCP_connection(ip_port_tcp_s, self_public_key, f2_public_key, f2_secret_key, 0); 423 TCP_Client_Connection *conn2 = new_TCP_connection(ip_port_tcp_s, self_public_key, f2_public_key, f2_secret_key, 0);
423 routing_response_handler(conn, response_callback, ((void *)conn) + 2); 424 routing_response_handler(conn, response_callback, ((void *)conn) + 2);
424 routing_status_handler(conn, status_callback, (void *)2); 425 routing_status_handler(conn, status_callback, (void *)2);
diff --git a/auto_tests/onion_test.c b/auto_tests/onion_test.c
index f27fefb8..31566471 100644
--- a/auto_tests/onion_test.c
+++ b/auto_tests/onion_test.c
@@ -275,7 +275,8 @@ Onions *new_onions(uint16_t port)
275 DHT *dht = new_DHT(new_networking(ip, port)); 275 DHT *dht = new_DHT(new_networking(ip, port));
276 on->onion = new_onion(dht); 276 on->onion = new_onion(dht);
277 on->onion_a = new_onion_announce(dht); 277 on->onion_a = new_onion_announce(dht);
278 on->onion_c = new_onion_client(new_net_crypto(dht, 0)); 278 TCP_Proxy_Info inf = {0};
279 on->onion_c = new_onion_client(new_net_crypto(dht, &inf));
279 280
280 if (on->onion && on->onion_a && on->onion_c) 281 if (on->onion && on->onion_a && on->onion_c)
281 return on; 282 return on;
@@ -294,15 +295,70 @@ void kill_onions(Onions *on)
294{ 295{
295 Networking_Core *net = on->onion->dht->net; 296 Networking_Core *net = on->onion->dht->net;
296 DHT *dht = on->onion->dht; 297 DHT *dht = on->onion->dht;
298 Net_Crypto *c = on->onion_c->c;
297 kill_onion_client(on->onion_c); 299 kill_onion_client(on->onion_c);
298 kill_onion_announce(on->onion_a); 300 kill_onion_announce(on->onion_a);
299 kill_onion(on->onion); 301 kill_onion(on->onion);
302 kill_net_crypto(c);
300 kill_DHT(dht); 303 kill_DHT(dht);
301 kill_networking(net); 304 kill_networking(net);
302 free(on); 305 free(on);
303} 306}
304 307
305#define NUM_ONIONS 50 308#define NUM_ONIONS 50
309#define NUM_FIRST 7
310#define NUM_LAST 37
311
312_Bool first_ip, last_ip;
313void dht_ip_callback(void *object, int32_t number, IP_Port ip_port)
314{
315 if (NUM_FIRST == number) {
316 first_ip = 1;
317 return;
318 }
319
320 if (NUM_LAST == number) {
321 last_ip = 1;
322 return;
323 }
324
325 ck_abort_msg("Error.");
326}
327
328_Bool first, last;
329uint8_t first_dht_pk[crypto_box_PUBLICKEYBYTES];
330uint8_t last_dht_pk[crypto_box_PUBLICKEYBYTES];
331
332static void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_public_key)
333{
334 Onions *on = object;
335 uint16_t count = 0;
336 int ret = DHT_addfriend(on->onion->dht, dht_public_key, &dht_ip_callback, object, number, &count);
337 ck_assert_msg(count == 1, "Count not 1");
338 ck_assert_msg(ret == 0, "DHT_addfriend() did not return 0");
339
340 if (NUM_FIRST == number && !first) {
341 first = 1;
342
343 if (memcmp(dht_public_key, last_dht_pk, crypto_box_PUBLICKEYBYTES) != 0) {
344 ck_abort_msg("Error wrong dht key.");
345 }
346
347 return;
348 }
349
350 if (NUM_LAST == number && !last) {
351 last = 1;
352
353 if (memcmp(dht_public_key, first_dht_pk, crypto_box_PUBLICKEYBYTES) != 0) {
354 ck_abort_msg("Error wrong dht key.");
355 }
356
357 return;
358 }
359
360 ck_abort_msg("Error.");
361}
306 362
307START_TEST(test_announce) 363START_TEST(test_announce)
308{ 364{
@@ -340,6 +396,8 @@ START_TEST(test_announce)
340 c_sleep(50); 396 c_sleep(50);
341 } 397 }
342 398
399 printf("connected\n");
400
343 for (i = 0; i < 25 * 2; ++i) { 401 for (i = 0; i < 25 * 2; ++i) {
344 for (j = 0; j < NUM_ONIONS; ++j) { 402 for (j = 0; j < NUM_ONIONS; ++j) {
345 do_onions(onions[j]); 403 do_onions(onions[j]);
@@ -348,37 +406,40 @@ START_TEST(test_announce)
348 c_sleep(50); 406 c_sleep(50);
349 } 407 }
350 408
351 onion_addfriend(onions[7]->onion_c, onions[37]->onion_c->c->self_public_key); 409 memcpy(first_dht_pk, onions[NUM_FIRST]->onion->dht->self_public_key, crypto_box_PUBLICKEYBYTES);
352 int frnum = onion_addfriend(onions[37]->onion_c, onions[7]->onion_c->c->self_public_key); 410 memcpy(last_dht_pk, onions[NUM_LAST]->onion->dht->self_public_key, crypto_box_PUBLICKEYBYTES);
411
412 printf("adding friend\n");
413 int frnum_f = onion_addfriend(onions[NUM_FIRST]->onion_c, onions[NUM_LAST]->onion_c->c->self_public_key);
414 int frnum = onion_addfriend(onions[NUM_LAST]->onion_c, onions[NUM_FIRST]->onion_c->c->self_public_key);
415
416 onion_dht_pk_callback(onions[NUM_FIRST]->onion_c, frnum_f, &dht_pk_callback, onions[NUM_FIRST], NUM_FIRST);
417 onion_dht_pk_callback(onions[NUM_LAST]->onion_c, frnum, &dht_pk_callback, onions[NUM_LAST], NUM_LAST);
353 418
354 int ok = -1; 419 int ok = -1;
355 420
356 IP_Port ip_port; 421 IP_Port ip_port;
357 422
358 while (ok == -1) { 423 while (!first || !last) {
359 for (i = 0; i < NUM_ONIONS; ++i) { 424 for (i = 0; i < NUM_ONIONS; ++i) {
360 networking_poll(onions[i]->onion->net); 425 do_onions(onions[i]);
361 do_onion_client(onions[i]->onion_c);
362 } 426 }
363 427
364 ok = onion_getfriendip(onions[37]->onion_c, frnum, &ip_port);
365
366 c_sleep(50); 428 c_sleep(50);
367 } 429 }
368 430
369 printf("id discovered\n"); 431 printf("Waiting for ips\n");
370 432
371 while (ok != 1) { 433 while (!first_ip || !last_ip) {
372 for (i = 0; i < NUM_ONIONS; ++i) { 434 for (i = 0; i < NUM_ONIONS; ++i) {
373 do_onions(onions[i]); 435 do_onions(onions[i]);
374 } 436 }
375 437
376 ok = onion_getfriendip(onions[37]->onion_c, frnum, &ip_port);
377
378 c_sleep(50); 438 c_sleep(50);
379 } 439 }
380 440
381 ck_assert_msg(ip_port.port == onions[7]->onion->net->port, "Port in returned ip not correct."); 441 onion_getfriendip(onions[NUM_LAST]->onion_c, frnum, &ip_port);
442 ck_assert_msg(ip_port.port == onions[NUM_FIRST]->onion->net->port, "Port in returned ip not correct.");
382 443
383 for (i = 0; i < NUM_ONIONS; ++i) { 444 for (i = 0; i < NUM_ONIONS; ++i) {
384 kill_onions(onions[i]); 445 kill_onions(onions[i]);
@@ -391,7 +452,7 @@ Suite *onion_suite(void)
391 Suite *s = suite_create("Onion"); 452 Suite *s = suite_create("Onion");
392 453
393 DEFTESTCASE_SLOW(basic, 5); 454 DEFTESTCASE_SLOW(basic, 5);
394 //DEFTESTCASE_SLOW(announce, 50); //TODO: fix test. 455 DEFTESTCASE_SLOW(announce, 70);
395 return s; 456 return s;
396} 457}
397 458
diff --git a/configure.ac b/configure.ac
index e43e8f78..a100f344 100644
--- a/configure.ac
+++ b/configure.ac
@@ -472,7 +472,7 @@ AC_C_BIGENDIAN
472# Checks for library functions. 472# Checks for library functions.
473AC_FUNC_FORK 473AC_FUNC_FORK
474AC_CHECK_FUNCS([gettimeofday memset socket strchr malloc]) 474AC_CHECK_FUNCS([gettimeofday memset socket strchr malloc])
475if (test "x$WIN32" != "xyes") && (test "x$MACH" != "xyes") && (test "x$DISABLE_RT" != "xyes"); then 475if (test "x$WIN32" != "xyes") && (test "x$MACH" != "xyes") && (test "x${host_os#*openbsd}" == "x$host_os") && (test "x$DISABLE_RT" != "xyes"); then
476 AC_CHECK_LIB(rt, clock_gettime, 476 AC_CHECK_LIB(rt, clock_gettime,
477 [ 477 [
478 RT_LIBS="-lrt" 478 RT_LIBS="-lrt"
diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc
index 9afe7791..9fb910fc 100644
--- a/toxcore/Makefile.inc
+++ b/toxcore/Makefile.inc
@@ -46,6 +46,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \
46 ../toxcore/TCP_client.c \ 46 ../toxcore/TCP_client.c \
47 ../toxcore/TCP_server.h \ 47 ../toxcore/TCP_server.h \
48 ../toxcore/TCP_server.c \ 48 ../toxcore/TCP_server.c \
49 ../toxcore/TCP_connection.h \
50 ../toxcore/TCP_connection.c \
49 ../toxcore/list.c \ 51 ../toxcore/list.c \
50 ../toxcore/list.h \ 52 ../toxcore/list.h \
51 ../toxcore/misc_tools.h 53 ../toxcore/misc_tools.h
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
index 23c41120..fefc3b17 100644
--- a/toxcore/Messenger.c
+++ b/toxcore/Messenger.c
@@ -172,7 +172,7 @@ static int send_online_packet(Messenger *m, int32_t friendnumber)
172 m->friendlist[friendnumber].friendcon_id), &packet, sizeof(packet), 0) != -1; 172 m->friendlist[friendnumber].friendcon_id), &packet, sizeof(packet), 0) != -1;
173} 173}
174 174
175static int send_offine_packet(Messenger *m, int friendcon_id) 175static int send_offline_packet(Messenger *m, int friendcon_id)
176{ 176{
177 uint8_t packet = PACKET_ID_OFFLINE; 177 uint8_t packet = PACKET_ID_OFFLINE;
178 return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, friendcon_id), &packet, 178 return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, friendcon_id), &packet,
@@ -408,7 +408,7 @@ int m_delfriend(Messenger *m, int32_t friendnumber)
408 kill_friend_connection(m->fr_c, m->friendlist[friendnumber].friendcon_id); 408 kill_friend_connection(m->fr_c, m->friendlist[friendnumber].friendcon_id);
409 409
410 if (friend_con_connected(m->fr_c, m->friendlist[friendnumber].friendcon_id) == FRIENDCONN_STATUS_CONNECTED) { 410 if (friend_con_connected(m->fr_c, m->friendlist[friendnumber].friendcon_id) == FRIENDCONN_STATUS_CONNECTED) {
411 send_offine_packet(m, m->friendlist[friendnumber].friendcon_id); 411 send_offline_packet(m, m->friendlist[friendnumber].friendcon_id);
412 } 412 }
413 413
414 memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); 414 memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend));
diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h
index e37a4ee0..d4d18a4b 100644
--- a/toxcore/TCP_client.h
+++ b/toxcore/TCP_client.h
@@ -78,8 +78,10 @@ typedef struct {
78 uint64_t ping_response_id; 78 uint64_t ping_response_id;
79 uint64_t ping_request_id; 79 uint64_t ping_request_id;
80 80
81 //TODO: remove
81 void *net_crypto_pointer; 82 void *net_crypto_pointer;
82 uint32_t net_crypto_location; 83 uint32_t net_crypto_location;
84
83 struct { 85 struct {
84 uint8_t status; /* 0 if not used, 1 if other is offline, 2 if other is online. */ 86 uint8_t status; /* 0 if not used, 1 if other is offline, 2 if other is online. */
85 uint8_t public_key[crypto_box_PUBLICKEYBYTES]; 87 uint8_t public_key[crypto_box_PUBLICKEYBYTES];
@@ -96,6 +98,10 @@ typedef struct {
96 98
97 int (*onion_callback)(void *object, const uint8_t *data, uint16_t length); 99 int (*onion_callback)(void *object, const uint8_t *data, uint16_t length);
98 void *onion_callback_object; 100 void *onion_callback_object;
101
102 /* Can be used by user. */
103 void *custom_object;
104 uint32_t custom_uint;
99} TCP_Client_Connection; 105} TCP_Client_Connection;
100 106
101/* Create new TCP connection to ip_port/public_key 107/* Create new TCP connection to ip_port/public_key
diff --git a/toxcore/TCP_connection.c b/toxcore/TCP_connection.c
new file mode 100644
index 00000000..ddcbd1d8
--- /dev/null
+++ b/toxcore/TCP_connection.c
@@ -0,0 +1,722 @@
1/* TCP_connection.c
2 *
3 * Handles TCP relay connections between two Tox clients.
4 *
5 * Copyright (C) 2015 Tox project All Rights Reserved.
6 *
7 * This file is part of Tox.
8 *
9 * Tox is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Tox is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "TCP_connection.h"
29
30/* Set the size of the array to num.
31 *
32 * return -1 if realloc fails.
33 * return 0 if it succeeds.
34 */
35#define realloc_tox_array(array, element_size, num, temp_pointer) (num ? (temp_pointer = realloc(array, num * element_size), temp_pointer ? (array = temp_pointer, 0) : (-1) ) : (free(array), array = NULL, 0))
36
37
38/* return 1 if the connections_number is not valid.
39 * return 0 if the connections_number is valid.
40 */
41static _Bool connections_number_not_valid(const TCP_Connections *tcp_c, int connections_number)
42{
43 if ((unsigned int)connections_number >= tcp_c->connections_length)
44 return 1;
45
46 if (tcp_c->connections == NULL)
47 return 1;
48
49 if (tcp_c->connections[connections_number].status == TCP_CONN_NONE)
50 return 1;
51
52 return 0;
53}
54
55/* return 1 if the tcp_connections_number is not valid.
56 * return 0 if the tcp_connections_number is valid.
57 */
58static _Bool tcp_connections_number_not_valid(const TCP_Connections *tcp_c, int tcp_connections_number)
59{
60 if ((unsigned int)tcp_connections_number >= tcp_c->tcp_connections_length)
61 return 1;
62
63 if (tcp_c->tcp_connections == NULL)
64 return 1;
65
66 if (tcp_c->tcp_connections[tcp_connections_number].status == TCP_CONN_NONE)
67 return 1;
68
69 return 0;
70}
71
72/* Create a new empty connection.
73 *
74 * return -1 on failure.
75 * return connections_number on success.
76 */
77static int create_connection(TCP_Connections *tcp_c)
78{
79 uint32_t i;
80
81 for (i = 0; i < tcp_c->connections_length; ++i) {
82 if (tcp_c->connections[i].status == TCP_CONN_NONE)
83 return i;
84 }
85
86 int id = -1;
87
88 TCP_Connection_to *temp_pointer;
89
90 if (realloc_tox_array(tcp_c->connections, sizeof(TCP_Connection_to), tcp_c->connections_length + 1,
91 temp_pointer) == 0) {
92 id = tcp_c->connections_length;
93 ++tcp_c->connections_length;
94 memset(&(tcp_c->connections[id]), 0, sizeof(TCP_Connection_to));
95 }
96
97 return id;
98}
99
100/* Create a new empty tcp connection.
101 *
102 * return -1 on failure.
103 * return tcp_connections_number on success.
104 */
105static int create_tcp_connection(TCP_Connections *tcp_c)
106{
107 uint32_t i;
108
109 for (i = 0; i < tcp_c->tcp_connections_length; ++i) {
110 if (tcp_c->tcp_connections[i].status == TCP_CONN_NONE)
111 return i;
112 }
113
114 int id = -1;
115
116 TCP_con *temp_pointer;
117
118 if (realloc_tox_array(tcp_c->tcp_connections, sizeof(TCP_con), tcp_c->tcp_connections_length + 1, temp_pointer) == 0) {
119 id = tcp_c->tcp_connections_length;
120 ++tcp_c->tcp_connections_length;
121 memset(&(tcp_c->tcp_connections[id]), 0, sizeof(TCP_con));
122 }
123
124 return id;
125}
126
127/* Wipe a connection.
128 *
129 * return -1 on failure.
130 * return 0 on success.
131 */
132static int wipe_connection(TCP_Connections *tcp_c, int connections_number)
133{
134 if (connections_number_not_valid(tcp_c, connections_number))
135 return -1;
136
137 uint32_t i;
138 memset(&(tcp_c->connections[connections_number]), 0 , sizeof(TCP_Connection_to));
139
140 for (i = tcp_c->connections_length; i != 0; --i) {
141 if (tcp_c->connections[i - 1].status != TCP_CONN_NONE)
142 break;
143 }
144
145 if (tcp_c->connections_length != i) {
146 tcp_c->connections_length = i;
147 TCP_Connection_to *temp_pointer;
148 realloc_tox_array(tcp_c->connections, sizeof(TCP_Connection_to), tcp_c->connections_length, temp_pointer);
149 }
150
151 return 0;
152}
153
154/* Wipe a connection.
155 *
156 * return -1 on failure.
157 * return 0 on success.
158 */
159static int wipe_tcp_connection(TCP_Connections *tcp_c, int tcp_connections_number)
160{
161 if (tcp_connections_number_not_valid(tcp_c, tcp_connections_number))
162 return -1;
163
164 uint32_t i;
165 memset(&(tcp_c->tcp_connections[tcp_connections_number]), 0 , sizeof(TCP_con));
166
167 for (i = tcp_c->tcp_connections_length; i != 0; --i) {
168 if (tcp_c->tcp_connections[i - 1].status != TCP_CONN_NONE)
169 break;
170 }
171
172 if (tcp_c->tcp_connections_length != i) {
173 tcp_c->tcp_connections_length = i;
174 TCP_con *temp_pointer;
175 realloc_tox_array(tcp_c->tcp_connections, sizeof(TCP_con), tcp_c->tcp_connections_length, temp_pointer);
176 }
177
178 return 0;
179}
180
181static TCP_Connection_to *get_connection(const TCP_Connections *tcp_c, int connections_number)
182{
183 if (connections_number_not_valid(tcp_c, connections_number))
184 return 0;
185
186 return &tcp_c->connections[connections_number];
187}
188
189static TCP_con *get_tcp_connection(const TCP_Connections *tcp_c, int tcp_connections_number)
190{
191 if (tcp_connections_number_not_valid(tcp_c, tcp_connections_number))
192 return 0;
193
194 return &tcp_c->tcp_connections[tcp_connections_number];
195}
196
197/* Send a packet to the TCP connection.
198 *
199 * return -1 on failure.
200 * return 0 on success.
201 */
202int send_packet_tcp_connection(TCP_Connections *tcp_c, int connections_number, uint8_t *packet, uint16_t length)
203{
204 TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);
205
206 if (!con_to) {
207 return -1;
208 }
209
210 unsigned int i;
211 int ret = -1;
212
213 for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
214 uint32_t tcp_con_num = con_to->connections[i].tcp_connection;
215
216 //TODO
217 if (tcp_con_num) {
218 tcp_con_num -= 1;
219 TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_con_num);
220
221 if (!tcp_con) {
222 continue;
223 }
224
225 // ret = send_data(c->tcp_connections[tcp_index], conn->con_number_tcp[tcp_index], packet, length);
226 }
227 }
228
229 return ret;
230}
231
232void set_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_data_callback)(void *object, int id,
233 const uint8_t *data, uint16_t length), void *object)
234{
235 tcp_c->tcp_data_callback = tcp_data_callback;
236 tcp_c->tcp_data_callback_object = object;
237}
238
239/* Find the TCP connection with public_key.
240 *
241 * return connections_number on success.
242 * return -1 on failure.
243 */
244static int find_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key)
245{
246 unsigned int i;
247
248 for (i = 0; i < tcp_c->connections_length; ++i) {
249 TCP_Connection_to *con_to = get_connection(tcp_c, i);
250
251 if (con_to) {
252 if (memcmp(con_to->public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) {
253 return i;
254 }
255 }
256 }
257
258 return -1;
259}
260
261/* Find the TCP connection to a relay with relay_pk.
262 *
263 * return connections_number on success.
264 * return -1 on failure.
265 */
266static int find_tcp_connection_relay(TCP_Connections *tcp_c, const uint8_t *relay_pk)
267{
268 unsigned int i;
269
270 for (i = 0; i < tcp_c->tcp_connections_length; ++i) {
271 TCP_con *tcp_con = get_tcp_connection(tcp_c, i);
272
273 if (tcp_con) {
274 if (memcmp(tcp_con->connection->public_key, relay_pk, crypto_box_PUBLICKEYBYTES) == 0) {
275 return i;
276 }
277 }
278 }
279
280 return -1;
281}
282
283/* Create a new TCP connection to public_key.
284 *
285 * id is the id in the callbacks for that connection.
286 *
287 * return connections_number on success.
288 * return -1 on failure.
289 */
290int new_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key, int id)
291{
292 if (find_tcp_connection_to(tcp_c, public_key) != -1)
293 return -1;
294
295 int connections_number = create_connection(tcp_c);
296
297 if (connections_number == -1)
298 return -1;
299
300 TCP_Connection_to *con_to = &tcp_c->connections[connections_number];
301
302 con_to->status = TCP_CONN_VALID;
303 memcpy(con_to->public_key, public_key, crypto_box_PUBLICKEYBYTES);
304 con_to->id = id;
305
306 return connections_number;
307}
308
309/* return 0 on success.
310 * return -1 on failure.
311 */
312int kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number)
313{
314 TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);
315
316 if (!con_to)
317 return -1;
318
319 //TODO
320 return wipe_connection(tcp_c, connections_number);
321}
322
323static _Bool tcp_connection_in_conn(TCP_Connection_to *con_to, int tcp_connections_number)
324{
325 unsigned int i;
326
327 for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
328 if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) {
329 return 1;
330 }
331 }
332
333 return 0;
334}
335
336/* return index on success.
337 * return -1 on failure.
338 */
339static int add_tcp_connection_to_conn(TCP_Connection_to *con_to, int tcp_connections_number)
340{
341 unsigned int i;
342
343 if (tcp_connection_in_conn(con_to, tcp_connections_number))
344 return -1;
345
346 for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
347 if (con_to->connections[i].tcp_connection == 0) {
348 con_to->connections[i].tcp_connection = tcp_connections_number + 1;
349 con_to->connections[i].status = TCP_CONNECTIONS_STATUS_NONE;
350 con_to->connections[i].connection_id = 0;
351 return i;
352 }
353 }
354
355 return -1;
356}
357
358/* return index on success.
359 * return -1 on failure.
360 */
361static int rm_tcp_connection_from_conn(TCP_Connection_to *con_to, int tcp_connections_number)
362{
363 unsigned int i;
364
365 for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
366 if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) {
367 con_to->connections[i].tcp_connection = 0;
368 con_to->connections[i].status = TCP_CONNECTIONS_STATUS_NONE;
369 con_to->connections[i].connection_id = 0;
370 return i;
371 }
372 }
373
374 return -1;
375}
376
377/* return index on success.
378 * return -1 on failure.
379 */
380static int set_tcp_connection_status(TCP_Connection_to *con_to, int tcp_connections_number, unsigned int status,
381 uint8_t connection_id)
382{
383 unsigned int i;
384
385 for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {
386 if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) {
387 con_to->connections[i].status = status;
388 con_to->connections[i].connection_id = connection_id;
389 return i;
390 }
391 }
392
393 return -1;
394}
395
396/* Kill a TCP relay connection.
397 *
398 * return 0 on success.
399 * return -1 on failure.
400 */
401static int kill_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number)
402{
403 TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
404
405 if (!tcp_con)
406 return -1;
407
408 unsigned int i;
409
410 for (i = 0; i < tcp_c->connections_length; ++i) {
411 TCP_Connection_to *con_to = get_connection(tcp_c, i);
412
413 if (con_to) {
414 rm_tcp_connection_from_conn(con_to, tcp_connections_number);
415 }
416 }
417
418 kill_TCP_connection(tcp_con->connection);
419
420 return wipe_tcp_connection(tcp_c, tcp_connections_number);
421}
422
423/* Send a TCP routing request.
424 *
425 * return 0 on success.
426 * return -1 on failure.
427 */
428static int send_tcp_relay_routing_request(TCP_Connections *tcp_c, int tcp_connections_number, uint8_t *public_key)
429{
430 TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
431
432 if (!tcp_con)
433 return -1;
434
435 if (send_routing_request(tcp_con->connection, public_key) != 1)
436 return -1;
437
438 return 0;
439}
440
441static int tcp_response_callback(void *object, uint8_t connection_id, const uint8_t *public_key)
442{
443 TCP_Client_Connection *TCP_client_con = object;
444 TCP_Connections *tcp_c = TCP_client_con->custom_object;
445
446 unsigned int tcp_connections_number = TCP_client_con->custom_uint;
447 TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
448
449 if (!tcp_con)
450 return -1;
451
452 int connections_number = find_tcp_connection_to(tcp_c, public_key);
453
454 if (connections_number == -1)
455 return -1;
456
457 set_tcp_connection_number(tcp_con->connection, connection_id, connections_number);
458
459 TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);
460
461 if (con_to == NULL)
462 return -1;
463
464 if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_REGISTERED, connection_id) == -1)
465 return -1;
466
467 return 0;
468}
469
470static int tcp_status_callback(void *object, uint32_t number, uint8_t connection_id, uint8_t status)
471{
472 TCP_Client_Connection *TCP_client_con = object;
473 TCP_Connections *tcp_c = TCP_client_con->custom_object;
474
475 unsigned int tcp_connections_number = TCP_client_con->custom_uint;
476 TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
477 TCP_Connection_to *con_to = get_connection(tcp_c, number);
478
479 if (!con_to || !tcp_con)
480 return -1;
481
482 if (status == 1) {
483 if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_REGISTERED, connection_id) == -1)
484 return -1;
485
486 } else if (status == 2) {
487 if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_ONLINE, connection_id) == -1)
488 return -1;
489
490 }
491
492 return 0;
493}
494
495static int tcp_data_callback(void *object, uint32_t number, uint8_t connection_id, const uint8_t *data, uint16_t length)
496{
497
498 if (length == 0)
499 return -1;
500
501 TCP_Client_Connection *TCP_client_con = object;
502 TCP_Connections *tcp_c = TCP_client_con->custom_object;
503
504 unsigned int tcp_connections_number = TCP_client_con->custom_uint;
505 TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
506
507 if (!tcp_con)
508 return -1;
509
510 TCP_Connection_to *con_to = get_connection(tcp_c, number);
511
512 if (!con_to)
513 return -1;
514
515 if (tcp_c->tcp_data_callback)
516 tcp_c->tcp_data_callback(tcp_c->tcp_data_callback_object, con_to->id, data, length);
517
518 return 0;
519}
520
521static int tcp_oob_callback(void *object, const uint8_t *public_key, const uint8_t *data, uint16_t length)
522{
523 if (length == 0)
524 return -1;
525
526 TCP_Client_Connection *TCP_client_con = object;
527 TCP_Connections *tcp_c = TCP_client_con->custom_object;
528
529 unsigned int tcp_connections_number = TCP_client_con->custom_uint;
530 TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
531
532 if (!tcp_con)
533 return -1;
534
535 uint8_t relay_pk[crypto_box_PUBLICKEYBYTES];
536 memcpy(relay_pk, tcp_con->connection->public_key, crypto_box_PUBLICKEYBYTES);
537
538 if (tcp_c->tcp_oob_callback)
539 tcp_c->tcp_oob_callback(tcp_c->tcp_oob_callback_object, public_key, relay_pk, data, length);
540
541 return 0;
542}
543
544static int tcp_onion_callback(void *object, const uint8_t *data, uint16_t length)
545{
546 TCP_Connections *tcp_c = object;
547
548 if (tcp_c->tcp_onion_callback)
549 tcp_c->tcp_onion_callback(tcp_c->tcp_onion_callback_object, data, length);
550
551 return 0;
552}
553
554/* Set callbacks for the TCP relay connection.
555 *
556 * return 0 on success.
557 * return -1 on failure.
558 */
559static int tcp_relay_set_callbacks(TCP_Connections *tcp_c, int tcp_connections_number)
560{
561 TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
562
563 if (!tcp_con)
564 return -1;
565
566 TCP_Client_Connection *con = tcp_con->connection;
567
568 con->custom_object = tcp_c;
569 con->custom_uint = tcp_connections_number;
570 onion_response_handler(con, &tcp_onion_callback, tcp_c);
571 routing_response_handler(con, &tcp_response_callback, con);
572 routing_status_handler(con, &tcp_status_callback, con);
573 routing_data_handler(con, &tcp_data_callback, con);
574 oob_data_handler(con, &tcp_oob_callback, con);
575
576 return 0;
577}
578
579static int tcp_relay_on_online(TCP_Connections *tcp_c, int tcp_connections_number)
580{
581 TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
582
583 if (!tcp_con)
584 return -1;
585
586 unsigned int i;
587
588 for (i = 0; i < tcp_c->connections_length; ++i) {
589 TCP_Connection_to *con_to = get_connection(tcp_c, i);
590
591 if (con_to) {
592 if (tcp_connection_in_conn(con_to, tcp_connections_number)) {
593 send_tcp_relay_routing_request(tcp_c, tcp_connections_number, con_to->public_key);
594 }
595 }
596 }
597
598 tcp_relay_set_callbacks(tcp_c, tcp_connections_number);
599 tcp_con->status = TCP_CONN_CONNECTED;
600 return 0;
601}
602
603static int add_tcp_relay(TCP_Connections *tcp_c, IP_Port ip_port, const uint8_t *relay_pk)
604{
605 int tcp_connections_number = create_tcp_connection(tcp_c);
606
607 if (tcp_connections_number == -1)
608 return -1;
609
610 TCP_con *tcp_con = &tcp_c->tcp_connections[tcp_connections_number];
611
612
613 tcp_con->connection = new_TCP_connection(ip_port, relay_pk, tcp_c->dht->self_public_key, tcp_c->dht->self_secret_key,
614 &tcp_c->proxy_info);
615
616 if (!tcp_con->connection)
617 return -1;
618
619 tcp_con->status = TCP_CONN_VALID;
620
621 return tcp_connections_number;
622}
623
624/* Add a TCP relay tied to a connection.
625 *
626 * return 0 on success.
627 * return -1 on failure.
628 */
629int add_tcp_relay_connection(TCP_Connections *tcp_c, int connections_number, IP_Port ip_port, const uint8_t *relay_pk)
630{
631 TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);
632
633 if (!con_to)
634 return -1;
635
636 int tcp_connections_number = find_tcp_connection_relay(tcp_c, relay_pk);
637
638 if (tcp_connections_number != -1) {
639 if (add_tcp_connection_to_conn(con_to, tcp_connections_number) == -1)
640 return -1;
641
642 TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
643
644 if (!tcp_con)
645 return -1;
646
647 ++tcp_con->lock_count;
648
649 if (tcp_con->status == TCP_CONN_CONNECTED) {
650 send_tcp_relay_routing_request(tcp_c, tcp_connections_number, con_to->public_key);
651 }
652
653 return 0;
654 } else {
655 int tcp_connections_number = add_tcp_relay(tcp_c, ip_port, relay_pk);
656
657 if (add_tcp_connection_to_conn(con_to, tcp_connections_number) == -1) {
658 return -1;
659 }
660
661 TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);
662
663 if (!tcp_con)
664 return -1;
665
666 ++tcp_con->lock_count;
667 return 0;
668 }
669}
670
671
672TCP_Connections *new_tcp_connections(DHT *dht)
673{
674 if (dht == NULL)
675 return NULL;
676
677 TCP_Connections *temp = calloc(1, sizeof(TCP_Connections));
678
679 if (temp == NULL)
680 return NULL;
681
682 temp->dht = dht;
683 return temp;
684}
685
686static void do_tcp_conns(TCP_Connections *tcp_c)
687{
688 unsigned int i;
689
690 for (i = 0; i < tcp_c->tcp_connections_length; ++i) {
691 TCP_con *tcp_con = get_tcp_connection(tcp_c, i);
692
693 if (tcp_con) {
694 do_TCP_connection(tcp_con->connection);
695
696 if (tcp_con->connection->status == TCP_CLIENT_DISCONNECTED) {
697 kill_tcp_relay_connection(tcp_c, i);
698 continue;
699 }
700
701 if (tcp_con->status == TCP_CONN_VALID && tcp_con->connection->status == TCP_CLIENT_CONFIRMED) {
702 tcp_relay_on_online(tcp_c, i);
703 }
704 }
705 }
706}
707
708
709void do_tcp_connections(TCP_Connections *tcp_c)
710{
711//TODO kill unused conns
712
713 do_tcp_conns(tcp_c);
714}
715
716void kill_tcp_connections(TCP_Connections *tcp_c)
717{
718 //TODO
719 free(tcp_c);
720}
721
722
diff --git a/toxcore/TCP_connection.h b/toxcore/TCP_connection.h
new file mode 100644
index 00000000..94213814
--- /dev/null
+++ b/toxcore/TCP_connection.h
@@ -0,0 +1,88 @@
1/* TCP_connection.h
2 *
3 * Handles TCP relay connections between two Tox clients.
4 *
5 * Copyright (C) 2015 Tox project All Rights Reserved.
6 *
7 * This file is part of Tox.
8 *
9 * Tox is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Tox is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#ifndef TCP_CONNECTION_H
25#define TCP_CONNECTION_H
26
27#include "TCP_client.h"
28
29#define TCP_CONN_NONE 0
30#define TCP_CONN_VALID 1
31#define TCP_CONN_CONNECTED 2
32
33#define TCP_CONNECTIONS_STATUS_NONE 0
34#define TCP_CONNECTIONS_STATUS_REGISTERED 1
35#define TCP_CONNECTIONS_STATUS_ONLINE 2
36
37#define MAX_FRIEND_TCP_CONNECTIONS 4
38
39
40typedef struct {
41 uint8_t status;
42 uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer */
43
44 struct {
45 uint32_t tcp_connection;
46 unsigned int status;
47 unsigned int connection_id;
48 } connections[MAX_FRIEND_TCP_CONNECTIONS];
49
50 int id; /* id used in callbacks. */
51} TCP_Connection_to;
52
53typedef struct {
54 uint8_t status;
55 TCP_Client_Connection *connection;
56 uint32_t lock_count;
57} TCP_con;
58
59typedef struct {
60 DHT *dht;
61
62 TCP_Connection_to *connections;
63 uint32_t connections_length; /* Length of connections array. */
64
65 TCP_con *tcp_connections;
66 uint32_t tcp_connections_length; /* Length of tcp_connections array. */
67
68 int (*tcp_data_callback)(void *object, int id, const uint8_t *data, uint16_t length);
69 void *tcp_data_callback_object;
70
71 int (*tcp_oob_callback)(void *object, const uint8_t *public_key, const uint8_t *relay_pk, const uint8_t *data,
72 uint16_t length);
73 void *tcp_oob_callback_object;
74
75 int (*tcp_onion_callback)(void *object, const uint8_t *data, uint16_t length);
76 void *tcp_onion_callback_object;
77
78 TCP_Proxy_Info proxy_info;
79} TCP_Connections;
80
81
82
83TCP_Connections *new_tcp_connections(DHT *dht);
84void do_tcp_connections(TCP_Connections *tcp_c);
85void kill_tcp_connections(TCP_Connections *tcp_c);
86
87#endif
88
diff --git a/toxcore/TCP_server.c b/toxcore/TCP_server.c
index d7401de8..f07df2c6 100644
--- a/toxcore/TCP_server.c
+++ b/toxcore/TCP_server.c
@@ -925,6 +925,10 @@ static sock_t new_listening_TCP_socket(int family, uint16_t port)
925 ok = set_socket_dualstack(sock); 925 ok = set_socket_dualstack(sock);
926 } 926 }
927 927
928 if (ok) {
929 ok = set_socket_reuseaddr(sock);
930 }
931
928 ok = ok && bind_to_port(sock, family, port) && (listen(sock, TCP_MAX_BACKLOG) == 0); 932 ok = ok && bind_to_port(sock, family, port) && (listen(sock, TCP_MAX_BACKLOG) == 0);
929 933
930 if (!ok) { 934 if (!ok) {
diff --git a/toxcore/network.c b/toxcore/network.c
index d974ddc2..b3df3fbd 100644
--- a/toxcore/network.c
+++ b/toxcore/network.c
@@ -172,6 +172,17 @@ int set_socket_nosigpipe(sock_t sock)
172#endif 172#endif
173} 173}
174 174
175/* Enable SO_REUSEADDR on socket.
176 *
177 * return 1 on success
178 * return 0 on failure
179 */
180int set_socket_reuseaddr(sock_t sock)
181{
182 int set = 1;
183 return (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set)) == 0);
184}
185
175/* Set socket to dual (IPv4 + IPv6 socket) 186/* Set socket to dual (IPv4 + IPv6 socket)
176 * 187 *
177 * return 1 on success 188 * return 1 on success
diff --git a/toxcore/network.h b/toxcore/network.h
index c67f523d..b06c0f6a 100644
--- a/toxcore/network.h
+++ b/toxcore/network.h
@@ -334,6 +334,13 @@ int set_socket_nonblock(sock_t sock);
334 */ 334 */
335int set_socket_nosigpipe(sock_t sock); 335int set_socket_nosigpipe(sock_t sock);
336 336
337/* Enable SO_REUSEADDR on socket.
338 *
339 * return 1 on success
340 * return 0 on failure
341 */
342int set_socket_reuseaddr(sock_t sock);
343
337/* Set socket to dual (IPv4 + IPv6 socket) 344/* Set socket to dual (IPv4 + IPv6 socket)
338 * 345 *
339 * return 1 on success 346 * return 1 on success
diff --git a/toxcore/tox.c b/toxcore/tox.c
index a9306efc..848f81c7 100644
--- a/toxcore/tox.c
+++ b/toxcore/tox.c
@@ -851,7 +851,7 @@ void tox_callback_friend_message(Tox *tox, tox_friend_message_cb *function, void
851 851
852bool tox_hash(uint8_t *hash, const uint8_t *data, size_t length) 852bool tox_hash(uint8_t *hash, const uint8_t *data, size_t length)
853{ 853{
854 if (!hash || !data) { 854 if (!hash || (length && !data)) {
855 return 0; 855 return 0;
856 } 856 }
857 857
diff --git a/toxcore/tox.h b/toxcore/tox.h
index 034b1d78..8e368851 100644
--- a/toxcore/tox.h
+++ b/toxcore/tox.h
@@ -1418,8 +1418,8 @@ enum TOX_FILE_KIND {
1418 * primarily for validating cached avatars. This use is highly recommended to 1418 * primarily for validating cached avatars. This use is highly recommended to
1419 * avoid unnecessary avatar updates. 1419 * avoid unnecessary avatar updates.
1420 * 1420 *
1421 * If length is zero or data is NULL, the hash will contain all zero. If hash is 1421 * If hash is NULL or data is NULL while length is not 0 the function returns false,
1422 * NULL, the function returns false, otherwise it returns true. 1422 * otherwise it returns true.
1423 * 1423 *
1424 * This function is a wrapper to internal message-digest functions. 1424 * This function is a wrapper to internal message-digest functions.
1425 * 1425 *