summaryrefslogtreecommitdiff
path: root/toxcore/Lossless_UDP.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxcore/Lossless_UDP.c')
-rw-r--r--toxcore/Lossless_UDP.c1168
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 */
47int 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 */
62uint32_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
103static 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
111static 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 */
150static 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 */
173int 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 */
240static 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 */
298int 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. */
309static 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 */
328int 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 */
353int 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 */
376int 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 */
389int 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 */
411int 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. */
428IP_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. */
440uint32_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. */
454uint32_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(...). */
469uint32_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 */
485uint8_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 */
501int 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 */
523int 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 */
542int 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 */
559uint32_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 */
583int 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. */
618static 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
658static 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
672static 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
700static 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. */
715static 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 */
750static 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 */
795static 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: */
808static 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: */
831static 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 */
852static 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: */
876static 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
916static 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 */
963static 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
1015static 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
1044Lossless_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 */
1067static 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
1092static 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
1105static 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 */
1130static 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. */
1151void 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
1159void 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}