summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2013-06-29 18:40:41 -0400
committerirungentoo <irungentoo@gmail.com>2013-06-29 18:40:41 -0400
commit6bd24212ee41d87a011733974bdc76bd04e60037 (patch)
tree15e84e325573726bef7640a7eb6415630aae6bd9 /core
parent7f2d4bb05bbdf459e3c063db4cebec40acab9e55 (diff)
Lossless UDP now works.
The testclient and testserver simulate a packet loss of 33%. The only thing left to do in lossless UDP is the flow control (automatic adjustment of the data send rate) which is only needed to transfer large amounts of data.
Diffstat (limited to 'core')
-rw-r--r--core/Lossless_UDP.c251
-rw-r--r--core/Lossless_UDP.h23
2 files changed, 216 insertions, 58 deletions
diff --git a/core/Lossless_UDP.c b/core/Lossless_UDP.c
index 7ef818e8..82a0493f 100644
--- a/core/Lossless_UDP.c
+++ b/core/Lossless_UDP.c
@@ -2,18 +2,38 @@
2* 2*
3* An implementation of the Lossless_UDP protocol as seen in docs/Lossless_UDP.txt 3* An implementation of the Lossless_UDP protocol as seen in docs/Lossless_UDP.txt
4* 4*
5
6 Copyright (C) 2013 Tox project All Rights Reserved.
7
8 This file is part of Tox.
9
10 Tox is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 Tox is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with Tox. If not, see <http://www.gnu.org/licenses/>.
22
5*/ 23*/
6 24
7#include "Lossless_UDP.h" 25#include "Lossless_UDP.h"
8 26
27
28
9 //maximum data packets in sent and recieve queues. 29 //maximum data packets in sent and recieve queues.
10#define MAX_QUEUE_NUM 32 30#define MAX_QUEUE_NUM 32
11 31
12//maximum length of the data in the data packets 32//maximum length of the data in the data packets
13#define PDATA_SIZE 1024 33#define MAX_DATA_SIZE 1024
14 34
15//maximum number of data packets that can be sent/recieved at the same time 35//maximum number of data packets in the buffer
16#define MAX_PACKET_NUM (MAX_QUEUE_NUM/4) 36#define BUFFER_PACKET_NUM MAX_QUEUE_NUM
17 37
18//Lossless UDP connection timeout. 38//Lossless UDP connection timeout.
19#define CONNEXION_TIMEOUT 10 39#define CONNEXION_TIMEOUT 10
@@ -21,12 +41,12 @@
21//initial amount of sync/hanshake packets to send per second. 41//initial amount of sync/hanshake packets to send per second.
22#define SYNC_RATE 5 42#define SYNC_RATE 5
23 43
24//send rate of sync packets when data is being sent/recieved. 44//initial send rate of sync packets when data is being sent/recieved.
25#define DATA_SYNC_RATE 20 45#define DATA_SYNC_RATE 20
26 46
27typedef struct 47typedef struct
28{ 48{
29 char data[PDATA_SIZE]; 49 char data[MAX_DATA_SIZE];
30 uint16_t size; 50 uint16_t size;
31}Data; 51}Data;
32 52
@@ -56,7 +76,7 @@ typedef struct
56 uint32_t sendbuff_packetnum; //number of latest packet written onto the sendbuffer 76 uint32_t sendbuff_packetnum; //number of latest packet written onto the sendbuffer
57 uint32_t successful_sent;//we know all packets before that number were successfully sent 77 uint32_t successful_sent;//we know all packets before that number were successfully sent
58 uint32_t successful_read;//packet number of last packet read with the read_packet function 78 uint32_t successful_read;//packet number of last packet read with the read_packet function
59 uint32_t req_packets[MAX_PACKET_NUM]; //list of currently requested packet numbers(by the other person) 79 uint32_t req_packets[BUFFER_PACKET_NUM]; //list of currently requested packet numbers(by the other person)
60 uint16_t num_req_paquets; //total number of currently requested packets(by the other person) 80 uint16_t num_req_paquets; //total number of currently requested packets(by the other person)
61 uint8_t recv_counter; 81 uint8_t recv_counter;
62 uint8_t send_counter; 82 uint8_t send_counter;
@@ -83,6 +103,9 @@ int new_connection(IP_Port ip_port)
83 connections[i].status = 1; 103 connections[i].status = 1;
84 connections[i].inbound = 0; 104 connections[i].inbound = 0;
85 connections[i].handshake_id1 = random_int(); 105 connections[i].handshake_id1 = random_int();
106 connections[i].sent_packetnum = connections[i].handshake_id1;
107 connections[i].sendbuff_packetnum = connections[i].handshake_id1;
108 connections[i].successful_sent = connections[i].handshake_id1;
86 connections[i].SYNC_rate = SYNC_RATE; 109 connections[i].SYNC_rate = SYNC_RATE;
87 connections[i].data_rate = DATA_SYNC_RATE; 110 connections[i].data_rate = DATA_SYNC_RATE;
88 connections[i].last_recv = current_time(); 111 connections[i].last_recv = current_time();
@@ -144,11 +167,41 @@ int kill_connection(int connection_id)
144 return -1; 167 return -1;
145} 168}
146 169
170//check if connection is connected
171//return 0 no.
172//return 1 if attempting handshake
173//return 2 if handshake is done
174//return 3 if fully connected
175int is_connected(int connection_id)
176{
177 return connections[connection_id].status;
178}
179
180//returns the number of packets in the queue waiting to be successfully sent.
181uint32_t sendqueue(int connection_id)
182{
183 return connections[connection_id].sendbuff_packetnum - connections[connection_id].successful_sent;
184}
185
186//returns the number of packets in the queue waiting to be successfully read with read_packet(...)
187uint32_t recvqueue(int connection_id)
188{
189 return connections[connection_id].recv_packetnum - connections[connection_id].successful_read;
190}
191
147//return 0 if there is no received data in the buffer. 192//return 0 if there is no received data in the buffer.
148//return length of received packet if successful 193//return length of received packet if successful
149int read_packet(int connection_id, char * data) 194int read_packet(int connection_id, char * data)
150{ 195{
151 196 if(recvqueue(connection_id) != 0)
197 {
198 uint16_t index = connections[connection_id].successful_read % MAX_QUEUE_NUM;
199 uint16_t size = connections[connection_id].recvbuffer[index].size;
200 memcpy(data, connections[connection_id].recvbuffer[index].data, size);
201 connections[connection_id].successful_read++;
202 connections[connection_id].recvbuffer[index].size = 0;
203 return size;
204 }
152 return 0; 205 return 0;
153} 206}
154 207
@@ -156,34 +209,27 @@ int read_packet(int connection_id, char * data)
156//return 1 if data was put into the queue 209//return 1 if data was put into the queue
157int write_packet(int connection_id, char * data, uint32_t length) 210int write_packet(int connection_id, char * data, uint32_t length)
158{ 211{
159 212 if(length > MAX_DATA_SIZE)
160 213 {
214 return 0;
215 }
216 if(length == 0)
217 {
218 return 0;
219 }
220 if(sendqueue(connection_id) < MAX_QUEUE_NUM)
221 {
222 uint32_t index = connections[connection_id].sendbuff_packetnum % MAX_QUEUE_NUM;
223 memcpy(connections[connection_id].sendbuffer[index].data, data, length);
224 connections[connection_id].sendbuffer[index].size = length;
225 connections[connection_id].sendbuff_packetnum++;
226 return 1;
227 }
161 return 0; 228 return 0;
162} 229}
163 230
164 231
165 232
166//returns the number of packets in the queue waiting to be successfully sent.
167int sendqueue(int connection_id)
168{
169 return connections[connection_id].sendbuff_packetnum - connections[connection_id].successful_sent;
170}
171
172//returns the number of packets in the queue waiting to be successfully read with read_packet(...)
173int recvqueue(int connection_id)
174{
175 return connections[connection_id].recv_packetnum - connections[connection_id].successful_read;
176}
177
178//check if connection is connected
179//return 0 no.
180//return 1 if attempting handshake
181//return 2 if handshake is done
182//return 3 if fully connected
183int is_connected(int connection_id)
184{
185 return connections[connection_id].status;
186}
187 233
188//put the packet numbers the we are missing in requested and return the number 234//put the packet numbers the we are missing in requested and return the number
189uint32_t missing_packets(int connection_id, uint32_t * requested) 235uint32_t missing_packets(int connection_id, uint32_t * requested)
@@ -194,10 +240,14 @@ uint32_t missing_packets(int connection_id, uint32_t * requested)
194 { 240 {
195 if(connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size == 0) 241 if(connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size == 0)
196 { 242 {
197 memcpy(requested, &i, number); 243 memcpy(requested + number, &i, 4);
198 number++; 244 number++;
199 } 245 }
200 } 246 }
247 if(number == 0)
248 {
249 connections[connection_id].recv_packetnum = connections[connection_id].osent_packetnum;
250 }
201 return number; 251 return number;
202 252
203} 253}
@@ -221,14 +271,14 @@ int send_handshake(IP_Port ip_port, uint32_t handshake_id1, uint32_t handshake_i
221int send_SYNC(uint32_t connection_id) 271int send_SYNC(uint32_t connection_id)
222{ 272{
223 273
224 char packet[(MAX_PACKET_NUM*4 + 4 + 4 + 2)]; 274 char packet[(BUFFER_PACKET_NUM*4 + 4 + 4 + 2)];
225 uint16_t index = 0; 275 uint16_t index = 0;
226 276
227 IP_Port ip_port = connections[connection_id].ip_port; 277 IP_Port ip_port = connections[connection_id].ip_port;
228 uint8_t counter = connections[connection_id].send_counter; 278 uint8_t counter = connections[connection_id].send_counter;
229 uint32_t recv_packetnum = connections[connection_id].recv_packetnum; 279 uint32_t recv_packetnum = connections[connection_id].recv_packetnum;
230 uint32_t sent_packetnum = connections[connection_id].sent_packetnum; 280 uint32_t sent_packetnum = connections[connection_id].sent_packetnum;
231 uint32_t requested[MAX_PACKET_NUM]; 281 uint32_t requested[BUFFER_PACKET_NUM];
232 uint32_t number = missing_packets(connection_id, requested); 282 uint32_t number = missing_packets(connection_id, requested);
233 283
234 packet[0] = 17; 284 packet[0] = 17;
@@ -245,21 +295,39 @@ int send_SYNC(uint32_t connection_id)
245 295
246} 296}
247 297
248 298int send_data_packet(uint32_t connection_id, uint32_t packet_num)
249int send_data(IP_Port ip_port, uint32_t packet_num, char * data, uint32_t length)
250{ 299{
251 if(length > PDATA_SIZE) 300 uint32_t index = packet_num % MAX_QUEUE_NUM;
252 { 301 char packet[1 + 4 + MAX_DATA_SIZE];
253 return -1;
254 }
255 char packet[1 + 4 + PDATA_SIZE];
256
257 packet[0] = 18; 302 packet[0] = 18;
258 memcpy(packet + 1, &packet_num, 4); 303 memcpy(packet + 1, &packet_num, 4);
259 memcpy(packet + 5, data, length); 304 memcpy(packet + 5, connections[connection_id].sendbuffer[index].data,
260 return sendpacket(ip_port, packet, 1 + 4 + length); 305 connections[connection_id].sendbuffer[index].size);
306 return sendpacket(connections[connection_id].ip_port, packet,
307 1 + 4 + connections[connection_id].sendbuffer[index].size);
261} 308}
262 309
310//sends 1 data packet
311int send_DATA(uint32_t connection_id)
312{
313 int ret;
314 uint32_t buffer[BUFFER_PACKET_NUM];
315 if(connections[connection_id].num_req_paquets > 0)
316 {
317 ret = send_data_packet(connection_id, connections[connection_id].req_packets[0]);
318 connections[connection_id].num_req_paquets--;
319 memcpy(buffer, connections[connection_id].req_packets + 1, connections[connection_id].num_req_paquets * 4);
320 memcpy(connections[connection_id].req_packets, buffer, connections[connection_id].num_req_paquets * 4);
321 return ret;
322 }
323 if(connections[connection_id].sendbuff_packetnum != connections[connection_id].sent_packetnum)
324 {
325 ret = send_data_packet(connection_id, connections[connection_id].sent_packetnum);
326 connections[connection_id].sent_packetnum++;
327 return ret;
328 }
329 return 0;
330}
263 331
264//END of packet sending functions 332//END of packet sending functions
265 333
@@ -281,7 +349,7 @@ int getconnection_id(IP_Port ip_port)
281} 349}
282 350
283//table of random numbers used below. 351//table of random numbers used below.
284uint32_t randtable[6][256]; 352static uint32_t randtable[6][256];
285 353
286 354
287//generate a handshake_id which depends on the ip_port. 355//generate a handshake_id which depends on the ip_port.
@@ -333,9 +401,9 @@ int handle_handshake(char * packet, uint32_t length, IP_Port source)
333 //NOTE:is this necessary? 401 //NOTE:is this necessary?
334 //connections[connection].handshake_id2 = handshake_id2; 402 //connections[connection].handshake_id2 = handshake_id2;
335 connections[connection].orecv_packetnum = handshake_id1; 403 connections[connection].orecv_packetnum = handshake_id1;
336 connections[connection].sent_packetnum = handshake_id1;
337 connections[connection].osent_packetnum = handshake_id2; 404 connections[connection].osent_packetnum = handshake_id2;
338 connections[connection].recv_packetnum = handshake_id2; 405 connections[connection].recv_packetnum = handshake_id2;
406 connections[connection].successful_read = handshake_id2;
339 } 407 }
340 return 0; 408 return 0;
341 409
@@ -349,7 +417,7 @@ int SYNC_valid(uint32_t length)
349 { 417 {
350 return 0; 418 return 0;
351 } 419 }
352 if(length > (MAX_PACKET_NUM*4 + 4 + 4 + 2) || 420 if(length > (BUFFER_PACKET_NUM*4 + 4 + 4 + 2) ||
353 ((length - 4 - 4 - 2) % 4) != 0) 421 ((length - 4 - 4 - 2) % 4) != 0)
354 { 422 {
355 return 0; 423 return 0;
@@ -367,9 +435,12 @@ int handle_SYNC1(IP_Port source, uint32_t recv_packetnum, uint32_t sent_packetnu
367 { 435 {
368 connections[x].orecv_packetnum = recv_packetnum; 436 connections[x].orecv_packetnum = recv_packetnum;
369 connections[x].sent_packetnum = recv_packetnum; 437 connections[x].sent_packetnum = recv_packetnum;
438 connections[x].sendbuff_packetnum = recv_packetnum;
439 connections[x].successful_sent = recv_packetnum;
370 connections[x].osent_packetnum = sent_packetnum; 440 connections[x].osent_packetnum = sent_packetnum;
371 connections[x].recv_packetnum = sent_packetnum; 441 connections[x].recv_packetnum = sent_packetnum;
372 442 connections[x].successful_read = sent_packetnum;
443
373 return x; 444 return x;
374 } 445 }
375 } 446 }
@@ -379,26 +450,28 @@ int handle_SYNC1(IP_Port source, uint32_t recv_packetnum, uint32_t sent_packetnu
379//case 2: 450//case 2:
380int handle_SYNC2(int connection_id, uint8_t counter, uint32_t recv_packetnum, uint32_t sent_packetnum) 451int handle_SYNC2(int connection_id, uint8_t counter, uint32_t recv_packetnum, uint32_t sent_packetnum)
381{ 452{
382 if(recv_packetnum == connections[connection_id].orecv_packetnum && 453 if(recv_packetnum == connections[connection_id].orecv_packetnum)
383 sent_packetnum == connections[connection_id].osent_packetnum) 454 //&& sent_packetnum == connections[connection_id].osent_packetnum)
384 { 455 {
385 connections[connection_id].status = 3; 456 connections[connection_id].status = 3;
386 connections[connection_id].recv_counter = counter; 457 connections[connection_id].recv_counter = counter;
387 connections[connection_id].send_counter++; 458 connections[connection_id].send_counter++;
388 return 0; 459 return 0;
389 } 460 }
461 return 1;
390} 462}
391//case 3: 463//case 3:
392int handle_SYNC3(int connection_id, uint8_t counter, uint32_t recv_packetnum, uint32_t sent_packetnum, uint32_t * req_packets, 464int handle_SYNC3(int connection_id, uint8_t counter, uint32_t recv_packetnum, uint32_t sent_packetnum, uint32_t * req_packets,
393 uint16_t number) 465 uint16_t number)
394{ 466{
395 uint8_t comp_counter = (connections[connection_id].recv_counter + 1); 467 uint8_t comp_counter = (counter - connections[connection_id].recv_counter );
396 if((recv_packetnum - connections[connection_id].orecv_packetnum) < MAX_PACKET_NUM && 468 uint32_t comp_1 = (recv_packetnum - connections[connection_id].orecv_packetnum);
397 (sent_packetnum - connections[connection_id].osent_packetnum) < MAX_PACKET_NUM && 469 uint32_t comp_2 = (sent_packetnum - connections[connection_id].osent_packetnum);
398 counter == comp_counter) //packet valid 470 if(comp_1 < BUFFER_PACKET_NUM && comp_2 < BUFFER_PACKET_NUM && comp_counter < 10) //packet valid
399 { 471 {
400 connections[connection_id].orecv_packetnum = recv_packetnum; 472 connections[connection_id].orecv_packetnum = recv_packetnum;
401 connections[connection_id].osent_packetnum = sent_packetnum; 473 connections[connection_id].osent_packetnum = sent_packetnum;
474 connections[connection_id].successful_sent = recv_packetnum;
402 connections[connection_id].last_recv = current_time(); 475 connections[connection_id].last_recv = current_time();
403 connections[connection_id].recv_counter = counter; 476 connections[connection_id].recv_counter = counter;
404 connections[connection_id].send_counter++; 477 connections[connection_id].send_counter++;
@@ -419,7 +492,7 @@ int handle_SYNC(char * packet, uint32_t length, IP_Port source)
419 int connection = getconnection_id(source); 492 int connection = getconnection_id(source);
420 uint8_t counter; 493 uint8_t counter;
421 uint32_t recv_packetnum, sent_packetnum; 494 uint32_t recv_packetnum, sent_packetnum;
422 uint32_t req_packets[MAX_PACKET_NUM]; 495 uint32_t req_packets[BUFFER_PACKET_NUM];
423 uint16_t number = (length - 4 - 4 - 2)/ 4; 496 uint16_t number = (length - 4 - 4 - 2)/ 4;
424 497
425 memcpy(&counter, packet + 1, 1); 498 memcpy(&counter, packet + 1, 1);
@@ -446,8 +519,63 @@ int handle_SYNC(char * packet, uint32_t length, IP_Port source)
446 return 0; 519 return 0;
447} 520}
448 521
522//add a packet to the recieved buffer and set the recv_packetnum of the connection to its proper value.
523//return 1 if data was too big, 0 if not.
524int add_recv(int connection_id, uint32_t data_num, char * data, uint16_t size)
525{
526 if(size > MAX_DATA_SIZE)
527 {
528 return 1;
529 }
530
531 uint32_t i;
532 uint32_t maxnum = connections[connection_id].successful_read + BUFFER_PACKET_NUM;
533 uint32_t sent_packet = data_num - connections[connection_id].osent_packetnum;
534 for(i = connections[connection_id].recv_packetnum; i != maxnum; i++)
535 {
536 if(i == data_num)
537 {
538 memcpy(connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].data, data, size);
539 connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size = size;
540 if(sent_packet < BUFFER_PACKET_NUM)
541 {
542 connections[connection_id].osent_packetnum = data_num;
543 }
544 break;
545 }
546 }
547 for(i = connections[connection_id].recv_packetnum; i != maxnum; i++)
548 {
549 if(connections[connection_id].recvbuffer[i % MAX_QUEUE_NUM].size != 0)
550 {
551 connections[connection_id].recv_packetnum = i;
552 }
553 else
554 {
555 break;
556 }
557 }
558
559 return 0;
560}
561
449int handle_data(char * packet, uint32_t length, IP_Port source) 562int handle_data(char * packet, uint32_t length, IP_Port source)
450{ 563{
564 int connection = getconnection_id(source);
565
566 if(connection == -1)
567 {
568 return 1;
569 }
570 if(length > 1 + 4 + MAX_DATA_SIZE || length < 1 + 4 + 1)
571 {
572 return 1;
573 }
574 uint32_t number;
575 uint16_t size = length - 1 - 4;
576
577 memcpy(&number, packet + 1, 4);
578 return add_recv(connection, number, packet + 5, size);
451 579
452} 580}
453 581
@@ -477,7 +605,6 @@ int LosslessUDP_handlepacket(char * packet, uint32_t length, IP_Port source)
477} 605}
478 606
479//Send handshake requests 607//Send handshake requests
480//TODO: optimize this.
481//handshake packets are sent at the same rate as SYNC packets 608//handshake packets are sent at the same rate as SYNC packets
482void doNew() 609void doNew()
483{ 610{
@@ -521,7 +648,19 @@ void doSYNC()
521 648
522void doData() 649void doData()
523{ 650{
524 651 uint32_t i;
652 uint64_t temp_time = current_time();
653 for(i = 0; i < MAX_CONNECTIONS; i++)
654 {
655 if(connections[i].status == 3)
656 {
657 if((connections[i].last_sent + (1000000UL/connections[i].data_rate)) <= temp_time)
658 {
659 send_DATA(i);
660 connections[i].last_sent = temp_time;
661 }
662 }
663 }
525} 664}
526 665
527//TODO: flow control. 666//TODO: flow control.
diff --git a/core/Lossless_UDP.h b/core/Lossless_UDP.h
index f8021f5a..8f5503ea 100644
--- a/core/Lossless_UDP.h
+++ b/core/Lossless_UDP.h
@@ -2,7 +2,26 @@
2* 2*
3* An implementation of the Lossless_UDP protocol as seen in docs/Lossless_UDP.txt 3* An implementation of the Lossless_UDP protocol as seen in docs/Lossless_UDP.txt
4* 4*
5
6 Copyright (C) 2013 Tox project All Rights Reserved.
7
8 This file is part of Tox.
9
10 Tox is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 Tox is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with Tox. If not, see <http://www.gnu.org/licenses/>.
22
5*/ 23*/
24
6#ifndef LOSSLESS_UDP_H 25#ifndef LOSSLESS_UDP_H
7#define LOSSLESS_UDP_H 26#define LOSSLESS_UDP_H
8 27
@@ -33,10 +52,10 @@ int read_packet(int connection_id, char * data);
33int write_packet(int connection_id, char * data, uint32_t length); 52int write_packet(int connection_id, char * data, uint32_t length);
34 53
35//returns the number of packets in the queue waiting to be successfully sent. 54//returns the number of packets in the queue waiting to be successfully sent.
36int sendqueue(int connection_id); 55uint32_t sendqueue(int connection_id);
37 56
38//returns the number of packets in the queue waiting to be successfully read with read_packet(...) 57//returns the number of packets in the queue waiting to be successfully read with read_packet(...)
39int recvqueue(int connection_id); 58uint32_t recvqueue(int connection_id);
40 59
41//check if connection is connected 60//check if connection is connected
42//return 0 no. 61//return 0 no.