diff options
Diffstat (limited to 'toxcore/TCP_client.c')
-rw-r--r-- | toxcore/TCP_client.c | 398 |
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 | |||
90 | static int handle_handshake(TCP_Client_Connection *TCP_conn, uint8_t *data) | 93 | static 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 | */ | ||
140 | static 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 | */ | ||
177 | int 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 | |||
185 | void 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 | |||
192 | void 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 | */ | ||
203 | int 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 | */ | ||
221 | int 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 | */ | ||
241 | int 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 | |||
253 | void 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 | |||
260 | void 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 | */ | ||
271 | static 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 | */ | ||
283 | static 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 | */ | ||
295 | static 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 | */ | ||
307 | int 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 | */ | ||
321 | int 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 | |||
329 | void 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 | */ |
135 | TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key, uint8_t *self_public_key, | 338 | TCP_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 | ||
179 | static int do_confirmed_TCP(TCP_Client_Connection *TCP_connection) | 388 | /* return 0 on success |
389 | * return -1 on failure | ||
390 | */ | ||
391 | static 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 | |||
522 | static 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 | */ |
226 | void kill_TCP_connection(TCP_Client_Connection *TCP_connection) | 609 | void 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 | } |