summaryrefslogtreecommitdiff
path: root/toxcore/TCP_connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxcore/TCP_connection.c')
-rw-r--r--toxcore/TCP_connection.c722
1 files changed, 722 insertions, 0 deletions
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