summaryrefslogtreecommitdiff
path: root/toxcore/TCP_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxcore/TCP_client.c')
-rw-r--r--toxcore/TCP_client.c398
1 files changed, 392 insertions, 6 deletions
diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c
index 437429b9..e4845852 100644
--- a/toxcore/TCP_client.c
+++ b/toxcore/TCP_client.c
@@ -20,6 +20,9 @@
20* 20*
21*/ 21*/
22 22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
23 26
24#include "TCP_client.h" 27#include "TCP_client.h"
25 28
@@ -71,8 +74,8 @@ static int generate_handshake(TCP_Client_Connection *TCP_conn, uint8_t *self_pub
71 memcpy(plain + crypto_box_PUBLICKEYBYTES, TCP_conn->sent_nonce, crypto_box_NONCEBYTES); 74 memcpy(plain + crypto_box_PUBLICKEYBYTES, TCP_conn->sent_nonce, crypto_box_NONCEBYTES);
72 memcpy(TCP_conn->last_packet, self_public_key, crypto_box_PUBLICKEYBYTES); 75 memcpy(TCP_conn->last_packet, self_public_key, crypto_box_PUBLICKEYBYTES);
73 new_nonce(TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES); 76 new_nonce(TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES);
74 int len = encrypt_data_fast(TCP_conn->shared_key, TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES, plain, 77 int len = encrypt_data_symmetric(TCP_conn->shared_key, TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES, plain,
75 sizeof(plain), TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); 78 sizeof(plain), TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
76 79
77 if (len != sizeof(plain) + crypto_box_MACBYTES) 80 if (len != sizeof(plain) + crypto_box_MACBYTES)
78 return -1; 81 return -1;
@@ -90,8 +93,8 @@ static int generate_handshake(TCP_Client_Connection *TCP_conn, uint8_t *self_pub
90static int handle_handshake(TCP_Client_Connection *TCP_conn, uint8_t *data) 93static int handle_handshake(TCP_Client_Connection *TCP_conn, uint8_t *data)
91{ 94{
92 uint8_t plain[crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES]; 95 uint8_t plain[crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES];
93 int len = decrypt_data_fast(TCP_conn->shared_key, data, data + crypto_box_NONCEBYTES, 96 int len = decrypt_data_symmetric(TCP_conn->shared_key, data, data + crypto_box_NONCEBYTES,
94 TCP_SERVER_HANDSHAKE_SIZE - crypto_box_NONCEBYTES, plain); 97 TCP_SERVER_HANDSHAKE_SIZE - crypto_box_NONCEBYTES, plain);
95 98
96 if (len != sizeof(plain)) 99 if (len != sizeof(plain))
97 return -1; 100 return -1;
@@ -130,6 +133,206 @@ static int send_pending_data(TCP_Client_Connection *con)
130 return -1; 133 return -1;
131} 134}
132 135
136/* return 1 on success.
137 * return 0 if could not send packet.
138 * return -1 on failure (connection must be killed).
139 */
140static int write_packet_TCP_secure_connection(TCP_Client_Connection *con, uint8_t *data, uint16_t length)
141{
142 if (length + crypto_box_MACBYTES > MAX_PACKET_SIZE)
143 return -1;
144
145 if (send_pending_data(con) == -1)
146 return 0;
147
148 uint8_t packet[sizeof(uint16_t) + length + crypto_box_MACBYTES];
149
150 uint16_t c_length = htons(length + crypto_box_MACBYTES);
151 memcpy(packet, &c_length, sizeof(uint16_t));
152 int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));
153
154 if ((unsigned int)len != (sizeof(packet) - sizeof(uint16_t)))
155 return -1;
156
157 increment_nonce(con->sent_nonce);
158
159 len = send(con->sock, packet, sizeof(packet), MSG_NOSIGNAL);
160
161 if ((unsigned int)len == sizeof(packet))
162 return 1;
163
164 if (len <= 0)
165 return 0;
166
167 memcpy(con->last_packet, packet, length);
168 con->last_packet_length = sizeof(packet);
169 con->last_packet_sent = len;
170 return 1;
171}
172
173/* return 1 on success.
174 * return 0 if could not send packet.
175 * return -1 on failure (connection must be killed).
176 */
177int send_routing_request(TCP_Client_Connection *con, uint8_t *public_key)
178{
179 uint8_t packet[1 + crypto_box_PUBLICKEYBYTES];
180 packet[0] = TCP_PACKET_ROUTING_REQUEST;
181 memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES);
182 return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
183}
184
185void routing_response_handler(TCP_Client_Connection *con, int (*response_callback)(void *object, uint8_t connection_id,
186 uint8_t *public_key), void *object)
187{
188 con->response_callback = response_callback;
189 con->response_callback_object = object;
190}
191
192void routing_status_handler(TCP_Client_Connection *con, int (*status_callback)(void *object, uint32_t number,
193 uint8_t connection_id, uint8_t status), void *object)
194{
195 con->status_callback = status_callback;
196 con->status_callback_object = object;
197}
198
199/* return 1 on success.
200 * return 0 if could not send packet.
201 * return -1 on failure.
202 */
203int send_data(TCP_Client_Connection *con, uint8_t con_id, uint8_t *data, uint16_t length)
204{
205 if (con_id >= NUM_CLIENT_CONNECTIONS)
206 return -1;
207
208 if (con->connections[con_id].status != 2)
209 return -1;
210
211 uint8_t packet[1 + length];
212 packet[0] = con_id + NUM_RESERVED_PORTS;
213 memcpy(packet + 1, data, length);
214 return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
215}
216
217/* return 1 on success.
218 * return 0 if could not send packet.
219 * return -1 on failure.
220 */
221int send_oob_packet(TCP_Client_Connection *con, uint8_t *public_key, uint8_t *data, uint16_t length)
222{
223 if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH)
224 return -1;
225
226 uint8_t packet[1 + crypto_box_PUBLICKEYBYTES + length];
227 packet[0] = TCP_PACKET_OOB_SEND;
228 memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES);
229 memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, data, length);
230 return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
231}
232
233
234/* Set the number that will be used as an argument in the callbacks related to con_id.
235 *
236 * When not set by this function, the number is ~0.
237 *
238 * return 0 on success.
239 * return -1 on failure.
240 */
241int set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number)
242{
243 if (con_id >= NUM_CLIENT_CONNECTIONS)
244 return -1;
245
246 if (con->connections[con_id].status == 0)
247 return -1;
248
249 con->connections[con_id].number = number;
250 return 0;
251}
252
253void routing_data_handler(TCP_Client_Connection *con, int (*data_callback)(void *object, uint32_t number,
254 uint8_t connection_id, uint8_t *data, uint16_t length), void *object)
255{
256 con->data_callback = data_callback;
257 con->data_callback_object = object;
258}
259
260void oob_data_handler(TCP_Client_Connection *con, int (*oob_data_callback)(void *object, uint8_t *public_key,
261 uint8_t *data, uint16_t length), void *object)
262{
263 con->oob_data_callback = oob_data_callback;
264 con->oob_data_callback_object = object;
265}
266
267/* return 1 on success.
268 * return 0 if could not send packet.
269 * return -1 on failure (connection must be killed).
270 */
271static int send_disconnect_notification(TCP_Client_Connection *con, uint8_t id)
272{
273 uint8_t packet[1 + 1];
274 packet[0] = TCP_PACKET_DISCONNECT_NOTIFICATION;
275 packet[1] = id;
276 return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
277}
278
279/* return 1 on success.
280 * return 0 if could not send packet.
281 * return -1 on failure (connection must be killed).
282 */
283static int send_ping_request(TCP_Client_Connection *con, uint64_t ping_id)
284{
285 uint8_t packet[1 + sizeof(uint64_t)];
286 packet[0] = TCP_PACKET_PING;
287 memcpy(packet + 1, &ping_id, sizeof(uint64_t));
288 return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
289}
290
291/* return 1 on success.
292 * return 0 if could not send packet.
293 * return -1 on failure (connection must be killed).
294 */
295static int send_ping_response(TCP_Client_Connection *con, uint64_t ping_id)
296{
297 uint8_t packet[1 + sizeof(uint64_t)];
298 packet[0] = TCP_PACKET_PONG;
299 memcpy(packet + 1, &ping_id, sizeof(uint64_t));
300 return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
301}
302
303/* return 1 on success.
304 * return 0 if could not send packet.
305 * return -1 on failure (connection must be killed).
306 */
307int send_disconnect_request(TCP_Client_Connection *con, uint8_t con_id)
308{
309 if (con_id >= NUM_CLIENT_CONNECTIONS)
310 return -1;
311
312 con->connections[con_id].status = 0;
313 con->connections[con_id].number = 0;
314 return send_disconnect_notification(con, con_id + NUM_RESERVED_PORTS);
315}
316
317/* return 1 on success.
318 * return 0 if could not send packet.
319 * return -1 on failure (connection must be killed).
320 */
321int send_onion_request(TCP_Client_Connection *con, uint8_t *data, uint16_t length)
322{
323 uint8_t packet[1 + length];
324 packet[0] = TCP_PACKET_ONION_REQUEST;
325 memcpy(packet + 1, data, length);
326 return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
327}
328
329void onion_response_handler(TCP_Client_Connection *con, int (*onion_callback)(void *object, uint8_t *data,
330 uint16_t length), void *object)
331{
332 con->onion_callback = onion_callback;
333 con->onion_callback_object = object;
334}
335
133/* Create new TCP connection to ip_port/public_key 336/* Create new TCP connection to ip_port/public_key
134 */ 337 */
135TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key, uint8_t *self_public_key, 338TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key, uint8_t *self_public_key,
@@ -149,6 +352,11 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key,
149 return NULL; 352 return NULL;
150 } 353 }
151 354
355 if (!set_socket_nosigpipe(sock)) {
356 kill_sock(sock);
357 return 0;
358 }
359
152 if (!(set_socket_nonblock(sock) && connect_sock_to(sock, ip_port))) { 360 if (!(set_socket_nonblock(sock) && connect_sock_to(sock, ip_port))) {
153 kill_sock(sock); 361 kill_sock(sock);
154 return NULL; 362 return NULL;
@@ -164,6 +372,7 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key,
164 temp->status = TCP_CLIENT_CONNECTING; 372 temp->status = TCP_CLIENT_CONNECTING;
165 temp->sock = sock; 373 temp->sock = sock;
166 memcpy(temp->public_key, public_key, crypto_box_PUBLICKEYBYTES); 374 memcpy(temp->public_key, public_key, crypto_box_PUBLICKEYBYTES);
375 temp->ip_port = ip_port;
167 376
168 if (generate_handshake(temp, self_public_key, self_secret_key) == -1) { 377 if (generate_handshake(temp, self_public_key, self_secret_key) == -1) {
169 kill_sock(sock); 378 kill_sock(sock);
@@ -176,8 +385,181 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key,
176 return temp; 385 return temp;
177} 386}
178 387
179static int do_confirmed_TCP(TCP_Client_Connection *TCP_connection) 388/* return 0 on success
389 * return -1 on failure
390 */
391static int handle_TCP_packet(TCP_Client_Connection *conn, uint8_t *data, uint16_t length)
180{ 392{
393 if (length <= 1)
394 return -1;
395
396 switch (data[0]) {
397 case TCP_PACKET_ROUTING_RESPONSE: {
398 if (length != 1 + 1 + crypto_box_PUBLICKEYBYTES)
399 return -1;
400
401 if (data[1] < NUM_RESERVED_PORTS)
402 return 0;
403
404 uint8_t con_id = data[1] - NUM_RESERVED_PORTS;
405
406 if (conn->connections[con_id].status != 0)
407 return 0;
408
409 conn->connections[con_id].status = 1;
410 conn->connections[con_id].number = ~0;
411 memcpy(conn->connections[con_id].public_key, data + 2, crypto_box_PUBLICKEYBYTES);
412
413 if (conn->response_callback)
414 conn->response_callback(conn->response_callback_object, con_id, conn->connections[con_id].public_key);
415
416 return 0;
417 }
418
419 case TCP_PACKET_CONNECTION_NOTIFICATION: {
420 if (length != 1 + 1)
421 return -1;
422
423 if (data[1] < NUM_RESERVED_PORTS)
424 return -1;
425
426 uint8_t con_id = data[1] - NUM_RESERVED_PORTS;
427
428 if (conn->connections[con_id].status != 1)
429 return -1;
430
431 conn->connections[con_id].status = 2;
432
433 if (conn->status_callback)
434 conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id,
435 conn->connections[con_id].status);
436
437 return 0;
438 }
439
440 case TCP_PACKET_DISCONNECT_NOTIFICATION: {
441 if (length != 1 + 1)
442 return -1;
443
444 if (data[1] < NUM_RESERVED_PORTS)
445 return -1;
446
447 uint8_t con_id = data[1] - NUM_RESERVED_PORTS;
448
449 if (conn->connections[con_id].status == 0)
450 return 0;
451
452 if (conn->connections[con_id].status != 2)
453 return -1;
454
455 conn->connections[con_id].status = 1;
456
457 if (conn->status_callback)
458 conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id,
459 conn->connections[con_id].status);
460
461 return 0;
462 }
463
464 case TCP_PACKET_PING: {
465 if (length != 1 + sizeof(uint64_t))
466 return -1;
467
468 uint64_t ping_id;
469 memcpy(&ping_id, data + 1, sizeof(uint64_t));
470 send_ping_response(conn, ping_id);
471 return 0;
472 }
473
474 case TCP_PACKET_PONG: {
475 if (length != 1 + sizeof(uint64_t))
476 return -1;
477
478 uint64_t ping_id;
479 memcpy(&ping_id, data + 1, sizeof(uint64_t));
480
481 if (ping_id) {
482 if (ping_id == conn->ping_id) {
483 conn->ping_id = 0;
484 }
485
486 return 0;
487 } else {
488 return -1;
489 }
490 }
491
492 case TCP_PACKET_OOB_RECV: {
493 if (length <= 1 + crypto_box_PUBLICKEYBYTES)
494 return -1;
495
496 if (conn->oob_data_callback)
497 conn->oob_data_callback(conn->oob_data_callback_object, data + 1, data + 1 + crypto_box_PUBLICKEYBYTES,
498 length - (1 + crypto_box_PUBLICKEYBYTES));
499
500 return 0;
501 }
502
503 case TCP_PACKET_ONION_RESPONSE: {
504 conn->onion_callback(conn->onion_callback_object, data + 1, length - 1);
505 return 0;
506 }
507
508 default: {
509 if (data[0] < NUM_RESERVED_PORTS)
510 return -1;
511
512 uint8_t con_id = data[0] - NUM_RESERVED_PORTS;
513
514 if (conn->data_callback)
515 conn->data_callback(conn->data_callback_object, conn->connections[con_id].number, con_id, data + 1, length - 1);
516 }
517 }
518
519 return 0;
520}
521
522static int do_confirmed_TCP(TCP_Client_Connection *conn)
523{
524 send_pending_data(conn);
525 uint8_t packet[MAX_PACKET_SIZE];
526 int len;
527
528 if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY)) {
529 uint64_t ping_id = random_64b();
530
531 if (!ping_id)
532 ++ping_id;
533
534 int ret = send_ping_request(conn, ping_id);
535
536 if (ret == 1) {
537 conn->last_pinged = unix_time();
538 conn->ping_id = ping_id;
539 } else {
540 if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY + TCP_PING_TIMEOUT)) {
541 conn->status = TCP_CLIENT_DISCONNECTED;
542 }
543 }
544 }
545
546 if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) {
547 conn->status = TCP_CLIENT_DISCONNECTED;
548 return 0;
549 }
550
551 while ((len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key,
552 conn->recv_nonce, packet, sizeof(packet)))) {
553 if (len == -1) {
554 conn->status = TCP_CLIENT_DISCONNECTED;
555 break;
556 }
557
558 if (handle_TCP_packet(conn, packet, len) == -1) {
559 conn->status = TCP_CLIENT_DISCONNECTED;
560 break;
561 }
562 }
181 563
182 return 0; 564 return 0;
183} 565}
@@ -204,6 +586,7 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection)
204 586
205 if (sizeof(data) == len) { 587 if (sizeof(data) == len) {
206 if (handle_handshake(TCP_connection, data) == 0) { 588 if (handle_handshake(TCP_connection, data) == 0) {
589 TCP_connection->kill_at = ~0;
207 TCP_connection->status = TCP_CLIENT_CONFIRMED; 590 TCP_connection->status = TCP_CLIENT_CONFIRMED;
208 } else { 591 } else {
209 TCP_connection->kill_at = 0; 592 TCP_connection->kill_at = 0;
@@ -225,7 +608,10 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection)
225 */ 608 */
226void kill_TCP_connection(TCP_Client_Connection *TCP_connection) 609void kill_TCP_connection(TCP_Client_Connection *TCP_connection)
227{ 610{
611 if (TCP_connection == NULL)
612 return;
613
228 kill_sock(TCP_connection->sock); 614 kill_sock(TCP_connection->sock);
229 memset(TCP_connection, 0, sizeof(TCP_Client_Connection)); 615 memset(TCP_connection, 0, sizeof(TCP_Client_Connection));
230 free(TCP_connection); 616 free(TCP_connection);
231} \ No newline at end of file 617}