diff options
Diffstat (limited to 'toxcore/Lossless_UDP.c')
-rw-r--r-- | toxcore/Lossless_UDP.c | 1168 |
1 files changed, 0 insertions, 1168 deletions
diff --git a/toxcore/Lossless_UDP.c b/toxcore/Lossless_UDP.c deleted file mode 100644 index c0db8a10..00000000 --- a/toxcore/Lossless_UDP.c +++ /dev/null | |||
@@ -1,1168 +0,0 @@ | |||
1 | /* Lossless_UDP.c | ||
2 | * | ||
3 | * An implementation of the Lossless_UDP protocol as seen in http://wiki.tox.im/index.php/Lossless_UDP | ||
4 | * | ||
5 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
6 | * | ||
7 | * This file is part of Tox. | ||
8 | * | ||
9 | * Tox is free software: you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation, either version 3 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * Tox is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * TODO: clean this file a bit. | ||
26 | * There are a couple of useless variables to get rid of. | ||
27 | */ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #include "Lossless_UDP.h" | ||
34 | |||
35 | #define LUDP_CONNECTION_OUTBOUND 0 | ||
36 | #define LUDP_CONNECTION_INBOUND_HANDLED 1 | ||
37 | #define LUDP_CONNECTION_INBOUND 2 | ||
38 | |||
39 | /* Functions */ | ||
40 | |||
41 | /* | ||
42 | * Get connection id from IP_Port. | ||
43 | * | ||
44 | * return -1 if there are no connections like we are looking for. | ||
45 | * return id if it found it. | ||
46 | */ | ||
47 | int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port) | ||
48 | { | ||
49 | tox_array_for_each(&ludp->connections, Connection, tmp) { | ||
50 | if (tmp->status != LUDP_NO_CONNECTION && ipport_equal(&tmp->ip_port, &ip_port)) { | ||
51 | return tmp_i; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | return -1; | ||
56 | } | ||
57 | |||
58 | /* Resize a queue | ||
59 | * return length of queue on success. | ||
60 | * return ~0 on failure. | ||
61 | */ | ||
62 | uint32_t resize_queue(Data **buffer, uint32_t length, uint32_t new_length, uint32_t min_packetnum, | ||
63 | uint32_t max_packetnum) | ||
64 | { | ||
65 | if (MAX_QUEUE_NUM < new_length) | ||
66 | new_length = MAX_QUEUE_NUM; | ||
67 | |||
68 | if (max_packetnum - min_packetnum > new_length) | ||
69 | return ~0; | ||
70 | |||
71 | if (length == new_length) | ||
72 | return new_length; | ||
73 | |||
74 | Data *temp = calloc(1, sizeof(Data) * new_length); | ||
75 | |||
76 | if (temp == NULL) | ||
77 | return ~0; | ||
78 | |||
79 | if (*buffer == NULL) { | ||
80 | *buffer = temp; | ||
81 | return new_length; | ||
82 | } | ||
83 | |||
84 | uint32_t i; | ||
85 | |||
86 | for (i = min_packetnum; i != max_packetnum; ++i) | ||
87 | memcpy(temp + (i % new_length), *buffer + (i % length), sizeof(Data)); | ||
88 | |||
89 | free(*buffer); | ||
90 | *buffer = temp; | ||
91 | return new_length; | ||
92 | } | ||
93 | |||
94 | |||
95 | |||
96 | /* | ||
97 | * Generate a handshake_id which depends on the ip_port. | ||
98 | * This function will always give one unique handshake_id per ip_port. | ||
99 | * | ||
100 | * TODO: make this better | ||
101 | */ | ||
102 | |||
103 | static uint32_t randtable_initget(Lossless_UDP *ludp, uint32_t index, uint8_t value) | ||
104 | { | ||
105 | if (ludp->randtable[index][value] == 0) | ||
106 | ludp->randtable[index][value] = random_int(); | ||
107 | |||
108 | return ludp->randtable[index][value]; | ||
109 | } | ||
110 | |||
111 | static uint32_t handshake_id(Lossless_UDP *ludp, IP_Port source) | ||
112 | { | ||
113 | uint32_t id = 0, i = 0; | ||
114 | |||
115 | uint8_t *uint8; | ||
116 | uint8 = (uint8_t *)&source.port; | ||
117 | id ^= randtable_initget(ludp, i, *uint8); | ||
118 | i++, uint8++; | ||
119 | id ^= randtable_initget(ludp, i, *uint8); | ||
120 | i++; | ||
121 | |||
122 | if (source.ip.family == AF_INET) { | ||
123 | int k; | ||
124 | |||
125 | for (k = 0; k < 4; k++) { | ||
126 | id ^= randtable_initget(ludp, i++, source.ip.ip4.uint8[k]); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | if (source.ip.family == AF_INET6) { | ||
131 | int k; | ||
132 | |||
133 | for (k = 0; k < 16; k++) { | ||
134 | id ^= randtable_initget(ludp, i++, source.ip.ip6.uint8[k]); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /* id can't be zero. */ | ||
139 | if (id == 0) | ||
140 | id = 1; | ||
141 | |||
142 | return id; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * Change the handshake id associated with that ip_port. | ||
147 | * | ||
148 | * TODO: Make this better | ||
149 | */ | ||
150 | static void change_handshake(Lossless_UDP *ludp, IP_Port source) | ||
151 | { | ||
152 | uint8_t rand; | ||
153 | |||
154 | if (source.ip.family == AF_INET) { | ||
155 | rand = random_int() % 4; | ||
156 | } else if (source.ip.family == AF_INET6) { | ||
157 | rand = random_int() % 16; | ||
158 | } else { | ||
159 | return; | ||
160 | } | ||
161 | |||
162 | /* Forced to be more robust against strange definitions of sa_family_t */ | ||
163 | ludp->randtable[2 + rand][((uint8_t *)&source.ip.ip6)[rand]] = random_int(); | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * Initialize a new connection to ip_port | ||
168 | * | ||
169 | * return an integer corresponding to the connection id. | ||
170 | * return -1 if it could not initialize the connectiont | ||
171 | * If there already was an existing connection to that ip_port return its number. | ||
172 | */ | ||
173 | int new_connection(Lossless_UDP *ludp, IP_Port ip_port) | ||
174 | { | ||
175 | int connection_id = getconnection_id(ludp, ip_port); | ||
176 | |||
177 | if (connection_id != -1) { | ||
178 | confirm_connection(ludp, connection_id); | ||
179 | return connection_id; | ||
180 | } | ||
181 | |||
182 | tox_array_for_each(&ludp->connections, Connection, tmp) { | ||
183 | if (tmp->status == LUDP_NO_CONNECTION) { | ||
184 | connection_id = tmp_i; | ||
185 | break; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | if (connection_id == -1) { | ||
190 | if (tox_array_push_ptr(&ludp->connections, 0) == 0) | ||
191 | return -1; | ||
192 | |||
193 | connection_id = ludp->connections.len - 1; | ||
194 | } | ||
195 | |||
196 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
197 | |||
198 | memset(connection, 0, sizeof(Connection)); | ||
199 | |||
200 | uint32_t handshake_id1 = handshake_id(ludp, ip_port); | ||
201 | /* Add randomness to timeout to prevent connections getting stuck in a loop. */ | ||
202 | uint8_t timeout = CONNECTION_TIMEOUT + rand() % CONNECTION_TIMEOUT; | ||
203 | |||
204 | *connection = (Connection) { | ||
205 | .ip_port = ip_port, | ||
206 | .status = LUDP_HANDSHAKE_SENDING, | ||
207 | .inbound = LUDP_CONNECTION_OUTBOUND, | ||
208 | .handshake_id1 = handshake_id1, | ||
209 | .sent_packetnum = handshake_id1, | ||
210 | .sendbuff_packetnum = handshake_id1, | ||
211 | .successful_sent = handshake_id1, | ||
212 | .SYNC_rate = SYNC_RATE, | ||
213 | .data_rate = DATA_SYNC_RATE, | ||
214 | .last_recvSYNC = current_time(), | ||
215 | .last_sent = current_time(), | ||
216 | .killat = ~0, | ||
217 | .send_counter = 0, | ||
218 | .timeout = timeout, | ||
219 | .confirmed = 1 | ||
220 | }; | ||
221 | connection->sendbuffer_length = resize_queue(&connection->sendbuffer, 0, DEFAULT_QUEUE_NUM, 0, 0); | ||
222 | connection->recvbuffer_length = resize_queue(&connection->recvbuffer, 0, DEFAULT_QUEUE_NUM, 0, 0); | ||
223 | |||
224 | if (connection->sendbuffer_length == (uint32_t)~0 || connection->recvbuffer_length == (uint32_t)~0) { | ||
225 | free(connection->sendbuffer); | ||
226 | free(connection->recvbuffer); | ||
227 | memset(connection, 0, sizeof(Connection)); | ||
228 | return -1; | ||
229 | } | ||
230 | |||
231 | return connection_id; | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * Initialize a new inbound connection from ip_port. | ||
236 | * | ||
237 | * return an integer corresponding to the connection id. | ||
238 | * return -1 if it could not initialize the connection. | ||
239 | */ | ||
240 | static int new_inconnection(Lossless_UDP *ludp, IP_Port ip_port) | ||
241 | { | ||
242 | if (getconnection_id(ludp, ip_port) != -1) | ||
243 | return -1; /* TODO: return existing connection instead? */ | ||
244 | |||
245 | int connection_id = -1; | ||
246 | tox_array_for_each(&ludp->connections, Connection, tmp) { | ||
247 | if (tmp->status == LUDP_NO_CONNECTION) { | ||
248 | connection_id = tmp_i; | ||
249 | break; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | if (connection_id == -1) { | ||
254 | if (tox_array_push_ptr(&ludp->connections, 0) == 0) | ||
255 | return -1; | ||
256 | |||
257 | connection_id = ludp->connections.len - 1; | ||
258 | } | ||
259 | |||
260 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
261 | memset(connection, 0, sizeof(Connection)); | ||
262 | /* Add randomness to timeout to prevent connections getting stuck in a loop. */ | ||
263 | uint8_t timeout = CONNECTION_TIMEOUT + rand() % CONNECTION_TIMEOUT; | ||
264 | |||
265 | *connection = (Connection) { | ||
266 | .ip_port = ip_port, | ||
267 | .status = LUDP_NOT_CONFIRMED, | ||
268 | .inbound = LUDP_CONNECTION_INBOUND, | ||
269 | .SYNC_rate = SYNC_RATE, | ||
270 | .data_rate = DATA_SYNC_RATE, | ||
271 | .last_recvSYNC = current_time(), | ||
272 | .last_sent = current_time(), | ||
273 | .send_counter = 127, | ||
274 | |||
275 | .timeout = timeout, | ||
276 | |||
277 | /* If this connection isn't handled within the timeout kill it. */ | ||
278 | .killat = current_time() + 1000000ULL * timeout, | ||
279 | .confirmed = 0 | ||
280 | }; | ||
281 | connection->sendbuffer_length = resize_queue(&connection->sendbuffer, 0, DEFAULT_QUEUE_NUM, 0, 0); | ||
282 | connection->recvbuffer_length = resize_queue(&connection->recvbuffer, 0, DEFAULT_QUEUE_NUM, 0, 0); | ||
283 | |||
284 | if (connection->sendbuffer_length == (uint32_t)~0 || connection->recvbuffer_length == (uint32_t)~0) { | ||
285 | free(connection->sendbuffer); | ||
286 | free(connection->recvbuffer); | ||
287 | memset(connection, 0, sizeof(Connection)); | ||
288 | return -1; | ||
289 | } | ||
290 | |||
291 | return connection_id; | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * return an integer corresponding to the next connection in our incoming connection list with at least numpackets in the recieve queue. | ||
296 | * return -1 if there are no new incoming connections in the list. | ||
297 | */ | ||
298 | int incoming_connection(Lossless_UDP *ludp, uint32_t numpackets) | ||
299 | { | ||
300 | tox_array_for_each(&ludp->connections, Connection, tmp) { | ||
301 | if (tmp->inbound == LUDP_CONNECTION_INBOUND && tmp->recv_packetnum - tmp->successful_read >= numpackets) { | ||
302 | tmp->inbound = LUDP_CONNECTION_INBOUND_HANDLED; | ||
303 | return tmp_i; | ||
304 | } | ||
305 | } | ||
306 | return -1; | ||
307 | } | ||
308 | /* Try to free some memory from the connections array. */ | ||
309 | static void free_connections(Lossless_UDP *ludp) | ||
310 | { | ||
311 | uint32_t i; | ||
312 | |||
313 | for (i = ludp->connections.len; i != 0; --i) { | ||
314 | Connection *connection = &tox_array_get(&ludp->connections, i - 1, Connection); | ||
315 | |||
316 | if (connection->status != LUDP_NO_CONNECTION) | ||
317 | break; | ||
318 | } | ||
319 | |||
320 | if (ludp->connections.len == i) | ||
321 | return; | ||
322 | |||
323 | return tox_array_pop(&ludp->connections, ludp->connections.len - i); | ||
324 | } | ||
325 | /* return -1 if it could not kill the connection. | ||
326 | * return 0 if killed successfully. | ||
327 | */ | ||
328 | int kill_connection(Lossless_UDP *ludp, int connection_id) | ||
329 | { | ||
330 | if ((unsigned int)connection_id < ludp->connections.len) { | ||
331 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
332 | |||
333 | if (connection->status != LUDP_NO_CONNECTION) { | ||
334 | connection->status = LUDP_NO_CONNECTION; | ||
335 | change_handshake(ludp, connection->ip_port); | ||
336 | free(connection->sendbuffer); | ||
337 | free(connection->recvbuffer); | ||
338 | memset(connection, 0, sizeof(Connection)); | ||
339 | free_connections(ludp); | ||
340 | return 0; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | return -1; | ||
345 | } | ||
346 | |||
347 | /* | ||
348 | * timeout connection in seconds. | ||
349 | * | ||
350 | * return -1 if it can not kill the connection. | ||
351 | * return 0 if it will kill it. | ||
352 | */ | ||
353 | int timeout_connection_in(Lossless_UDP *ludp, int connection_id, uint32_t seconds) | ||
354 | { | ||
355 | if ((unsigned int)connection_id < ludp->connections.len) { | ||
356 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
357 | |||
358 | if (connection->status != LUDP_NO_CONNECTION) { | ||
359 | connection->killat = current_time() + 1000000ULL * seconds; | ||
360 | return 0; | ||
361 | } | ||
362 | } | ||
363 | |||
364 | return -1; | ||
365 | } | ||
366 | |||
367 | /* | ||
368 | * Check if connection is connected: | ||
369 | * | ||
370 | * return LUDP_NO_CONNECTION if not. | ||
371 | * return LUDP_HANDSHAKE_SENDING if attempting handshake. | ||
372 | * return LUDP_NOT_CONFIRMED if handshake is done. | ||
373 | * return LUDP_ESTABLISHED if fully connected. | ||
374 | * return LUDP_TIMED_OUT if timed out and waiting to be killed. | ||
375 | */ | ||
376 | int is_connected(Lossless_UDP *ludp, int connection_id) | ||
377 | { | ||
378 | if ((unsigned int)connection_id < ludp->connections.len) | ||
379 | return tox_array_get(&ludp->connections, connection_id, Connection).status; | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | /* Check if connection is confirmed. | ||
385 | * | ||
386 | * returns 1 if yes. | ||
387 | * returns 0 if no/failure. | ||
388 | */ | ||
389 | int connection_confirmed(Lossless_UDP *ludp, int connection_id) | ||
390 | { | ||
391 | if ((unsigned int)connection_id >= ludp->connections.len) | ||
392 | return 0; | ||
393 | |||
394 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
395 | |||
396 | if (connection->status == LUDP_NO_CONNECTION) | ||
397 | return 0; | ||
398 | |||
399 | if (connection->confirmed == 1) | ||
400 | return 1; | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | /* Confirm an incoming connection. | ||
406 | * Also disable the auto kill timeout on incomming connections. | ||
407 | * | ||
408 | * return 0 on success | ||
409 | * return -1 on failure. | ||
410 | */ | ||
411 | int confirm_connection(Lossless_UDP *ludp, int connection_id) | ||
412 | { | ||
413 | if ((unsigned int)connection_id >= ludp->connections.len) | ||
414 | return -1; | ||
415 | |||
416 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
417 | |||
418 | if (connection->status == LUDP_NO_CONNECTION) | ||
419 | return -1; | ||
420 | |||
421 | connection->killat = ~0; | ||
422 | connection->confirmed = 1; | ||
423 | connection->inbound = LUDP_CONNECTION_OUTBOUND; | ||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | /* return the ip_port of the corresponding connection. */ | ||
428 | IP_Port connection_ip(Lossless_UDP *ludp, int connection_id) | ||
429 | { | ||
430 | if ((unsigned int)connection_id < ludp->connections.len) | ||
431 | return tox_array_get(&ludp->connections, connection_id, Connection).ip_port; | ||
432 | |||
433 | IP_Port zero; | ||
434 | ip_reset(&zero.ip); | ||
435 | zero.port = 0; | ||
436 | return zero; | ||
437 | } | ||
438 | |||
439 | /* return the number of packets in the queue waiting to be successfully sent. */ | ||
440 | uint32_t sendqueue(Lossless_UDP *ludp, int connection_id) | ||
441 | { | ||
442 | if ((unsigned int)connection_id >= ludp->connections.len) | ||
443 | return 0; | ||
444 | |||
445 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
446 | |||
447 | if (connection->status == LUDP_NO_CONNECTION) | ||
448 | return 0; | ||
449 | |||
450 | return connection->sendbuff_packetnum - connection->successful_sent; | ||
451 | } | ||
452 | |||
453 | /* return number of packets in all queues waiting to be successfully sent. */ | ||
454 | uint32_t sendqueue_total(Lossless_UDP *ludp) | ||
455 | { | ||
456 | uint32_t i, total = 0; | ||
457 | |||
458 | for (i = 0; i < ludp->connections.len; i++) { | ||
459 | Connection *connection = &tox_array_get(&ludp->connections, i, Connection); | ||
460 | |||
461 | if (connection->status != 0) | ||
462 | total += connection->sendbuff_packetnum - connection->successful_sent; | ||
463 | } | ||
464 | |||
465 | return total; | ||
466 | } | ||
467 | |||
468 | /* return the number of packets in the queue waiting to be successfully read with read_packet(...). */ | ||
469 | uint32_t recvqueue(Lossless_UDP *ludp, int connection_id) | ||
470 | { | ||
471 | if ((unsigned int)connection_id >= ludp->connections.len) | ||
472 | return 0; | ||
473 | |||
474 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
475 | |||
476 | if (connection->status == LUDP_NO_CONNECTION) | ||
477 | return 0; | ||
478 | |||
479 | return connection->recv_packetnum - connection->successful_read; | ||
480 | } | ||
481 | |||
482 | /* return the id of the next packet in the queue. | ||
483 | * return ~0 if no packet in queue. | ||
484 | */ | ||
485 | uint8_t id_packet(Lossless_UDP *ludp, int connection_id) | ||
486 | { | ||
487 | if (recvqueue(ludp, connection_id) == 0) | ||
488 | return ~0; | ||
489 | |||
490 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
491 | |||
492 | if (connection->status != LUDP_NO_CONNECTION) | ||
493 | return connection->recvbuffer[connection->successful_read % connection->recvbuffer_length].data[0]; | ||
494 | |||
495 | return ~0; | ||
496 | } | ||
497 | |||
498 | /* return 0 if there is no received data in the buffer. | ||
499 | * return length of received packet if successful. | ||
500 | */ | ||
501 | int read_packet(Lossless_UDP *ludp, int connection_id, uint8_t *data) | ||
502 | { | ||
503 | if (recvqueue(ludp, connection_id) == 0) | ||
504 | return 0; | ||
505 | |||
506 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
507 | |||
508 | if (connection->status == LUDP_NO_CONNECTION) | ||
509 | return 0; | ||
510 | |||
511 | uint16_t index = connection->successful_read % connection->recvbuffer_length; | ||
512 | uint16_t size = connection->recvbuffer[index].size; | ||
513 | memcpy(data, connection->recvbuffer[index].data, size); | ||
514 | ++connection->successful_read; | ||
515 | connection->recvbuffer[index].size = 0; | ||
516 | return size; | ||
517 | } | ||
518 | |||
519 | /* Like read_packet() but does leaves the queue as is. | ||
520 | * return 0 if there is no received data in the buffer. | ||
521 | * return length of received packet if successful. | ||
522 | */ | ||
523 | int read_packet_silent(Lossless_UDP *ludp, int connection_id, uint8_t *data) | ||
524 | { | ||
525 | if (recvqueue(ludp, connection_id) == 0) | ||
526 | return 0; | ||
527 | |||
528 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
529 | |||
530 | if (connection->status == LUDP_NO_CONNECTION) | ||
531 | return 0; | ||
532 | |||
533 | uint16_t index = connection->successful_read % connection->recvbuffer_length; | ||
534 | uint16_t size = connection->recvbuffer[index].size; | ||
535 | memcpy(data, connection->recvbuffer[index].data, size); | ||
536 | return size; | ||
537 | } | ||
538 | /* Discard the next packet to be read from the queue | ||
539 | * return 0 if success. | ||
540 | * return -1 if failure. | ||
541 | */ | ||
542 | int discard_packet(Lossless_UDP *ludp, int connection_id) | ||
543 | { | ||
544 | if (recvqueue(ludp, connection_id) == 0) | ||
545 | return -1; | ||
546 | |||
547 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
548 | uint16_t index = connection->successful_read % connection->recvbuffer_length; | ||
549 | ++connection->successful_read; | ||
550 | connection->recvbuffer[index].size = 0; | ||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | #define MAX_SYNC_RATE 20 | ||
555 | #define MIN_SLOTS 16 | ||
556 | /* returns the number of packet slots left in the sendbuffer. | ||
557 | * return 0 if failure. | ||
558 | */ | ||
559 | uint32_t num_free_sendqueue_slots(Lossless_UDP *ludp, int connection_id) | ||
560 | { | ||
561 | if ((unsigned int)connection_id >= ludp->connections.len) | ||
562 | return 0; | ||
563 | |||
564 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
565 | uint32_t max_slots = (connection->data_rate / MAX_SYNC_RATE) * 1.5; | ||
566 | |||
567 | if (max_slots > MAX_QUEUE_NUM) | ||
568 | max_slots = MAX_QUEUE_NUM; | ||
569 | |||
570 | if (max_slots < MIN_SLOTS) | ||
571 | max_slots = MIN_SLOTS; | ||
572 | |||
573 | if (sendqueue(ludp, connection_id) > max_slots) | ||
574 | return 0; | ||
575 | |||
576 | return max_slots - sendqueue(ludp, connection_id); | ||
577 | } | ||
578 | |||
579 | |||
580 | /* return 0 if data could not be put in packet queue. | ||
581 | * return 1 if data was put into the queue. | ||
582 | */ | ||
583 | int write_packet(Lossless_UDP *ludp, int connection_id, uint8_t *data, uint32_t length) | ||
584 | { | ||
585 | if ((unsigned int)connection_id >= ludp->connections.len) | ||
586 | return 0; | ||
587 | |||
588 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
589 | |||
590 | if (connection->status == LUDP_NO_CONNECTION) | ||
591 | return 0; | ||
592 | |||
593 | if (length > MAX_DATA_SIZE || length == 0 || sendqueue(ludp, connection_id) >= MAX_QUEUE_NUM) | ||
594 | return 0; | ||
595 | |||
596 | if (num_free_sendqueue_slots(ludp, connection_id) == 0) | ||
597 | return 0; | ||
598 | |||
599 | if (sendqueue(ludp, connection_id) >= connection->sendbuffer_length && connection->sendbuffer_length != 0) { | ||
600 | uint32_t newlen = connection->sendbuffer_length = resize_queue(&connection->sendbuffer, connection->sendbuffer_length, | ||
601 | connection->sendbuffer_length * 2, connection->successful_sent, connection->sendbuff_packetnum); | ||
602 | |||
603 | if (newlen == (uint32_t)~0) | ||
604 | return 0; | ||
605 | |||
606 | connection->sendbuffer_length = newlen; | ||
607 | return write_packet(ludp, connection_id, data, length); | ||
608 | } | ||
609 | |||
610 | uint32_t index = connection->sendbuff_packetnum % connection->sendbuffer_length; | ||
611 | memcpy(connection->sendbuffer[index].data, data, length); | ||
612 | connection->sendbuffer[index].size = length; | ||
613 | connection->sendbuff_packetnum++; | ||
614 | return 1; | ||
615 | } | ||
616 | |||
617 | /* Put the packet numbers the we are missing in requested and return the number. */ | ||
618 | static uint32_t missing_packets(Lossless_UDP *ludp, int connection_id, uint32_t *requested) | ||
619 | { | ||
620 | if ((unsigned int)connection_id >= ludp->connections.len) | ||
621 | return 0; | ||
622 | |||
623 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
624 | |||
625 | /* Don't request packets if the buffer is full. */ | ||
626 | if (recvqueue(ludp, connection_id) >= (connection->recvbuffer_length - 1)) | ||
627 | return 0; | ||
628 | |||
629 | uint32_t number = 0; | ||
630 | uint32_t i; | ||
631 | uint32_t temp; | ||
632 | |||
633 | for (i = connection->recv_packetnum; | ||
634 | i != connection->osent_packetnum; | ||
635 | i++) { | ||
636 | if (connection->recvbuffer[i % connection->recvbuffer_length].size == 0) { | ||
637 | temp = htonl(i); | ||
638 | memcpy(requested + number, &temp, 4); | ||
639 | ++number; | ||
640 | } | ||
641 | |||
642 | if (number >= MAX_REQUESTED_PACKETS) | ||
643 | return number; | ||
644 | } | ||
645 | |||
646 | if (number == 0) | ||
647 | connection->recv_packetnum = connection->osent_packetnum; | ||
648 | |||
649 | return number; | ||
650 | } | ||
651 | |||
652 | /* | ||
653 | * BEGIN Packet sending functions. | ||
654 | * One per packet type. | ||
655 | * See http://wiki.tox.im/index.php/Lossless_UDP for more information. | ||
656 | */ | ||
657 | |||
658 | static int send_handshake(Lossless_UDP *ludp, IP_Port ip_port, uint32_t handshake_id1, uint32_t handshake_id2) | ||
659 | { | ||
660 | uint8_t packet[1 + 4 + 4]; | ||
661 | uint32_t temp; | ||
662 | |||
663 | packet[0] = NET_PACKET_HANDSHAKE; | ||
664 | temp = htonl(handshake_id1); | ||
665 | memcpy(packet + 1, &temp, 4); | ||
666 | temp = htonl(handshake_id2); | ||
667 | memcpy(packet + 5, &temp, 4); | ||
668 | |||
669 | return sendpacket(ludp->net, ip_port, packet, sizeof(packet)); | ||
670 | } | ||
671 | |||
672 | static int send_SYNC(Lossless_UDP *ludp, int connection_id) | ||
673 | { | ||
674 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
675 | uint8_t packet[(MAX_REQUESTED_PACKETS * 4 + 4 + 4 + 2)]; | ||
676 | uint16_t index = 0; | ||
677 | |||
678 | IP_Port ip_port = connection->ip_port; | ||
679 | uint8_t counter = connection->send_counter; | ||
680 | uint32_t recv_packetnum = htonl(connection->recv_packetnum); | ||
681 | uint32_t sent_packetnum = htonl(connection->sent_packetnum); | ||
682 | |||
683 | uint32_t requested[MAX_REQUESTED_PACKETS]; | ||
684 | uint32_t number = missing_packets(ludp, connection_id, requested); | ||
685 | |||
686 | packet[0] = NET_PACKET_SYNC; | ||
687 | index += 1; | ||
688 | memcpy(packet + index, &counter, 1); | ||
689 | index += 1; | ||
690 | memcpy(packet + index, &recv_packetnum, 4); | ||
691 | index += 4; | ||
692 | memcpy(packet + index, &sent_packetnum, 4); | ||
693 | index += 4; | ||
694 | memcpy(packet + index, requested, 4 * number); | ||
695 | |||
696 | return sendpacket(ludp->net, ip_port, packet, (number * 4 + 4 + 4 + 2)); | ||
697 | |||
698 | } | ||
699 | |||
700 | static int send_data_packet(Lossless_UDP *ludp, int connection_id, uint32_t packet_num) | ||
701 | { | ||
702 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
703 | |||
704 | uint32_t index = packet_num % connection->sendbuffer_length; | ||
705 | uint32_t temp; | ||
706 | uint8_t packet[1 + 4 + MAX_DATA_SIZE]; | ||
707 | packet[0] = NET_PACKET_DATA; | ||
708 | temp = htonl(packet_num); | ||
709 | memcpy(packet + 1, &temp, 4); | ||
710 | memcpy(packet + 5, connection->sendbuffer[index].data, connection->sendbuffer[index].size); | ||
711 | return sendpacket(ludp->net, connection->ip_port, packet, 1 + 4 + connection->sendbuffer[index].size); | ||
712 | } | ||
713 | |||
714 | /* Sends 1 data packet. */ | ||
715 | static int send_DATA(Lossless_UDP *ludp, int connection_id) | ||
716 | { | ||
717 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
718 | int ret; | ||
719 | uint32_t buffer[MAX_REQUESTED_PACKETS]; | ||
720 | |||
721 | if (connection->num_req_paquets > 0) { | ||
722 | ret = send_data_packet(ludp, connection_id, connection->req_packets[0]); | ||
723 | connection->num_req_paquets--; | ||
724 | memcpy(buffer, connection->req_packets + 1, connection->num_req_paquets * 4); | ||
725 | memcpy(connection->req_packets, buffer, connection->num_req_paquets * 4); | ||
726 | return ret; | ||
727 | } | ||
728 | |||
729 | if (connection->sendbuff_packetnum != connection->sent_packetnum) { | ||
730 | ret = send_data_packet(ludp, connection_id, connection->sent_packetnum); | ||
731 | connection->sent_packetnum++; | ||
732 | return ret; | ||
733 | } | ||
734 | |||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | /* | ||
739 | * END of packet sending functions. | ||
740 | * | ||
741 | * | ||
742 | * BEGIN Packet handling functions. | ||
743 | * One to handle each type of packets we receive. | ||
744 | */ | ||
745 | |||
746 | |||
747 | /* return 0 if handled correctly. | ||
748 | * return 1 if packet is bad. | ||
749 | */ | ||
750 | static int handle_handshake(void *object, IP_Port source, uint8_t *packet, uint32_t length) | ||
751 | { | ||
752 | Lossless_UDP *ludp = object; | ||
753 | |||
754 | if (length != (1 + 4 + 4)) | ||
755 | return 1; | ||
756 | |||
757 | uint32_t temp; | ||
758 | uint32_t handshake_id1, handshake_id2; | ||
759 | int connection_id = getconnection_id(ludp, source); | ||
760 | |||
761 | memcpy(&temp, packet + 1, 4); | ||
762 | handshake_id1 = ntohl(temp); | ||
763 | memcpy(&temp, packet + 5, 4); | ||
764 | handshake_id2 = ntohl(temp); | ||
765 | |||
766 | |||
767 | if (handshake_id2 == 0 && is_connected(ludp, connection_id) != LUDP_ESTABLISHED && | ||
768 | is_connected(ludp, connection_id) != LUDP_TIMED_OUT) { | ||
769 | send_handshake(ludp, source, handshake_id(ludp, source), handshake_id1); | ||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | if (is_connected(ludp, connection_id) != LUDP_HANDSHAKE_SENDING) | ||
774 | return 1; | ||
775 | |||
776 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
777 | |||
778 | /* if handshake_id2 is what we sent previously as handshake_id1 */ | ||
779 | if (handshake_id2 == connection->handshake_id1) { | ||
780 | connection->status = LUDP_NOT_CONFIRMED; | ||
781 | /* NOTE: Is this necessary? | ||
782 | connection->handshake_id2 = handshake_id1; */ | ||
783 | connection->orecv_packetnum = handshake_id2; | ||
784 | connection->osent_packetnum = handshake_id1; | ||
785 | connection->recv_packetnum = handshake_id1; | ||
786 | connection->successful_read = handshake_id1; | ||
787 | } | ||
788 | |||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | /* return 1 if sync packet is valid. | ||
793 | * return 0 if not. | ||
794 | */ | ||
795 | static int SYNC_valid(uint32_t length) | ||
796 | { | ||
797 | if (length < 4 + 4 + 2) | ||
798 | return 0; | ||
799 | |||
800 | if (length > (MAX_REQUESTED_PACKETS * 4 + 4 + 4 + 2) || | ||
801 | ((length - 4 - 4 - 2) % 4) != 0) | ||
802 | return 0; | ||
803 | |||
804 | return 1; | ||
805 | } | ||
806 | |||
807 | /* case 1 in handle_SYNC: */ | ||
808 | static int handle_SYNC1(Lossless_UDP *ludp, IP_Port source, uint32_t recv_packetnum, uint32_t sent_packetnum) | ||
809 | { | ||
810 | if (handshake_id(ludp, source) == recv_packetnum) { | ||
811 | int connection_id = new_inconnection(ludp, source); | ||
812 | |||
813 | if (connection_id != -1) { | ||
814 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
815 | connection->orecv_packetnum = recv_packetnum; | ||
816 | connection->sent_packetnum = recv_packetnum; | ||
817 | connection->sendbuff_packetnum = recv_packetnum; | ||
818 | connection->successful_sent = recv_packetnum; | ||
819 | connection->osent_packetnum = sent_packetnum; | ||
820 | connection->recv_packetnum = sent_packetnum; | ||
821 | connection->successful_read = sent_packetnum; | ||
822 | |||
823 | return connection_id; | ||
824 | } | ||
825 | } | ||
826 | |||
827 | return -1; | ||
828 | } | ||
829 | |||
830 | /* case 2 in handle_SYNC: */ | ||
831 | static int handle_SYNC2(Lossless_UDP *ludp, int connection_id, uint8_t counter, uint32_t recv_packetnum, | ||
832 | uint32_t sent_packetnum) | ||
833 | { | ||
834 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
835 | |||
836 | if (recv_packetnum == connection->orecv_packetnum && sent_packetnum == connection->osent_packetnum) { | ||
837 | connection->status = LUDP_ESTABLISHED; | ||
838 | connection->recv_counter = counter; | ||
839 | ++connection->send_counter; | ||
840 | send_SYNC(ludp, connection_id); | ||
841 | return 0; | ||
842 | } | ||
843 | |||
844 | return 1; | ||
845 | } | ||
846 | |||
847 | /* | ||
848 | * Automatically adjusts send rates of data packets for optimal transmission. | ||
849 | * | ||
850 | * TODO: Improve this. | ||
851 | */ | ||
852 | static void adjust_datasendspeed(Connection *connection, uint32_t req_packets) | ||
853 | { | ||
854 | /* if there are no packets in send buffer */ | ||
855 | if (connection->sendbuff_packetnum - connection->successful_sent == 0) { | ||
856 | connection->data_rate -= connection->data_rate / 8; | ||
857 | |||
858 | if (connection->data_rate < DATA_SYNC_RATE) | ||
859 | connection->data_rate = DATA_SYNC_RATE; | ||
860 | |||
861 | return; | ||
862 | } | ||
863 | |||
864 | if (req_packets <= (connection->data_rate / connection->SYNC_rate) / 4 || req_packets <= 10) { | ||
865 | connection->data_rate += (connection->data_rate / 4) + 1; | ||
866 | |||
867 | if (connection->data_rate > connection->sendbuffer_length * connection->SYNC_rate) | ||
868 | connection->data_rate = connection->sendbuffer_length * connection->SYNC_rate; | ||
869 | } else { | ||
870 | connection->data_rate -= connection->data_rate / 8; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | |||
875 | /* case 3 in handle_SYNC: */ | ||
876 | static int handle_SYNC3(Lossless_UDP *ludp, int connection_id, uint8_t counter, uint32_t recv_packetnum, | ||
877 | uint32_t sent_packetnum, | ||
878 | uint32_t *req_packets, | ||
879 | uint16_t number) | ||
880 | { | ||
881 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
882 | |||
883 | uint8_t comp_counter = (counter - connection->recv_counter); | ||
884 | uint32_t i, temp; | ||
885 | /* uint32_t comp_1 = (recv_packetnum - connection->successful_sent); | ||
886 | uint32_t comp_2 = (sent_packetnum - connection->successful_read); */ | ||
887 | uint32_t comp_1 = (recv_packetnum - connection->orecv_packetnum); | ||
888 | uint32_t comp_2 = (sent_packetnum - connection->osent_packetnum); | ||
889 | |||
890 | /* Packet valid. */ | ||
891 | if (comp_1 <= connection->sendbuffer_length && | ||
892 | comp_2 <= MAX_QUEUE_NUM && | ||
893 | comp_counter != 0 && comp_counter < 8) { | ||
894 | connection->orecv_packetnum = recv_packetnum; | ||
895 | connection->osent_packetnum = sent_packetnum; | ||
896 | connection->successful_sent = recv_packetnum; | ||
897 | connection->last_recvSYNC = current_time(); | ||
898 | |||
899 | connection->recv_counter = counter; | ||
900 | |||
901 | ++connection->send_counter; | ||
902 | |||
903 | for (i = 0; i < number; ++i) { | ||
904 | temp = ntohl(req_packets[i]); | ||
905 | memcpy(connection->req_packets + i, &temp, sizeof(uint32_t)); | ||
906 | } | ||
907 | |||
908 | connection->num_req_paquets = number; | ||
909 | adjust_datasendspeed(connection, number); | ||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | return 1; | ||
914 | } | ||
915 | |||
916 | static int handle_SYNC(void *object, IP_Port source, uint8_t *packet, uint32_t length) | ||
917 | { | ||
918 | Lossless_UDP *ludp = object; | ||
919 | |||
920 | if (!SYNC_valid(length)) | ||
921 | return 1; | ||
922 | |||
923 | uint8_t counter; | ||
924 | uint32_t temp; | ||
925 | uint32_t recv_packetnum, sent_packetnum; | ||
926 | uint16_t number = (length - 4 - 4 - 2) / 4; | ||
927 | uint32_t req_packets[number]; | ||
928 | |||
929 | memcpy(&counter, packet + 1, 1); | ||
930 | memcpy(&temp, packet + 2, 4); | ||
931 | recv_packetnum = ntohl(temp); | ||
932 | memcpy(&temp, packet + 6, 4); | ||
933 | sent_packetnum = ntohl(temp); | ||
934 | |||
935 | if (number != 0) | ||
936 | memcpy(req_packets, packet + 10, 4 * number); | ||
937 | |||
938 | int connection_id = getconnection_id(ludp, source); | ||
939 | |||
940 | if (connection_id == -1) | ||
941 | return handle_SYNC1(ludp, source, recv_packetnum, sent_packetnum); | ||
942 | |||
943 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
944 | |||
945 | if (connection->status == LUDP_NOT_CONFIRMED) | ||
946 | return handle_SYNC2(ludp, connection_id, counter, | ||
947 | recv_packetnum, sent_packetnum); | ||
948 | |||
949 | if (connection->status == LUDP_ESTABLISHED) | ||
950 | return handle_SYNC3(ludp, connection_id, counter, recv_packetnum, | ||
951 | sent_packetnum, req_packets, number); | ||
952 | |||
953 | return 0; | ||
954 | } | ||
955 | |||
956 | /* | ||
957 | * Add a packet to the received buffer and set the recv_packetnum of the | ||
958 | * connection to its proper value. | ||
959 | * | ||
960 | * return 1 if data was too big. | ||
961 | * return 0 if not. | ||
962 | */ | ||
963 | static int add_recv(Lossless_UDP *ludp, int connection_id, uint32_t data_num, uint8_t *data, uint16_t size) | ||
964 | { | ||
965 | if (size > MAX_DATA_SIZE) | ||
966 | return 1; | ||
967 | |||
968 | Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); | ||
969 | uint32_t i; | ||
970 | uint32_t test = data_num - connection->recv_packetnum; | ||
971 | |||
972 | if (test > MAX_QUEUE_NUM) | ||
973 | return 0; | ||
974 | |||
975 | if (test > connection->recvbuffer_length) { | ||
976 | if (connection->confirmed == 0) | ||
977 | return 0; | ||
978 | |||
979 | uint32_t len = resize_queue(&connection->recvbuffer, connection->recvbuffer_length, test * 2, | ||
980 | connection->successful_read, connection->successful_read + connection->recvbuffer_length); | ||
981 | |||
982 | if (len == (uint32_t)~0) | ||
983 | return 0; | ||
984 | |||
985 | connection->recvbuffer_length = len; | ||
986 | } | ||
987 | |||
988 | uint32_t maxnum = connection->successful_read + connection->recvbuffer_length; | ||
989 | uint32_t sent_packet = data_num - connection->osent_packetnum; | ||
990 | |||
991 | for (i = connection->recv_packetnum; i != maxnum; ++i) { | ||
992 | if (i == data_num) { | ||
993 | memcpy(connection->recvbuffer[data_num % connection->recvbuffer_length].data, data, size); | ||
994 | |||
995 | connection->recvbuffer[data_num % connection->recvbuffer_length].size = size; | ||
996 | connection->last_recvdata = current_time(); | ||
997 | |||
998 | if (sent_packet < connection->recvbuffer_length) | ||
999 | connection->osent_packetnum = data_num; | ||
1000 | |||
1001 | break; | ||
1002 | } | ||
1003 | } | ||
1004 | |||
1005 | for (i = connection->recv_packetnum; i != maxnum; ++i) { | ||
1006 | if (connection->recvbuffer[i % connection->recvbuffer_length].size != 0) | ||
1007 | connection->recv_packetnum = i; | ||
1008 | else | ||
1009 | break; | ||
1010 | } | ||
1011 | |||
1012 | return 0; | ||
1013 | } | ||
1014 | |||
1015 | static int handle_data(void *object, IP_Port source, uint8_t *packet, uint32_t length) | ||
1016 | { | ||
1017 | Lossless_UDP *ludp = object; | ||
1018 | int connection_id = getconnection_id(ludp, source); | ||
1019 | |||
1020 | /* Drop the data packet if connection is not connected. */ | ||
1021 | if (connection_id == -1) | ||
1022 | return 1; | ||
1023 | |||
1024 | if (tox_array_get(&ludp->connections, connection_id, Connection).status != LUDP_ESTABLISHED) | ||
1025 | return 1; | ||
1026 | |||
1027 | if (length > 1 + 4 + MAX_DATA_SIZE || length < 1 + 4 + 1) | ||
1028 | return 1; | ||
1029 | |||
1030 | uint32_t temp; | ||
1031 | uint32_t number; | ||
1032 | uint16_t size = length - 1 - 4; | ||
1033 | |||
1034 | memcpy(&temp, packet + 1, 4); | ||
1035 | number = ntohl(temp); | ||
1036 | |||
1037 | return add_recv(ludp, connection_id, number, packet + 5, size); | ||
1038 | } | ||
1039 | |||
1040 | /* | ||
1041 | * END of packet handling functions. | ||
1042 | */ | ||
1043 | |||
1044 | Lossless_UDP *new_lossless_udp(Networking_Core *net) | ||
1045 | { | ||
1046 | if (net == NULL) | ||
1047 | return NULL; | ||
1048 | |||
1049 | Lossless_UDP *temp = calloc(1, sizeof(Lossless_UDP)); | ||
1050 | |||
1051 | if (temp == NULL) | ||
1052 | return NULL; | ||
1053 | |||
1054 | tox_array_init(&temp->connections, sizeof(Connection)); | ||
1055 | |||
1056 | temp->net = net; | ||
1057 | networking_registerhandler(net, NET_PACKET_HANDSHAKE, &handle_handshake, temp); | ||
1058 | networking_registerhandler(net, NET_PACKET_SYNC, &handle_SYNC, temp); | ||
1059 | networking_registerhandler(net, NET_PACKET_DATA, &handle_data, temp); | ||
1060 | return temp; | ||
1061 | } | ||
1062 | |||
1063 | /* | ||
1064 | * Send handshake requests. | ||
1065 | * Handshake packets are sent at the same rate as SYNC packets. | ||
1066 | */ | ||
1067 | static void do_new(Lossless_UDP *ludp) | ||
1068 | { | ||
1069 | uint64_t temp_time = current_time(); | ||
1070 | |||
1071 | tox_array_for_each(&ludp->connections, Connection, tmp) { | ||
1072 | if (tmp->status == LUDP_HANDSHAKE_SENDING && (tmp->last_sent + (1000000ULL / tmp->SYNC_rate)) <= temp_time) { | ||
1073 | send_handshake(ludp, tmp->ip_port, tmp->handshake_id1, 0); | ||
1074 | tmp->last_sent = temp_time; | ||
1075 | } | ||
1076 | |||
1077 | /* kill all timed out connections */ | ||
1078 | if (tmp->status != LUDP_NO_CONNECTION && (tmp->last_recvSYNC + tmp->timeout * 1000000ULL) < temp_time | ||
1079 | && tmp->status != LUDP_TIMED_OUT) { | ||
1080 | tmp->status = LUDP_TIMED_OUT; | ||
1081 | /* kill_connection(i); */ | ||
1082 | } | ||
1083 | |||
1084 | if (tmp->status != LUDP_NO_CONNECTION && tmp->killat < temp_time) | ||
1085 | tmp->status = LUDP_TIMED_OUT; | ||
1086 | |||
1087 | if (tmp->inbound == LUDP_CONNECTION_INBOUND && tmp->status == LUDP_TIMED_OUT) | ||
1088 | kill_connection(ludp, tmp_i); | ||
1089 | } | ||
1090 | } | ||
1091 | |||
1092 | static void do_SYNC(Lossless_UDP *ludp) | ||
1093 | { | ||
1094 | uint64_t temp_time = current_time(); | ||
1095 | |||
1096 | tox_array_for_each(&ludp->connections, Connection, tmp) { | ||
1097 | if (tmp->status == LUDP_NOT_CONFIRMED || tmp->status == LUDP_ESTABLISHED) | ||
1098 | if ((tmp->last_SYNC + (1000000ULL / tmp->SYNC_rate)) <= temp_time) { | ||
1099 | send_SYNC(ludp, tmp_i); | ||
1100 | tmp->last_SYNC = temp_time; | ||
1101 | } | ||
1102 | } | ||
1103 | } | ||
1104 | |||
1105 | static void do_data(Lossless_UDP *ludp) | ||
1106 | { | ||
1107 | uint64_t j; | ||
1108 | uint64_t temp_time = current_time(); | ||
1109 | |||
1110 | tox_array_for_each(&ludp->connections, Connection, tmp) { | ||
1111 | if (tmp->status == LUDP_ESTABLISHED && sendqueue(ludp, tmp_i) != 0 && | ||
1112 | (tmp->last_sent + (1000000ULL / tmp->data_rate)) <= temp_time) { | ||
1113 | for (j = tmp->last_sent; j < temp_time; j += (1000000ULL / tmp->data_rate)) | ||
1114 | if (send_DATA(ludp, tmp_i) <= 0) | ||
1115 | break; | ||
1116 | |||
1117 | tmp->last_sent = temp_time; | ||
1118 | |||
1119 | } | ||
1120 | } | ||
1121 | } | ||
1122 | |||
1123 | |||
1124 | |||
1125 | /* | ||
1126 | * Automatically adjusts send rates of packets for optimal transmission. | ||
1127 | * | ||
1128 | * TODO: Flow control. | ||
1129 | */ | ||
1130 | static void adjust_rates(Lossless_UDP *ludp) | ||
1131 | { | ||
1132 | uint64_t temp_time = current_time(); | ||
1133 | |||
1134 | tox_array_for_each(&ludp->connections, Connection, tmp) { | ||
1135 | if (tmp->status == LUDP_HANDSHAKE_SENDING || tmp->status == LUDP_NOT_CONFIRMED) | ||
1136 | tmp->SYNC_rate = MAX_SYNC_RATE; | ||
1137 | |||
1138 | if (tmp->status == LUDP_ESTABLISHED) { | ||
1139 | if (sendqueue(ludp, tmp_i) != 0) { | ||
1140 | tmp->SYNC_rate = MAX_SYNC_RATE; | ||
1141 | } else if (tmp->last_recvdata + 200000ULL > temp_time) { /* 200 ms */ | ||
1142 | tmp->SYNC_rate = MAX_SYNC_RATE; | ||
1143 | } else { | ||
1144 | tmp->SYNC_rate = SYNC_RATE; | ||
1145 | } | ||
1146 | } | ||
1147 | } | ||
1148 | } | ||
1149 | |||
1150 | /* Call this function a couple times per second. It is the main loop. */ | ||
1151 | void do_lossless_udp(Lossless_UDP *ludp) | ||
1152 | { | ||
1153 | do_new(ludp); | ||
1154 | do_SYNC(ludp); | ||
1155 | do_data(ludp); | ||
1156 | adjust_rates(ludp); | ||
1157 | } | ||
1158 | |||
1159 | void kill_lossless_udp(Lossless_UDP *ludp) | ||
1160 | { | ||
1161 | uint32_t i; | ||
1162 | |||
1163 | for (i = 0; i < ludp->connections.len; ++i) | ||
1164 | kill_connection(ludp, i); | ||
1165 | |||
1166 | tox_array_delete(&ludp->connections); | ||
1167 | free(ludp); | ||
1168 | } | ||