summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--toxcore/Messenger.c138
-rw-r--r--toxcore/TCP_client.c9
-rw-r--r--toxcore/TCP_client.h1
-rw-r--r--toxcore/net_crypto.c151
-rw-r--r--toxcore/net_crypto.h28
-rw-r--r--toxcore/onion_client.c40
-rw-r--r--toxcore/onion_client.h15
-rw-r--r--toxcore/tox.c28
8 files changed, 309 insertions, 101 deletions
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
index b0d5a2e5..96005237 100644
--- a/toxcore/Messenger.c
+++ b/toxcore/Messenger.c
@@ -195,6 +195,21 @@ void getaddress(Messenger *m, uint8_t *address)
195 memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(nospam), &checksum, sizeof(checksum)); 195 memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(nospam), &checksum, sizeof(checksum));
196} 196}
197 197
198/* callback for recv TCP relay nodes. */
199static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, uint8_t *public_key)
200{
201 Messenger *m = object;
202
203 if (friend_not_valid(m, number))
204 return -1;
205
206 if (m->friendlist[number].crypt_connection_id != -1) {
207 return add_tcp_relay_peer(m->net_crypto, m->friendlist[number].crypt_connection_id, ip_port, public_key);
208 } else {
209 return add_tcp_relay(m->net_crypto, ip_port, public_key);
210 }
211}
212
198/* 213/*
199 * Add a friend. 214 * Add a friend.
200 * Set the data that will be sent along with friend request. 215 * Set the data that will be sent along with friend request.
@@ -277,6 +292,7 @@ int32_t m_addfriend(Messenger *m, uint8_t *address, uint8_t *data, uint16_t leng
277 m->friendlist[i].message_id = 0; 292 m->friendlist[i].message_id = 0;
278 m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ 293 m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */
279 memcpy(&(m->friendlist[i].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t)); 294 memcpy(&(m->friendlist[i].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t));
295 recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i);
280 296
281 if (m->numfriends == i) 297 if (m->numfriends == i)
282 ++m->numfriends; 298 ++m->numfriends;
@@ -322,6 +338,7 @@ int32_t m_addfriend_norequest(Messenger *m, uint8_t *client_id)
322 m->friendlist[i].is_typing = 0; 338 m->friendlist[i].is_typing = 0;
323 m->friendlist[i].message_id = 0; 339 m->friendlist[i].message_id = 0;
324 m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ 340 m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */
341 recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i);
325 342
326 if (m->numfriends == i) 343 if (m->numfriends == i)
327 ++m->numfriends; 344 ++m->numfriends;
@@ -2203,17 +2220,15 @@ void do_friends(Messenger *m)
2203 } 2220 }
2204 2221
2205 if (m->friendlist[i].crypt_connection_id != -1) { 2222 if (m->friendlist[i].crypt_connection_id != -1) {
2206 uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; 2223 uint8_t dht_public_key1[crypto_box_PUBLICKEYBYTES];
2207 uint64_t timestamp = onion_getfriend_DHT_pubkey(m->onion_c, m->friendlist[i].onion_friendnum, dht_public_key); 2224 uint64_t timestamp1 = onion_getfriend_DHT_pubkey(m->onion_c, m->friendlist[i].onion_friendnum, dht_public_key1);
2208 2225 uint8_t dht_public_key2[crypto_box_PUBLICKEYBYTES];
2209 if (timestamp != 0) { 2226 uint64_t timestamp2 = get_connection_dht_key(m->net_crypto, m->friendlist[i].crypt_connection_id, dht_public_key2);
2210 set_connection_dht_public_key(m->net_crypto, m->friendlist[i].crypt_connection_id, dht_public_key, timestamp); 2227
2211 } 2228 if (timestamp1 > timestamp2) {
2212 2229 set_connection_dht_public_key(m->net_crypto, m->friendlist[i].crypt_connection_id, dht_public_key1, timestamp1);
2213 timestamp = get_connection_dht_key(m->net_crypto, m->friendlist[i].crypt_connection_id, dht_public_key); 2230 } else if (timestamp1 < timestamp2) {
2214 2231 onion_set_friend_DHT_pubkey(m->onion_c, m->friendlist[i].onion_friendnum, dht_public_key2, timestamp2);
2215 if (timestamp != 0) {
2216 onion_set_friend_DHT_pubkey(m->onion_c, m->friendlist[i].onion_friendnum, dht_public_key, timestamp);
2217 } 2232 }
2218 2233
2219 uint8_t direct_connected; 2234 uint8_t direct_connected;
@@ -2462,9 +2477,10 @@ int wait_cleanup_messenger(Messenger *m, uint8_t *data)
2462#define MESSENGER_STATE_TYPE_NAME 4 2477#define MESSENGER_STATE_TYPE_NAME 4
2463#define MESSENGER_STATE_TYPE_STATUSMESSAGE 5 2478#define MESSENGER_STATE_TYPE_STATUSMESSAGE 5
2464#define MESSENGER_STATE_TYPE_STATUS 6 2479#define MESSENGER_STATE_TYPE_STATUS 6
2480#define MESSENGER_STATE_TYPE_TCP_RELAY 10
2465 2481
2466#define SAVED_FRIEND_REQUEST_SIZE 1024 2482#define SAVED_FRIEND_REQUEST_SIZE 1024
2467 2483#define NUM_SAVED_TCP_RELAYS 8
2468struct SAVED_FRIEND { 2484struct SAVED_FRIEND {
2469 uint8_t status; 2485 uint8_t status;
2470 uint8_t client_id[CLIENT_ID_SIZE]; 2486 uint8_t client_id[CLIENT_ID_SIZE];
@@ -2599,6 +2615,7 @@ uint32_t messenger_size(Messenger *m)
2599 + sizesubhead + m->name_length // Own nickname. 2615 + sizesubhead + m->name_length // Own nickname.
2600 + sizesubhead + m->statusmessage_length // status message 2616 + sizesubhead + m->statusmessage_length // status message
2601 + sizesubhead + 1 // status 2617 + sizesubhead + 1 // status
2618 + sizesubhead + NUM_SAVED_TCP_RELAYS * sizeof(Node_format) //TCP relays
2602 ; 2619 ;
2603} 2620}
2604 2621
@@ -2663,74 +2680,15 @@ void messenger_save(Messenger *m, uint8_t *data)
2663 data = z_state_save_subheader(data, len, type); 2680 data = z_state_save_subheader(data, len, type);
2664 *data = m->userstatus; 2681 *data = m->userstatus;
2665 data += len; 2682 data += len;
2666}
2667
2668static int messenger_load_state_callback_old(void *outer, uint8_t *data, uint32_t length, uint16_t type)
2669{
2670 Messenger *m = outer;
2671
2672 switch (type) {
2673 case MESSENGER_STATE_TYPE_NOSPAMKEYS:
2674 if (length == crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t)) {
2675 set_nospam(&(m->fr), *(uint32_t *)data);
2676 load_keys(m->net_crypto, &data[sizeof(uint32_t)]);
2677#ifdef ENABLE_ASSOC_DHT
2678
2679 if (m->dht->assoc)
2680 Assoc_self_client_id_changed(m->dht->assoc, m->net_crypto->self_public_key);
2681
2682#endif
2683 } else
2684 return -1; /* critical */
2685
2686 break;
2687
2688 case MESSENGER_STATE_TYPE_DHT:
2689 DHT_load(m->dht, data, length);
2690 break;
2691
2692 case MESSENGER_STATE_TYPE_FRIENDS:
2693 if (!(length % sizeof(Friend))) {
2694 uint16_t num = length / sizeof(Friend);
2695 Friend *friends = (Friend *)data;
2696 uint32_t i;
2697
2698 for (i = 0; i < num; ++i) {
2699 if (friends[i].status >= 3) {
2700 int fnum = m_addfriend_norequest(m, friends[i].client_id);
2701 setfriendname(m, fnum, friends[i].name, friends[i].name_length);
2702 /* set_friend_statusmessage(fnum, temp[i].statusmessage, temp[i].statusmessage_length); */
2703 } else if (friends[i].status != 0) {
2704 /* TODO: This is not a good way to do this. */
2705 uint8_t address[FRIEND_ADDRESS_SIZE];
2706 id_copy(address, friends[i].client_id);
2707 memcpy(address + crypto_box_PUBLICKEYBYTES, &(friends[i].friendrequest_nospam), sizeof(uint32_t));
2708 uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
2709 memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum));
2710 m_addfriend(m, address, friends[i].info, friends[i].info_size);
2711 }
2712 }
2713 }
2714
2715 break;
2716 2683
2717 case MESSENGER_STATE_TYPE_NAME: 2684 Node_format relays[NUM_SAVED_TCP_RELAYS];
2718 if ((length > 0) && (length < MAX_NAME_LENGTH)) { 2685 len = sizeof(relays);
2719 setname(m, data, length); 2686 type = MESSENGER_STATE_TYPE_TCP_RELAY;
2720 } 2687 data = z_state_save_subheader(data, len, type);
2721 2688 memset(relays, 0, len);
2722 break; 2689 copy_connected_tcp_relays(m->net_crypto, relays, NUM_SAVED_TCP_RELAYS);
2723 2690 memcpy(data, relays, len);
2724#ifdef DEBUG 2691 data += len;
2725
2726 default:
2727 fprintf(stderr, "Load state: contains unrecognized part (len %u, type %u)\n",
2728 length, type);
2729 break;
2730#endif
2731 }
2732
2733 return 0;
2734} 2692}
2735 2693
2736static int messenger_load_state_callback(void *outer, uint8_t *data, uint32_t length, uint16_t type) 2694static int messenger_load_state_callback(void *outer, uint8_t *data, uint32_t length, uint16_t type)
@@ -2781,6 +2739,22 @@ static int messenger_load_state_callback(void *outer, uint8_t *data, uint32_t le
2781 } 2739 }
2782 2740
2783 break; 2741 break;
2742
2743 case MESSENGER_STATE_TYPE_TCP_RELAY: {
2744 Node_format relays[NUM_SAVED_TCP_RELAYS];
2745
2746 if (length != sizeof(relays)) {
2747 return -1;
2748 }
2749
2750 memcpy(relays, data, length);
2751 uint32_t i;
2752
2753 for (i = 0; i < NUM_SAVED_TCP_RELAYS; ++i) {
2754 add_tcp_relay(m->net_crypto, relays[i].ip_port, relays[i].client_id);
2755 }
2756 }
2757 break;
2784#ifdef DEBUG 2758#ifdef DEBUG
2785 2759
2786 default: 2760 default:
@@ -2807,11 +2781,7 @@ int messenger_load(Messenger *m, uint8_t *data, uint32_t length)
2807 if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL)) 2781 if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL))
2808 return load_state(messenger_load_state_callback, m, data + cookie_len, 2782 return load_state(messenger_load_state_callback, m, data + cookie_len,
2809 length - cookie_len, MESSENGER_STATE_COOKIE_TYPE); 2783 length - cookie_len, MESSENGER_STATE_COOKIE_TYPE);
2810 2784 else
2811 else if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL_OLD))
2812 return load_state(messenger_load_state_callback_old, m, data + cookie_len,
2813 length - cookie_len, MESSENGER_STATE_COOKIE_TYPE);
2814 else /* old state file */
2815 return -1; 2785 return -1;
2816} 2786}
2817 2787
diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c
index 9091900f..e4845852 100644
--- a/toxcore/TCP_client.c
+++ b/toxcore/TCP_client.c
@@ -372,6 +372,7 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key,
372 temp->status = TCP_CLIENT_CONNECTING; 372 temp->status = TCP_CLIENT_CONNECTING;
373 temp->sock = sock; 373 temp->sock = sock;
374 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;
375 376
376 if (generate_handshake(temp, self_public_key, self_secret_key) == -1) { 377 if (generate_handshake(temp, self_public_key, self_secret_key) == -1) {
377 kill_sock(sock); 378 kill_sock(sock);
@@ -403,7 +404,7 @@ static int handle_TCP_packet(TCP_Client_Connection *conn, uint8_t *data, uint16_
403 uint8_t con_id = data[1] - NUM_RESERVED_PORTS; 404 uint8_t con_id = data[1] - NUM_RESERVED_PORTS;
404 405
405 if (conn->connections[con_id].status != 0) 406 if (conn->connections[con_id].status != 0)
406 return -1; 407 return 0;
407 408
408 conn->connections[con_id].status = 1; 409 conn->connections[con_id].status = 1;
409 conn->connections[con_id].number = ~0; 410 conn->connections[con_id].number = ~0;
@@ -445,6 +446,9 @@ static int handle_TCP_packet(TCP_Client_Connection *conn, uint8_t *data, uint16_
445 446
446 uint8_t con_id = data[1] - NUM_RESERVED_PORTS; 447 uint8_t con_id = data[1] - NUM_RESERVED_PORTS;
447 448
449 if (conn->connections[con_id].status == 0)
450 return 0;
451
448 if (conn->connections[con_id].status != 2) 452 if (conn->connections[con_id].status != 2)
449 return -1; 453 return -1;
450 454
@@ -604,6 +608,9 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection)
604 */ 608 */
605void kill_TCP_connection(TCP_Client_Connection *TCP_connection) 609void kill_TCP_connection(TCP_Client_Connection *TCP_connection)
606{ 610{
611 if (TCP_connection == NULL)
612 return;
613
607 kill_sock(TCP_connection->sock); 614 kill_sock(TCP_connection->sock);
608 memset(TCP_connection, 0, sizeof(TCP_Client_Connection)); 615 memset(TCP_connection, 0, sizeof(TCP_Client_Connection));
609 free(TCP_connection); 616 free(TCP_connection);
diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h
index 9583e15f..afb95392 100644
--- a/toxcore/TCP_client.h
+++ b/toxcore/TCP_client.h
@@ -40,6 +40,7 @@ typedef struct {
40 uint8_t status; 40 uint8_t status;
41 sock_t sock; 41 sock_t sock;
42 uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* public key of the server */ 42 uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* public key of the server */
43 IP_Port ip_port; /* The ip and port of the server */
43 uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */ 44 uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */
44 uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* Nonce of sent packets. */ 45 uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* Nonce of sent packets. */
45 uint8_t shared_key[crypto_box_BEFORENMBYTES]; 46 uint8_t shared_key[crypto_box_BEFORENMBYTES];
diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c
index 1e3456c3..875c639f 100644
--- a/toxcore/net_crypto.c
+++ b/toxcore/net_crypto.c
@@ -406,6 +406,8 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, uint8_t *data,
406 if (conn == 0) 406 if (conn == 0)
407 return -1; 407 return -1;
408 408
409 int direct_send_attempt = 0;
410
409 //TODO: on bad networks, direct connections might not last indefinitely. 411 //TODO: on bad networks, direct connections might not last indefinitely.
410 if (conn->ip_port.ip.family != 0) { 412 if (conn->ip_port.ip.family != 0) {
411 uint8_t direct_connected = 0; 413 uint8_t direct_connected = 0;
@@ -415,8 +417,10 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, uint8_t *data,
415 return 0; 417 return 0;
416 418
417 //TODO: a better way of sending packets directly to confirm the others ip. 419 //TODO: a better way of sending packets directly to confirm the others ip.
418 if (length < 96 || data[0] == NET_PACKET_COOKIE_REQUEST || data[0] == NET_PACKET_CRYPTO_HS) 420 if (length < 96 || data[0] == NET_PACKET_COOKIE_REQUEST || data[0] == NET_PACKET_CRYPTO_HS) {
419 sendpacket(c->dht->net, conn->ip_port, data, length); 421 if ((uint32_t)sendpacket(c->dht->net, conn->ip_port, data, length) == length)
422 direct_send_attempt = 1;
423 }
420 424
421 } 425 }
422 426
@@ -424,12 +428,23 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, uint8_t *data,
424 uint32_t i; 428 uint32_t i;
425 429
426 for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { 430 for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) {
427 if (conn->status_tcp[i] == 2) {/* friend is connected to this relay. */ 431 if (conn->status_tcp[i] == STATUS_TCP_ONLINE) {/* friend is connected to this relay. */
428 if (send_data(c->tcp_connections[i], conn->con_number_tcp[i], data, length) == 1) 432 if (send_data(c->tcp_connections[i], conn->con_number_tcp[i], data, length) == 1)
429 return 0; 433 return 0;
430 } 434 }
431 } 435 }
432 436
437 for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) {
438 if (conn->status_tcp[i] == STATUS_TCP_INVISIBLE) {
439 if (send_oob_packet(c->tcp_connections[i], conn->dht_public_key, data, length) == 1)
440 return 0;
441 }
442 }
443
444 if (direct_send_attempt) {
445 return 0;
446 }
447
433 return -1; 448 return -1;
434} 449}
435 450
@@ -1461,9 +1476,9 @@ static int disconnect_peer_tcp(Net_Crypto *c, int crypt_connection_id)
1461 uint32_t i; 1476 uint32_t i;
1462 1477
1463 for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { 1478 for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) {
1464 if (conn->status_tcp[i]) { 1479 if (conn->status_tcp[i] != STATUS_TCP_NULL) {
1465 send_disconnect_request(c->tcp_connections[i], conn->con_number_tcp[i]); 1480 send_disconnect_request(c->tcp_connections[i], conn->con_number_tcp[i]);
1466 conn->status_tcp[i] = 0; 1481 conn->status_tcp[i] = STATUS_TCP_NULL;
1467 conn->con_number_tcp[i] = 0; 1482 conn->con_number_tcp[i] = 0;
1468 } 1483 }
1469 } 1484 }
@@ -1575,9 +1590,10 @@ int set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port)
1575 if (!ipport_equal(&ip_port, &conn->ip_port)) { 1590 if (!ipport_equal(&ip_port, &conn->ip_port)) {
1576 conn->ip_port = ip_port; 1591 conn->ip_port = ip_port;
1577 conn->direct_lastrecv_time = 0; 1592 conn->direct_lastrecv_time = 0;
1593 return 0;
1578 } 1594 }
1579 1595
1580 return 0; 1596 return -1;
1581} 1597}
1582 1598
1583static int tcp_response_callback(void *object, uint8_t connection_id, uint8_t *public_key) 1599static int tcp_response_callback(void *object, uint8_t connection_id, uint8_t *public_key)
@@ -1605,8 +1621,17 @@ static int tcp_response_callback(void *object, uint8_t connection_id, uint8_t *p
1605 if (c->tcp_connections[location] != TCP_con) 1621 if (c->tcp_connections[location] != TCP_con)
1606 return -1; 1622 return -1;
1607 1623
1608 conn->status_tcp[location] = 1;
1609 conn->con_number_tcp[location] = connection_id; 1624 conn->con_number_tcp[location] = connection_id;
1625 uint32_t i;
1626
1627 for (i = 0; i < conn->num_tcp_relays; ++i) {
1628 if (memcmp(TCP_con->public_key, conn->tcp_relays[i].client_id, crypto_box_PUBLICKEYBYTES) == 0) {
1629 conn->status_tcp[location] = STATUS_TCP_INVISIBLE;
1630 return 0;
1631 }
1632 }
1633
1634 conn->status_tcp[location] = STATUS_TCP_OFFLINE;
1610 return 0; 1635 return 0;
1611} 1636}
1612 1637
@@ -1628,13 +1653,19 @@ static int tcp_status_callback(void *object, uint32_t number, uint8_t connection
1628 if (c->tcp_connections[location] != TCP_con) 1653 if (c->tcp_connections[location] != TCP_con)
1629 return -1; 1654 return -1;
1630 1655
1631 conn->status_tcp[location] = status; 1656 if (status == 1) {
1657 conn->status_tcp[location] = STATUS_TCP_OFFLINE;
1658 } else if (status == 2) {
1659 conn->status_tcp[location] = STATUS_TCP_ONLINE;
1660 }
1661
1632 conn->con_number_tcp[location] = connection_id; 1662 conn->con_number_tcp[location] = connection_id;
1633 return 0; 1663 return 0;
1634} 1664}
1635 1665
1636static int tcp_data_callback(void *object, uint32_t number, uint8_t connection_id, uint8_t *data, uint16_t length) 1666static int tcp_data_callback(void *object, uint32_t number, uint8_t connection_id, uint8_t *data, uint16_t length)
1637{ 1667{
1668
1638 if (length == 0) 1669 if (length == 0)
1639 return -1; 1670 return -1;
1640 1671
@@ -1729,6 +1760,59 @@ static int tcp_connection_check(Net_Crypto *c, uint8_t *public_key)
1729 return 0; 1760 return 0;
1730} 1761}
1731 1762
1763/* Add a tcp relay, associating it to a crypt_connection_id.
1764 *
1765 * return 0 if it was added.
1766 * return -1 if it wasn't.
1767 */
1768int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, uint8_t *public_key)
1769{
1770 Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);
1771
1772 if (conn == 0)
1773 return -1;
1774
1775 if (ip_port.ip.family == TCP_INET) {
1776 ip_port.ip.family = AF_INET;
1777 } else if (ip_port.ip.family == TCP_INET6) {
1778 ip_port.ip.family = AF_INET6;
1779 }
1780
1781 if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6)
1782 return -1;
1783
1784 uint32_t i;
1785
1786 for (i = 0; i < conn->num_tcp_relays; ++i) {
1787 if (memcmp(conn->tcp_relays[i].client_id, public_key, crypto_box_PUBLICKEYBYTES) == 0) {
1788 conn->tcp_relays[i].ip_port = ip_port;
1789 return 0;
1790 }
1791 }
1792
1793 if (conn->num_tcp_relays == MAX_TCP_RELAYS_PEER) {
1794 uint16_t index = rand() % MAX_TCP_RELAYS_PEER;
1795 conn->tcp_relays[index].ip_port = ip_port;
1796 memcpy(conn->tcp_relays[index].client_id, public_key, crypto_box_PUBLICKEYBYTES);
1797 } else {
1798 conn->tcp_relays[conn->num_tcp_relays].ip_port = ip_port;
1799 memcpy(conn->tcp_relays[conn->num_tcp_relays].client_id, public_key, crypto_box_PUBLICKEYBYTES);
1800 ++conn->num_tcp_relays;
1801 }
1802
1803 for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) {
1804 if (c->tcp_connections[i] == NULL)
1805 continue;
1806
1807 if (memcmp(c->tcp_connections[i]->public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) {
1808 if (conn->status_tcp[i] == STATUS_TCP_OFFLINE)
1809 conn->status_tcp[i] = STATUS_TCP_INVISIBLE;
1810 }
1811 }
1812
1813 return add_tcp_relay(c, ip_port, public_key);
1814}
1815
1732/* Add a tcp relay to the array. 1816/* Add a tcp relay to the array.
1733 * 1817 *
1734 * return 0 if it was added. 1818 * return 0 if it was added.
@@ -1736,6 +1820,15 @@ static int tcp_connection_check(Net_Crypto *c, uint8_t *public_key)
1736 */ 1820 */
1737int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, uint8_t *public_key) 1821int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, uint8_t *public_key)
1738{ 1822{
1823 if (ip_port.ip.family == TCP_INET) {
1824 ip_port.ip.family = AF_INET;
1825 } else if (ip_port.ip.family == TCP_INET6) {
1826 ip_port.ip.family = AF_INET6;
1827 }
1828
1829 if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6)
1830 return -1;
1831
1739 if (tcp_connection_check(c, public_key) != 0) 1832 if (tcp_connection_check(c, public_key) != 0)
1740 return -1; 1833 return -1;
1741 1834
@@ -1751,6 +1844,41 @@ int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, uint8_t *public_key)
1751 return -1; 1844 return -1;
1752} 1845}
1753 1846
1847/* Copy a maximum of num TCP relays we are connected to to tcp_relays.
1848 * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6.
1849 *
1850 * return number of relays copied to tcp_relays on success.
1851 * return 0 on failure.
1852 */
1853unsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, uint16_t num)
1854{
1855 if (num == 0)
1856 return 0;
1857
1858 uint32_t i;
1859 uint16_t copied = 0;
1860
1861 for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) {
1862 if (c->tcp_connections[i] != NULL) {
1863 memcpy(tcp_relays[copied].client_id, c->tcp_connections[i]->public_key, crypto_box_PUBLICKEYBYTES);
1864 tcp_relays[copied].ip_port = c->tcp_connections[i]->ip_port;
1865
1866 if (tcp_relays[copied].ip_port.ip.family == AF_INET) {
1867 tcp_relays[copied].ip_port.ip.family = TCP_INET;
1868 } else if (tcp_relays[copied].ip_port.ip.family == AF_INET6) {
1869 tcp_relays[copied].ip_port.ip.family = TCP_INET6;
1870 }
1871
1872 ++copied;
1873
1874 if (copied == num)
1875 return copied;
1876 }
1877 }
1878
1879 return copied;
1880}
1881
1754/* Add a connected tcp connection to the tcp_connections array. 1882/* Add a connected tcp connection to the tcp_connections array.
1755 * 1883 *
1756 * return 0 if it was added. 1884 * return 0 if it was added.
@@ -1834,7 +1962,7 @@ static void clear_disconnected_tcp_peer(Crypto_Connection *conn, uint32_t number
1834 if (number >= MAX_TCP_CONNECTIONS) 1962 if (number >= MAX_TCP_CONNECTIONS)
1835 return; 1963 return;
1836 1964
1837 conn->status_tcp[number] = 0; 1965 conn->status_tcp[number] = STATUS_TCP_NULL;
1838 conn->con_number_tcp[number] = 0; 1966 conn->con_number_tcp[number] = 0;
1839} 1967}
1840 1968
@@ -2255,6 +2383,11 @@ void kill_net_crypto(Net_Crypto *c)
2255 crypto_kill(c, i); 2383 crypto_kill(c, i);
2256 } 2384 }
2257 2385
2386 for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) {
2387 kill_TCP_connection(c->tcp_connections_new[i]);
2388 kill_TCP_connection(c->tcp_connections[i]);
2389 }
2390
2258 networking_registerhandler(c->dht->net, NET_PACKET_COOKIE_REQUEST, NULL, NULL); 2391 networking_registerhandler(c->dht->net, NET_PACKET_COOKIE_REQUEST, NULL, NULL);
2259 networking_registerhandler(c->dht->net, NET_PACKET_COOKIE_RESPONSE, NULL, NULL); 2392 networking_registerhandler(c->dht->net, NET_PACKET_COOKIE_RESPONSE, NULL, NULL);
2260 networking_registerhandler(c->dht->net, NET_PACKET_CRYPTO_HS, NULL, NULL); 2393 networking_registerhandler(c->dht->net, NET_PACKET_CRYPTO_HS, NULL, NULL);
diff --git a/toxcore/net_crypto.h b/toxcore/net_crypto.h
index e41e7e1d..25f8c2f7 100644
--- a/toxcore/net_crypto.h
+++ b/toxcore/net_crypto.h
@@ -61,7 +61,13 @@
61 61
62#define CRYPTO_RESERVED_PACKETS 16 62#define CRYPTO_RESERVED_PACKETS 16
63 63
64#define MAX_TCP_CONNECTIONS 8 64#define MAX_TCP_CONNECTIONS 32
65#define MAX_TCP_RELAYS_PEER 4
66
67#define STATUS_TCP_NULL 0
68#define STATUS_TCP_OFFLINE 1
69#define STATUS_TCP_INVISIBLE 2 /* we know the other peer is connected to this relay but he isn't appearing online */
70#define STATUS_TCP_ONLINE 3
65 71
66typedef struct { 72typedef struct {
67 uint64_t time; 73 uint64_t time;
@@ -127,8 +133,11 @@ typedef struct {
127 133
128 uint8_t killed; /* set to 1 to kill the connection. */ 134 uint8_t killed; /* set to 1 to kill the connection. */
129 135
130 uint8_t status_tcp[MAX_TCP_CONNECTIONS]; 136 uint8_t status_tcp[MAX_TCP_CONNECTIONS]; /* set to one of STATUS_TCP_* */
131 uint8_t con_number_tcp[MAX_TCP_CONNECTIONS]; 137 uint8_t con_number_tcp[MAX_TCP_CONNECTIONS];
138
139 Node_format tcp_relays[MAX_TCP_RELAYS_PEER];
140 uint16_t num_tcp_relays;
132} Crypto_Connection; 141} Crypto_Connection;
133 142
134typedef struct { 143typedef struct {
@@ -244,6 +253,13 @@ uint32_t crypto_num_free_sendqueue_slots(Net_Crypto *c, int crypt_connection_id)
244 */ 253 */
245int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length); 254int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length);
246 255
256/* Add a tcp relay, associating it to a crypt_connection_id.
257 *
258 * return 0 if it was added.
259 * return -1 if it wasn't.
260 */
261int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, uint8_t *public_key);
262
247/* Add a tcp relay to the array. 263/* Add a tcp relay to the array.
248 * 264 *
249 * return 0 if it was added. 265 * return 0 if it was added.
@@ -251,6 +267,14 @@ int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data,
251 */ 267 */
252int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, uint8_t *public_key); 268int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, uint8_t *public_key);
253 269
270/* Copy a maximum of num TCP relays we are connected to to tcp_relays.
271 * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6.
272 *
273 * return number of relays copied to tcp_relays on success.
274 * return 0 on failure.
275 */
276unsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, uint16_t num);
277
254/* Kill a crypto connection. 278/* Kill a crypto connection.
255 * 279 *
256 * return -1 on failure. 280 * return -1 on failure.
diff --git a/toxcore/onion_client.c b/toxcore/onion_client.c
index be4d12aa..03ffbaa7 100644
--- a/toxcore/onion_client.c
+++ b/toxcore/onion_client.c
@@ -505,7 +505,7 @@ static int handle_fakeid_announce(void *object, uint8_t *source_pubkey, uint8_t
505 if (len_nodes != 0) { 505 if (len_nodes != 0) {
506 Node_format nodes[MAX_SENT_NODES]; 506 Node_format nodes[MAX_SENT_NODES];
507 int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, data + 1 + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES, 507 int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, data + 1 + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES,
508 len_nodes, 0); 508 len_nodes, 1);
509 509
510 if (num_nodes <= 0) 510 if (num_nodes <= 0)
511 return 1; 511 return 1;
@@ -513,7 +513,17 @@ static int handle_fakeid_announce(void *object, uint8_t *source_pubkey, uint8_t
513 int i; 513 int i;
514 514
515 for (i = 0; i < num_nodes; ++i) { 515 for (i = 0; i < num_nodes; ++i) {
516 DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].client_id, onion_c->friends_list[friend_num].fake_client_id); 516 uint8_t family = nodes[i].ip_port.ip.family;
517
518 if (family == AF_INET || family == AF_INET6) {
519 DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].client_id, onion_c->friends_list[friend_num].fake_client_id);
520 } else if (family == TCP_INET || family == TCP_INET6) {
521 if (onion_c->friends_list[friend_num].tcp_relay_node_callback) {
522 void *obj = onion_c->friends_list[friend_num].tcp_relay_node_callback_object;
523 uint32_t number = onion_c->friends_list[friend_num].tcp_relay_node_callback_number;
524 onion_c->friends_list[friend_num].tcp_relay_node_callback(obj, number, nodes[i].ip_port, nodes[i].client_id);
525 }
526 }
517 } 527 }
518 } 528 }
519 529
@@ -664,8 +674,9 @@ static int send_fakeid_announce(Onion_Client *onion_c, uint16_t friend_num, uint
664 memcpy(data + 1, &no_replay, sizeof(no_replay)); 674 memcpy(data + 1, &no_replay, sizeof(no_replay));
665 memcpy(data + 1 + sizeof(uint64_t), onion_c->dht->self_public_key, crypto_box_PUBLICKEYBYTES); 675 memcpy(data + 1 + sizeof(uint64_t), onion_c->dht->self_public_key, crypto_box_PUBLICKEYBYTES);
666 Node_format nodes[MAX_SENT_NODES]; 676 Node_format nodes[MAX_SENT_NODES];
667 uint16_t num_nodes = closelist_nodes(onion_c->dht, nodes, MAX_SENT_NODES); 677 uint16_t num_relays = copy_connected_tcp_relays(onion_c->c, nodes, (MAX_SENT_NODES / 2));
668 678 uint16_t num_nodes = closelist_nodes(onion_c->dht, &nodes[num_relays], MAX_SENT_NODES - num_relays);
679 num_nodes += num_relays;
669 int nodes_len = 0; 680 int nodes_len = 0;
670 681
671 if (num_nodes != 0) { 682 if (num_nodes != 0) {
@@ -800,6 +811,26 @@ int onion_delfriend(Onion_Client *onion_c, int friend_num)
800 return friend_num; 811 return friend_num;
801} 812}
802 813
814/* Set the function for this friend that will be callbacked with object and number
815 * when that friends gives us one of the TCP relays he is connected to.
816 *
817 * object and number will be passed as argument to this function.
818 *
819 * return -1 on failure.
820 * return 0 on success.
821 */
822int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object,
823 uint32_t number, IP_Port ip_port, uint8_t *public_key), void *object, uint32_t number)
824{
825 if ((uint32_t)friend_num >= onion_c->num_friends)
826 return -1;
827
828 onion_c->friends_list[friend_num].tcp_relay_node_callback = tcp_relay_node_callback;
829 onion_c->friends_list[friend_num].tcp_relay_node_callback_object = object;
830 onion_c->friends_list[friend_num].tcp_relay_node_callback_number = number;
831 return 0;
832}
833
803/* Set a friends DHT public key. 834/* Set a friends DHT public key.
804 * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to 835 * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to
805 * the other peer. 836 * the other peer.
@@ -830,6 +861,7 @@ int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, uint8_t *
830 return -1; 861 return -1;
831 } 862 }
832 863
864 onion_c->friends_list[friend_num].last_seen = unix_time();
833 onion_c->friends_list[friend_num].is_fake_clientid = 1; 865 onion_c->friends_list[friend_num].is_fake_clientid = 1;
834 onion_c->friends_list[friend_num].fake_client_id_timestamp = timestamp; 866 onion_c->friends_list[friend_num].fake_client_id_timestamp = timestamp;
835 memcpy(onion_c->friends_list[friend_num].fake_client_id, dht_key, crypto_box_PUBLICKEYBYTES); 867 memcpy(onion_c->friends_list[friend_num].fake_client_id, dht_key, crypto_box_PUBLICKEYBYTES);
diff --git a/toxcore/onion_client.h b/toxcore/onion_client.h
index 029f5624..0d2e84a5 100644
--- a/toxcore/onion_client.h
+++ b/toxcore/onion_client.h
@@ -102,6 +102,10 @@ typedef struct {
102 102
103 Last_Pinged last_pinged[MAX_STORED_PINGED_NODES]; 103 Last_Pinged last_pinged[MAX_STORED_PINGED_NODES];
104 uint8_t last_pinged_index; 104 uint8_t last_pinged_index;
105
106 int (*tcp_relay_node_callback)(void *object, uint32_t number, IP_Port ip_port, uint8_t *public_key);
107 void *tcp_relay_node_callback_object;
108 uint32_t tcp_relay_node_callback_number;
105} Onion_Friend; 109} Onion_Friend;
106 110
107typedef int (*oniondata_handler_callback)(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t len); 111typedef int (*oniondata_handler_callback)(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t len);
@@ -176,6 +180,17 @@ int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_on
176 */ 180 */
177int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port); 181int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port);
178 182
183/* Set the function for this friend that will be callbacked with object and number
184 * when that friends gives us one of the TCP relays he is connected to.
185 *
186 * object and number will be passed as argument to this function.
187 *
188 * return -1 on failure.
189 * return 0 on success.
190 */
191int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object,
192 uint32_t number, IP_Port ip_port, uint8_t *public_key), void *object, uint32_t number);
193
179/* Set a friends DHT public key. 194/* Set a friends DHT public key.
180 * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to 195 * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to
181 * the other peer. 196 * the other peer.
diff --git a/toxcore/tox.c b/toxcore/tox.c
index d86f1a17..083582bb 100644
--- a/toxcore/tox.c
+++ b/toxcore/tox.c
@@ -739,12 +739,38 @@ uint64_t tox_file_data_remaining(Tox *tox, int32_t friendnumber, uint8_t filenum
739 739
740/***************END OF FILE SENDING FUNCTIONS******************/ 740/***************END OF FILE SENDING FUNCTIONS******************/
741 741
742/* TODO: expose this properly. */
743static int tox_add_tcp_relay(Tox *tox, const char *address, uint8_t ipv6enabled, uint16_t port, uint8_t *public_key)
744{
745 Messenger *m = tox;
746 IP_Port ip_port_v64;
747 IP *ip_extra = NULL;
748 IP_Port ip_port_v4;
749 ip_init(&ip_port_v64.ip, ipv6enabled);
750
751 if (ipv6enabled) {
752 /* setup for getting BOTH: an IPv6 AND an IPv4 address */
753 ip_port_v64.ip.family = AF_UNSPEC;
754 ip_reset(&ip_port_v4.ip);
755 ip_extra = &ip_port_v4.ip;
756 }
757
758 if (addr_resolve_or_parse_ip(address, &ip_port_v64.ip, ip_extra)) {
759 ip_port_v64.port = port;
760 add_tcp_relay(m->net_crypto, ip_port_v64, public_key);
761 return 1;
762 } else {
763 return 0;
764 }
765}
766
742int tox_bootstrap_from_address(Tox *tox, const char *address, 767int tox_bootstrap_from_address(Tox *tox, const char *address,
743 uint8_t ipv6enabled, uint16_t port, uint8_t *public_key) 768 uint8_t ipv6enabled, uint16_t port, uint8_t *public_key)
744{ 769{
745 Messenger *m = tox; 770 Messenger *m = tox;
771 tox_add_tcp_relay(tox, address, ipv6enabled, port, public_key);
746 return DHT_bootstrap_from_address(m->dht, address, ipv6enabled, port, public_key); 772 return DHT_bootstrap_from_address(m->dht, address, ipv6enabled, port, public_key);
747}; 773}
748 774
749/* return 0 if we are not connected to the DHT. 775/* return 0 if we are not connected to the DHT.
750 * return 1 if we are. 776 * return 1 if we are.