summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2014-12-26 19:38:19 -0500
committerirungentoo <irungentoo@gmail.com>2014-12-26 19:38:19 -0500
commitfe57a72659a8a298d8c11f7355d15815dee10195 (patch)
treeaa3064268b325cb1ceb145cb5a367d1df6c1c4f9
parenta4f0b65ad72682e6ca2becf3081f7e5e72a0f7af (diff)
parent35602e12c007aec38f65c860cad5f03953c4596d (diff)
Merge branch 'http-proxy-feature' of https://github.com/nurupo/InsertProjectNameHere
-rw-r--r--INSTALL4
-rw-r--r--toxcore/Messenger.c6
-rw-r--r--toxcore/Messenger.h1
-rw-r--r--toxcore/TCP_client.c128
-rw-r--r--toxcore/TCP_client.h14
-rw-r--r--toxcore/net_crypto.c12
-rw-r--r--toxcore/net_crypto.h1
-rw-r--r--toxcore/network.c35
-rw-r--r--toxcore/network.h20
-rw-r--r--toxcore/tox.c15
-rw-r--r--toxcore/tox.h14
11 files changed, 199 insertions, 51 deletions
diff --git a/INSTALL b/INSTALL
index 007e9396..20998407 100644
--- a/INSTALL
+++ b/INSTALL
@@ -12,8 +12,8 @@ without warranty of any kind.
12Basic Installation 12Basic Installation
13================== 13==================
14 14
15 Briefly, the shell commands `./configure; make; make install' should 15 Briefly, the shell command `./configure && make && make install'
16configure, build, and install this package. The following 16should configure, build, and install this package. The following
17more-detailed instructions are generic; see the `README' file for 17more-detailed instructions are generic; see the `README' file for
18instructions specific to this package. Some packages provide this 18instructions specific to this package. Some packages provide this
19`INSTALL' file but do not implement all of the features documented 19`INSTALL' file but do not implement all of the features documented
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
index f9bd68c2..9869f738 100644
--- a/toxcore/Messenger.c
+++ b/toxcore/Messenger.c
@@ -1595,11 +1595,7 @@ Messenger *new_messenger(Messenger_Options *options)
1595 return NULL; 1595 return NULL;
1596 } 1596 }
1597 1597
1598 if (options->proxy_enabled) { 1598 m->net_crypto = new_net_crypto(m->dht, &options->proxy_info);
1599 m->net_crypto = new_net_crypto(m->dht, &options->proxy_info);
1600 } else {
1601 m->net_crypto = new_net_crypto(m->dht, 0);
1602 }
1603 1599
1604 if (m->net_crypto == NULL) { 1600 if (m->net_crypto == NULL) {
1605 kill_networking(m->net); 1601 kill_networking(m->net);
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h
index ae6f54c6..3851edf7 100644
--- a/toxcore/Messenger.h
+++ b/toxcore/Messenger.h
@@ -75,7 +75,6 @@
75typedef struct { 75typedef struct {
76 uint8_t ipv6enabled; 76 uint8_t ipv6enabled;
77 uint8_t udp_disabled; 77 uint8_t udp_disabled;
78 uint8_t proxy_enabled;
79 TCP_Proxy_Info proxy_info; 78 TCP_Proxy_Info proxy_info;
80} Messenger_Options; 79} Messenger_Options;
81 80
diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c
index 23ab28c0..aee309ae 100644
--- a/toxcore/TCP_client.c
+++ b/toxcore/TCP_client.c
@@ -37,8 +37,9 @@
37 */ 37 */
38static int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_info) 38static int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_info)
39{ 39{
40 if (proxy_info) 40 if (proxy_info->proxy_type != TCP_PROXY_NONE) {
41 ip_port = proxy_info->ip_port; 41 ip_port =proxy_info->ip_port;
42 }
42 43
43 struct sockaddr_storage addr = {0}; 44 struct sockaddr_storage addr = {0};
44 size_t addrsize; 45 size_t addrsize;
@@ -66,8 +67,67 @@ static int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_i
66 return 1; 67 return 1;
67} 68}
68 69
70/* return 1 on success.
71 * return 0 on failure.
72 */
73static int proxy_http_generate_connection_request(TCP_Client_Connection *TCP_conn)
74{
75 char one[] = "CONNECT ";
76 char two[] = " HTTP/1.1\nHost: ";
77 char three[] = "\r\n\r\n";
78
79 char ip[INET6_ADDRSTRLEN];
80 if (!ip_parse_addr(&TCP_conn->ip_port.ip, ip, sizeof(ip))) {
81 return 0;
82 }
83 const uint16_t port = ntohs(TCP_conn->ip_port.port);
84 const int written = snprintf(TCP_conn->last_packet, MAX_PACKET_SIZE, "%s%s:%hu%s%s:%hu%s", one, ip, port, two, ip, port, three);
85 if (written < 0) {
86 return 0;
87 }
88
89 TCP_conn->last_packet_length = written;
90 TCP_conn->last_packet_sent = 0;
91
92 return 1;
93}
94
95/* return 1 on success.
96 * return 0 if no data received.
97 * return -1 on failure (connection refused).
98 */
99static int proxy_http_read_connection_response(TCP_Client_Connection *TCP_conn)
100{
101 char success[] = "200";
102 uint8_t data[16]; // draining works the best if the length is a power of 2
103
104 int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data) - 1);
105
106 if (ret == -1) {
107 return 0;
108 }
109
110 data[sizeof(data) - 1] = '\0';
111
112 if (strstr(data, success)) {
113 // drain all data
114 // instead of drainining it byte by byte do it in bigger chunks
115 // decrementing to 1
116 size_t step = sizeof(data);
117 do {
118 if (ret <= 0) {
119 step = step % 2 == 0 ? step/2 : 1;
120 }
121 ret = read_TCP_packet(TCP_conn->sock, data, step);
122 } while (ret > 0 || step != 1);
123
124 return 1;
125 }
69 126
70static void socks5_generate_handshake(TCP_Client_Connection *TCP_conn) 127 return -1;
128}
129
130static void proxy_socks5_generate_handshake(TCP_Client_Connection *TCP_conn)
71{ 131{
72 TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ 132 TCP_conn->last_packet[0] = 5; /* SOCKSv5 */
73 TCP_conn->last_packet[1] = 1; /* number of authentication methods supported */ 133 TCP_conn->last_packet[1] = 1; /* number of authentication methods supported */
@@ -95,7 +155,7 @@ static int socks5_read_handshake_response(TCP_Client_Connection *TCP_conn)
95 return -1; 155 return -1;
96} 156}
97 157
98static void socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) 158static void proxy_socks5_generate_connection_request(TCP_Client_Connection *TCP_conn)
99{ 159{
100 TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ 160 TCP_conn->last_packet[0] = 5; /* SOCKSv5 */
101 TCP_conn->last_packet[1] = 1; /* command code: establish a TCP/IP stream connection */ 161 TCP_conn->last_packet[1] = 1; /* command code: establish a TCP/IP stream connection */
@@ -125,7 +185,7 @@ static void socks5_generate_connection_request(TCP_Client_Connection *TCP_conn)
125 * return 0 if no data received. 185 * return 0 if no data received.
126 * return -1 on failure (connection refused). 186 * return -1 on failure (connection refused).
127 */ 187 */
128static int socks5_read_connection_response(TCP_Client_Connection *TCP_conn) 188static int proxy_socks5_read_connection_response(TCP_Client_Connection *TCP_conn)
129{ 189{
130 if (TCP_conn->ip_port.ip.family == AF_INET) { 190 if (TCP_conn->ip_port.ip.family == AF_INET) {
131 uint8_t data[4 + sizeof(IP4) + sizeof(uint16_t)]; 191 uint8_t data[4 + sizeof(IP4) + sizeof(uint16_t)];
@@ -546,8 +606,9 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public
546 606
547 uint8_t family = ip_port.ip.family; 607 uint8_t family = ip_port.ip.family;
548 608
549 if (proxy_info) 609 if (proxy_info->proxy_type != TCP_PROXY_NONE) {
550 family = proxy_info->ip_port.ip.family; 610 family = proxy_info->ip_port.ip.family;
611 }
551 612
552 sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP); 613 sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP);
553 614
@@ -577,19 +638,26 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public
577 memcpy(temp->self_public_key, self_public_key, crypto_box_PUBLICKEYBYTES); 638 memcpy(temp->self_public_key, self_public_key, crypto_box_PUBLICKEYBYTES);
578 encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key); 639 encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key);
579 temp->ip_port = ip_port; 640 temp->ip_port = ip_port;
641 temp->proxy_info = *proxy_info;
580 642
581 if (proxy_info) { 643 switch (proxy_info->proxy_type) {
582 temp->status = TCP_CLIENT_PROXY_CONNECTING; 644 case TCP_PROXY_HTTP:
583 temp->proxy_info = *proxy_info; 645 temp->status = TCP_CLIENT_PROXY_HTTP_CONNECTING;
584 socks5_generate_handshake(temp); 646 proxy_http_generate_connection_request(temp);
585 } else { 647 break;
586 temp->status = TCP_CLIENT_CONNECTING; 648 case TCP_PROXY_SOCKS5:
649 temp->status = TCP_CLIENT_PROXY_SOCKS5_CONNECTING;
650 proxy_socks5_generate_handshake(temp);
651 break;
652 case TCP_PROXY_NONE:
653 temp->status = TCP_CLIENT_CONNECTING;
587 654
588 if (generate_handshake(temp) == -1) { 655 if (generate_handshake(temp) == -1) {
589 kill_sock(sock); 656 kill_sock(sock);
590 free(temp); 657 free(temp);
591 return NULL; 658 return NULL;
592 } 659 }
660 break;
593 } 661 }
594 662
595 temp->kill_at = unix_time() + TCP_CONNECTION_TIMEOUT; 663 temp->kill_at = unix_time() + TCP_CONNECTION_TIMEOUT;
@@ -783,7 +851,23 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection)
783 return; 851 return;
784 } 852 }
785 853
786 if (TCP_connection->status == TCP_CLIENT_PROXY_CONNECTING) { 854 if (TCP_connection->status == TCP_CLIENT_PROXY_HTTP_CONNECTING) {
855 if (send_pending_data(TCP_connection) == 0) {
856 int ret = proxy_http_read_connection_response(TCP_connection);
857
858 if (ret == -1) {
859 TCP_connection->kill_at = 0;
860 TCP_connection->status = TCP_CLIENT_DISCONNECTED;
861 }
862
863 if (ret == 1) {
864 generate_handshake(TCP_connection);
865 TCP_connection->status = TCP_CLIENT_CONNECTING;
866 }
867 }
868 }
869
870 if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_CONNECTING) {
787 if (send_pending_data(TCP_connection) == 0) { 871 if (send_pending_data(TCP_connection) == 0) {
788 int ret = socks5_read_handshake_response(TCP_connection); 872 int ret = socks5_read_handshake_response(TCP_connection);
789 873
@@ -793,15 +877,15 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection)
793 } 877 }
794 878
795 if (ret == 1) { 879 if (ret == 1) {
796 socks5_generate_connection_request(TCP_connection); 880 proxy_socks5_generate_connection_request(TCP_connection);
797 TCP_connection->status = TCP_CLIENT_PROXY_UNCONFIRMED; 881 TCP_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED;
798 } 882 }
799 } 883 }
800 } 884 }
801 885
802 if (TCP_connection->status == TCP_CLIENT_PROXY_UNCONFIRMED) { 886 if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED) {
803 if (send_pending_data(TCP_connection) == 0) { 887 if (send_pending_data(TCP_connection) == 0) {
804 int ret = socks5_read_connection_response(TCP_connection); 888 int ret = proxy_socks5_read_connection_response(TCP_connection);
805 889
806 if (ret == -1) { 890 if (ret == -1) {
807 TCP_connection->kill_at = 0; 891 TCP_connection->kill_at = 0;
diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h
index 83cb48ba..e37a4ee0 100644
--- a/toxcore/TCP_client.h
+++ b/toxcore/TCP_client.h
@@ -29,14 +29,22 @@
29 29
30#define TCP_CONNECTION_TIMEOUT 10 30#define TCP_CONNECTION_TIMEOUT 10
31 31
32typedef struct { 32typedef enum {
33 TCP_PROXY_NONE,
34 TCP_PROXY_HTTP,
35 TCP_PROXY_SOCKS5
36} TCP_PROXY_TYPE;
37
38typedef struct {
33 IP_Port ip_port; 39 IP_Port ip_port;
40 uint8_t proxy_type; // a value from TCP_PROXY_TYPE
34} TCP_Proxy_Info; 41} TCP_Proxy_Info;
35 42
36enum { 43enum {
37 TCP_CLIENT_NO_STATUS, 44 TCP_CLIENT_NO_STATUS,
38 TCP_CLIENT_PROXY_CONNECTING, 45 TCP_CLIENT_PROXY_HTTP_CONNECTING,
39 TCP_CLIENT_PROXY_UNCONFIRMED, 46 TCP_CLIENT_PROXY_SOCKS5_CONNECTING,
47 TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED,
40 TCP_CLIENT_CONNECTING, 48 TCP_CLIENT_CONNECTING,
41 TCP_CLIENT_UNCONFIRMED, 49 TCP_CLIENT_UNCONFIRMED,
42 TCP_CLIENT_CONFIRMED, 50 TCP_CLIENT_CONFIRMED,
diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c
index a1286c5d..c5872068 100644
--- a/toxcore/net_crypto.c
+++ b/toxcore/net_crypto.c
@@ -2029,13 +2029,8 @@ int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, const uint8_t *public_key)
2029 2029
2030 for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { 2030 for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) {
2031 if (c->tcp_connections_new[i] == NULL) { 2031 if (c->tcp_connections_new[i] == NULL) {
2032 if (c->proxy_set) { 2032 c->tcp_connections_new[i] = new_TCP_connection(ip_port, public_key, c->dht->self_public_key, c->dht->self_secret_key,
2033 c->tcp_connections_new[i] = new_TCP_connection(ip_port, public_key, c->dht->self_public_key, c->dht->self_secret_key,
2034 &c->proxy_info); 2033 &c->proxy_info);
2035 } else {
2036 c->tcp_connections_new[i] = new_TCP_connection(ip_port, public_key, c->dht->self_public_key, c->dht->self_secret_key,
2037 0);
2038 }
2039 2034
2040 return 0; 2035 return 0;
2041 } 2036 }
@@ -2768,10 +2763,7 @@ Net_Crypto *new_net_crypto(DHT *dht, TCP_Proxy_Info *proxy_info)
2768 2763
2769 bs_list_init(&temp->ip_port_list, sizeof(IP_Port), 8); 2764 bs_list_init(&temp->ip_port_list, sizeof(IP_Port), 8);
2770 2765
2771 if (proxy_info) { 2766 temp->proxy_info = *proxy_info;
2772 temp->proxy_info = *proxy_info;
2773 temp->proxy_set = 1;
2774 }
2775 2767
2776 return temp; 2768 return temp;
2777} 2769}
diff --git a/toxcore/net_crypto.h b/toxcore/net_crypto.h
index 7fa05f08..78dea54e 100644
--- a/toxcore/net_crypto.h
+++ b/toxcore/net_crypto.h
@@ -215,7 +215,6 @@ typedef struct {
215 int (*tcp_onion_callback)(void *object, const uint8_t *data, uint16_t length); 215 int (*tcp_onion_callback)(void *object, const uint8_t *data, uint16_t length);
216 void *tcp_onion_callback_object; 216 void *tcp_onion_callback_object;
217 217
218 uint8_t proxy_set;
219 TCP_Proxy_Info proxy_info; 218 TCP_Proxy_Info proxy_info;
220} Net_Crypto; 219} Net_Crypto;
221 220
diff --git a/toxcore/network.c b/toxcore/network.c
index 35ef5221..5539de6b 100644
--- a/toxcore/network.c
+++ b/toxcore/network.c
@@ -784,6 +784,9 @@ void ipport_unpack(IP_Port *target, const uint8_t *data)
784/* ip_ntoa 784/* ip_ntoa
785 * converts ip into a string 785 * converts ip into a string
786 * uses a static buffer, so mustn't used multiple times in the same output 786 * uses a static buffer, so mustn't used multiple times in the same output
787 *
788 * IPv6 addresses are enclosed into square brackets, i.e. "[IPv6]"
789 * writes error message into the buffer on error
787 */ 790 */
788/* there would be INET6_ADDRSTRLEN, but it might be too short for the error message */ 791/* there would be INET6_ADDRSTRLEN, but it might be too short for the error message */
789static char addresstext[96]; 792static char addresstext[96];
@@ -816,6 +819,38 @@ const char *ip_ntoa(const IP *ip)
816} 819}
817 820
818/* 821/*
822 * ip_parse_addr
823 * parses IP structure into an address string
824 *
825 * input
826 * ip: ip of AF_INET or AF_INET6 families
827 * length: length of the address buffer
828 * Must be at least INET_ADDRSTRLEN for AF_INET
829 * and INET6_ADDRSTRLEN for AF_INET6
830 *
831 * output
832 * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6)
833 *
834 * returns 1 on success, 0 on failure
835 */
836int ip_parse_addr(const IP *ip, char *address, size_t length)
837{
838 if (!address || !ip) {
839 return 0;
840 }
841
842 if (ip->family == AF_INET) {
843 struct in_addr *addr = (struct in_addr *)&ip->ip4;
844 return inet_ntop(ip->family, addr, address, length) != NULL;
845 } else if (ip->family == AF_INET6) {
846 struct in6_addr *addr = (struct in6_addr *)&ip->ip6;
847 return inet_ntop(ip->family, addr, address, length) != NULL;
848 }
849
850 return 0;
851}
852
853/*
819 * addr_parse_ip 854 * addr_parse_ip
820 * directly parses the input into an IP structure 855 * directly parses the input into an IP structure
821 * tries IPv4 first, then IPv6 856 * tries IPv4 first, then IPv6
diff --git a/toxcore/network.h b/toxcore/network.h
index ccda7ae9..5f9af490 100644
--- a/toxcore/network.h
+++ b/toxcore/network.h
@@ -180,10 +180,30 @@ IP_Port;
180/* ip_ntoa 180/* ip_ntoa
181 * converts ip into a string 181 * converts ip into a string
182 * uses a static buffer, so mustn't used multiple times in the same output 182 * uses a static buffer, so mustn't used multiple times in the same output
183 *
184 * IPv6 addresses are enclosed into square brackets, i.e. "[IPv6]"
185 * writes error message into the buffer on error
183 */ 186 */
184const char *ip_ntoa(const IP *ip); 187const char *ip_ntoa(const IP *ip);
185 188
186/* 189/*
190 * ip_parse_addr
191 * parses IP structure into an address string
192 *
193 * input
194 * ip: ip of AF_INET or AF_INET6 families
195 * length: length of the address buffer
196 * Must be at least INET_ADDRSTRLEN for AF_INET
197 * and INET6_ADDRSTRLEN for AF_INET6
198 *
199 * output
200 * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6)
201 *
202 * returns 1 on success, 0 on failure
203 */
204int ip_parse_addr(const IP *ip, char *address, size_t length);
205
206/*
187 * addr_parse_ip 207 * addr_parse_ip
188 * directly parses the input into an IP structure 208 * directly parses the input into an IP structure
189 * tries IPv4 first, then IPv6 209 * tries IPv4 first, then IPv6
diff --git a/toxcore/tox.c b/toxcore/tox.c
index 3f458ac2..d7f231b5 100644
--- a/toxcore/tox.c
+++ b/toxcore/tox.c
@@ -1020,9 +1020,20 @@ Tox *tox_new(Tox_Options *options)
1020 } else { 1020 } else {
1021 m_options.ipv6enabled = options->ipv6enabled; 1021 m_options.ipv6enabled = options->ipv6enabled;
1022 m_options.udp_disabled = options->udp_disabled; 1022 m_options.udp_disabled = options->udp_disabled;
1023 m_options.proxy_enabled = options->proxy_enabled;
1024 1023
1025 if (m_options.proxy_enabled) { 1024 switch (options->proxy_type) {
1025 case TOX_PROXY_HTTP:
1026 m_options.proxy_info.proxy_type = TCP_PROXY_HTTP;
1027 break;
1028 case TOX_PROXY_SOCKS5:
1029 m_options.proxy_info.proxy_type = TCP_PROXY_SOCKS5;
1030 break;
1031 case TOX_PROXY_NONE:
1032 m_options.proxy_info.proxy_type = TCP_PROXY_NONE;
1033 break;
1034 }
1035
1036 if (m_options.proxy_info.proxy_type != TCP_PROXY_NONE) {
1026 ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled); 1037 ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled);
1027 1038
1028 if (m_options.ipv6enabled) 1039 if (m_options.ipv6enabled)
diff --git a/toxcore/tox.h b/toxcore/tox.h
index 3b72eede..c5a5d952 100644
--- a/toxcore/tox.h
+++ b/toxcore/tox.h
@@ -873,6 +873,12 @@ int tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8_
873 */ 873 */
874int tox_isconnected(const Tox *tox); 874int tox_isconnected(const Tox *tox);
875 875
876typedef enum {
877 TOX_PROXY_NONE,
878 TOX_PROXY_HTTP,
879 TOX_PROXY_SOCKS5
880} TOX_PROXY_TYPE;
881
876typedef struct { 882typedef struct {
877 /* 883 /*
878 * The type of UDP socket created depends on ipv6enabled: 884 * The type of UDP socket created depends on ipv6enabled:
@@ -885,13 +891,11 @@ typedef struct {
885 891
886 /* Set to 1 to disable udp support. (default: 0) 892 /* Set to 1 to disable udp support. (default: 0)
887 This will force Tox to use TCP only which may slow things down. 893 This will force Tox to use TCP only which may slow things down.
888 Disabling udp support is necessary when using anonymous proxies or Tor.*/ 894 Disabling udp support is necessary when using proxies or Tor.*/
889 uint8_t udp_disabled; 895 uint8_t udp_disabled;
890 896 uint8_t proxy_type; /* a value from TOX_PROXY_TYPE */
891 /* Enable proxy support. (only basic TCP socks5 proxy currently supported.) (default: 0 (disabled))*/
892 uint8_t proxy_enabled;
893 char proxy_address[256]; /* Proxy ip or domain in NULL terminated string format. */ 897 char proxy_address[256]; /* Proxy ip or domain in NULL terminated string format. */
894 uint16_t proxy_port; /* Proxy port: in host byte order. */ 898 uint16_t proxy_port; /* Proxy port in host byte order. */
895} Tox_Options; 899} Tox_Options;
896 900
897/* 901/*