diff options
-rw-r--r-- | docs/TCP_Network.txt | 2 | ||||
-rw-r--r-- | toxcore/TCP_server.c | 309 | ||||
-rw-r--r-- | toxcore/TCP_server.h | 68 |
3 files changed, 379 insertions, 0 deletions
diff --git a/docs/TCP_Network.txt b/docs/TCP_Network.txt index b9215943..ce52b8e9 100644 --- a/docs/TCP_Network.txt +++ b/docs/TCP_Network.txt | |||
@@ -78,6 +78,8 @@ received | |||
78 | client sent the server the public key and the public key we sent to the client, | 78 | client sent the server the public key and the public key we sent to the client, |
79 | the next with base nonce + 1...) | 79 | the next with base nonce + 1...) |
80 | 80 | ||
81 | The connection is set to an unconfirmed state until a packet is recieved and | ||
82 | decrypted correctly using the information in the handshake. | ||
81 | 83 | ||
82 | each packet sent to/from the server has an id (the first byte of the plain text | 84 | each packet sent to/from the server has an id (the first byte of the plain text |
83 | data of the packet.) | 85 | data of the packet.) |
diff --git a/toxcore/TCP_server.c b/toxcore/TCP_server.c new file mode 100644 index 00000000..2e3f3996 --- /dev/null +++ b/toxcore/TCP_server.c | |||
@@ -0,0 +1,309 @@ | |||
1 | /* | ||
2 | * TCP_server.c -- Implementation of the TCP relay server part of Tox. | ||
3 | * | ||
4 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
5 | * | ||
6 | * This file is part of Tox. | ||
7 | * | ||
8 | * Tox is free software: you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation, either version 3 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * Tox is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include "TCP_server.h" | ||
24 | |||
25 | #if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32) | ||
26 | #include <sys/ioctl.h> | ||
27 | #endif | ||
28 | |||
29 | /* return 1 if valid | ||
30 | * return 0 if not valid | ||
31 | */ | ||
32 | static int sock_valid(sock_t sock) | ||
33 | { | ||
34 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
35 | |||
36 | if (sock == INVALID_SOCKET) { | ||
37 | #else | ||
38 | |||
39 | if (sock < 0) { | ||
40 | #endif | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | return 1; | ||
45 | } | ||
46 | |||
47 | static void kill_sock(sock_t sock) | ||
48 | { | ||
49 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
50 | closesocket(sock); | ||
51 | #else | ||
52 | close(sock); | ||
53 | #endif | ||
54 | } | ||
55 | |||
56 | /* return 1 on success | ||
57 | * return 0 on failure | ||
58 | */ | ||
59 | static int set_nonblock(sock_t sock) | ||
60 | { | ||
61 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
62 | u_long mode = 1; | ||
63 | return (ioctlsocket(sock, FIONBIO, &mode) == 0); | ||
64 | #else | ||
65 | return (fcntl(sock, F_SETFL, O_NONBLOCK, 1) == 0); | ||
66 | #endif | ||
67 | } | ||
68 | |||
69 | /* return 1 on success | ||
70 | * return 0 on failure | ||
71 | */ | ||
72 | static int set_dualstack(sock_t sock) | ||
73 | { | ||
74 | char ipv6only = 0; | ||
75 | socklen_t optsize = sizeof(ipv6only); | ||
76 | int res = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, &optsize); | ||
77 | |||
78 | if ((res == 0) && (ipv6only == 0)) | ||
79 | return 1; | ||
80 | |||
81 | ipv6only = 0; | ||
82 | return (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only)) == 0); | ||
83 | } | ||
84 | |||
85 | /* return 1 on success | ||
86 | * return 0 on failure | ||
87 | */ | ||
88 | static int bind_to_port(sock_t sock, int family, uint16_t port) | ||
89 | { | ||
90 | struct sockaddr_storage addr = {0}; | ||
91 | size_t addrsize; | ||
92 | |||
93 | if (family == AF_INET) { | ||
94 | struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; | ||
95 | |||
96 | addrsize = sizeof(struct sockaddr_in); | ||
97 | addr4->sin_family = AF_INET; | ||
98 | addr4->sin_port = htons(port); | ||
99 | } else if (family == AF_INET6) { | ||
100 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; | ||
101 | |||
102 | addrsize = sizeof(struct sockaddr_in6); | ||
103 | addr6->sin6_family = AF_INET6; | ||
104 | addr6->sin6_port = htons(port); | ||
105 | } else { | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | return (bind(sock, (struct sockaddr *)&addr, addrsize) == 0); | ||
110 | } | ||
111 | |||
112 | /* return length on success | ||
113 | * return 0 if nothing has been read from socket. | ||
114 | * return ~0 on failure. | ||
115 | */ | ||
116 | static uint16_t read_length(sock_t sock) | ||
117 | { | ||
118 | int count; | ||
119 | ioctl(sock, FIONREAD, &count); | ||
120 | |||
121 | if (count >= sizeof(uint16_t)) { | ||
122 | uint16_t length; | ||
123 | int len = recv(sock, &length, sizeof(uint16_t), 0); | ||
124 | |||
125 | if (len != sizeof(uint16_t)) { | ||
126 | fprintf(stderr, "FAIL recv packet\n"); | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | length = ntohs(length); | ||
131 | |||
132 | if (length > MAX_PACKET_SIZE) { | ||
133 | return ~0; | ||
134 | } | ||
135 | |||
136 | return length; | ||
137 | } | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | /* return length on success | ||
143 | * return -1 on failure | ||
144 | */ | ||
145 | static int read_TCP_packet(sock_t sock, uint8_t *data, uint16_t length) | ||
146 | { | ||
147 | int count; | ||
148 | ioctl(sock, FIONREAD, &count); | ||
149 | |||
150 | if (count >= length) { | ||
151 | int len = recv(sock, data, length, 0); | ||
152 | |||
153 | if (len != length) { | ||
154 | fprintf(stderr, "FAIL recv packet\n"); | ||
155 | return -1; | ||
156 | } | ||
157 | |||
158 | return length; | ||
159 | } | ||
160 | |||
161 | return -1; | ||
162 | } | ||
163 | |||
164 | /* return 0 if everything went well. | ||
165 | * return -1 if the connection must be killed. | ||
166 | */ | ||
167 | static int handle_TCP_handshake(TCP_Secure_Connection *con, uint8_t *data, uint16_t length) | ||
168 | { | ||
169 | |||
170 | } | ||
171 | |||
172 | /* return 0 if everything went well. | ||
173 | * return -1 if the connection must be killed. | ||
174 | */ | ||
175 | static int read_connection_handshake(TCP_Secure_Connection *con) | ||
176 | { | ||
177 | int ok = 1; | ||
178 | |||
179 | while (1) { | ||
180 | if (con->next_packet_length == 0) { | ||
181 | uint16_t len = read_length(con->sock); | ||
182 | |||
183 | if (len == 0) | ||
184 | break; | ||
185 | |||
186 | if (len != TCP_SERVER_HANDSHAKE_SIZE) | ||
187 | return -1; | ||
188 | |||
189 | con->next_packet_length = len; | ||
190 | } else { | ||
191 | uint8_t data[con->next_packet_length]; | ||
192 | |||
193 | if (read_TCP_packet(con->sock, data, con->next_packet_length) != -1) { | ||
194 | return handle_TCP_handshake(con, data, con->next_packet_length); | ||
195 | } else { | ||
196 | break; | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | } | ||
201 | |||
202 | /* return 1 on success | ||
203 | * return 0 on failure | ||
204 | */ | ||
205 | static int accept_connection(TCP_Server *TCP_server, sock_t sock) | ||
206 | { | ||
207 | if (!sock_valid(sock)) | ||
208 | return 0; | ||
209 | |||
210 | if (!set_nonblock(sock)) { | ||
211 | kill_sock(sock); | ||
212 | return 0; | ||
213 | }//TODO | ||
214 | |||
215 | printf("accepted %u\n", sock); | ||
216 | |||
217 | return 1; | ||
218 | } | ||
219 | |||
220 | static sock_t new_listening_TCP_socket(int family, uint16_t port) | ||
221 | { | ||
222 | sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP); | ||
223 | |||
224 | if (!sock_valid(sock)) { | ||
225 | return ~0; | ||
226 | } | ||
227 | |||
228 | int ok = set_nonblock(sock); | ||
229 | |||
230 | if (ok && family == AF_INET6) { | ||
231 | ok = set_dualstack(sock); | ||
232 | } | ||
233 | |||
234 | ok = ok && bind_to_port(sock, family, port) && (listen(sock, TCP_MAX_BACKLOG) == 0); | ||
235 | |||
236 | if (!ok) { | ||
237 | kill_sock(sock); | ||
238 | return ~0; | ||
239 | } | ||
240 | |||
241 | return sock; | ||
242 | } | ||
243 | |||
244 | TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t *ports) | ||
245 | { | ||
246 | if (num_sockets == 0 || ports == NULL) | ||
247 | return NULL; | ||
248 | |||
249 | TCP_Server *temp = calloc(1, sizeof(Networking_Core)); | ||
250 | |||
251 | if (temp == NULL) | ||
252 | return NULL; | ||
253 | |||
254 | temp->socks_listening = calloc(num_sockets, sizeof(sock_t)); | ||
255 | |||
256 | if (temp->socks_listening == NULL) { | ||
257 | free(temp); | ||
258 | return NULL; | ||
259 | } | ||
260 | |||
261 | uint8_t family; | ||
262 | |||
263 | if (ipv6_enabled) { | ||
264 | family = AF_INET6; | ||
265 | } else { | ||
266 | family = AF_INET; | ||
267 | } | ||
268 | |||
269 | uint32_t i; | ||
270 | |||
271 | for (i = 0; i < num_sockets; ++i) { | ||
272 | sock_t sock = new_listening_TCP_socket(family, ports[i]); | ||
273 | |||
274 | if (sock_valid(sock)) { | ||
275 | temp->socks_listening[temp->num_listening_socks] = sock; | ||
276 | ++temp->num_listening_socks; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | return temp; | ||
281 | } | ||
282 | |||
283 | void do_TCP_server(TCP_Server *TCP_server) | ||
284 | { | ||
285 | uint32_t i; | ||
286 | |||
287 | for (i = 0; i < TCP_server->num_listening_socks; ++i) { | ||
288 | struct sockaddr_storage addr; | ||
289 | int addrlen = sizeof(addr); | ||
290 | sock_t sock; | ||
291 | |||
292 | do { | ||
293 | sock = accept(TCP_server->socks_listening[i], (struct sockaddr *)&addr, &addrlen); | ||
294 | //TODO | ||
295 | } while (accept_connection(TCP_server, sock)); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | void kill_TCP_server(TCP_Server *TCP_server) | ||
300 | { | ||
301 | uint32_t i; | ||
302 | |||
303 | for (i = 0; i < TCP_server->num_listening_socks; ++i) { | ||
304 | kill_sock(TCP_server->socks_listening[i]); | ||
305 | } | ||
306 | |||
307 | free(TCP_server->socks_listening); | ||
308 | free(TCP_server); | ||
309 | } | ||
diff --git a/toxcore/TCP_server.h b/toxcore/TCP_server.h new file mode 100644 index 00000000..d2c32fda --- /dev/null +++ b/toxcore/TCP_server.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * TCP_server.h -- Implementation of the TCP relay server part of Tox. | ||
3 | * | ||
4 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
5 | * | ||
6 | * This file is part of Tox. | ||
7 | * | ||
8 | * Tox is free software: you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation, either version 3 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * Tox is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include "net_crypto.h" | ||
24 | |||
25 | #define TCP_MAX_BACKLOG 128 | ||
26 | |||
27 | #define MAX_PACKET_SIZE 8192 | ||
28 | |||
29 | #define MAX_INCOMMING_CONNECTIONS 32 | ||
30 | |||
31 | #define TCP_SERVER_HANDSHAKE_SIZE (crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_MACBYTES) | ||
32 | #define TCP_CLIENT_HANDSHAKE_SIZE (crypto_box_PUBLICKEYBYTES + TCP_SERVER_HANDSHAKE_SIZE) | ||
33 | |||
34 | enum { | ||
35 | TCP_STATUS_NO_STATUS, | ||
36 | TCP_STATUS_CONNECTED, | ||
37 | TCP_STATUS_UNCONFIRMED, | ||
38 | TCP_STATUS_CONFIRMED, | ||
39 | }; | ||
40 | |||
41 | typedef struct { | ||
42 | uint8_t status; | ||
43 | sock_t sock; | ||
44 | uint8_t public_key[crypto_box_PUBLICKEYBYTES]; | ||
45 | uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */ | ||
46 | uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* Nonce of sent packets. */ | ||
47 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | ||
48 | uint16_t next_packet_length; | ||
49 | } TCP_Secure_Connection; | ||
50 | |||
51 | typedef struct { | ||
52 | sock_t *socks_listening; | ||
53 | unsigned int num_listening_socks; | ||
54 | |||
55 | TCP_Secure_Connection incomming_connection_queue[MAX_INCOMMING_CONNECTIONS]; | ||
56 | } TCP_Server; | ||
57 | |||
58 | /* Create new TCP server instance. | ||
59 | */ | ||
60 | TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t *ports); | ||
61 | |||
62 | /* Run the TCP_server | ||
63 | */ | ||
64 | void do_TCP_server(TCP_Server *TCP_server); | ||
65 | |||
66 | /* Kill the TCP server | ||
67 | */ | ||
68 | void kill_TCP_server(TCP_Server *TCP_server); | ||