summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/DHT.c4
-rw-r--r--core/Lossless_UDP.c436
-rw-r--r--core/Lossless_UDP.h58
-rw-r--r--docs/Lossless_UDP.txt10
-rw-r--r--testing/Lossless_UDP_testclient.c13
-rw-r--r--testing/Lossless_UDP_testserver.c2
6 files changed, 509 insertions, 14 deletions
diff --git a/core/DHT.c b/core/DHT.c
index 05d9d20c..5c63146f 100644
--- a/core/DHT.c
+++ b/core/DHT.c
@@ -492,7 +492,7 @@ int sendnodes(IP_Port ip_port, char * client_id, uint32_t ping_id)
492 492
493//Packet handling functions 493//Packet handling functions
494//One to handle each types of packets we recieve 494//One to handle each types of packets we recieve
495 495//return 0 if handled correctly, 1 if packet is bad.
496int handle_pingreq(char * packet, uint32_t length, IP_Port source)//tested 496int handle_pingreq(char * packet, uint32_t length, IP_Port source)//tested
497{ 497{
498 if(length != 5 + CLIENT_ID_SIZE) 498 if(length != 5 + CLIENT_ID_SIZE)
@@ -561,7 +561,7 @@ int handle_getnodes(char * packet, uint32_t length, IP_Port source)
561 561
562int handle_sendnodes(char * packet, uint32_t length, IP_Port source)//tested 562int handle_sendnodes(char * packet, uint32_t length, IP_Port source)//tested
563{ 563{
564 if(length > (5 + CLIENT_ID_SIZE + MAX_SENT_NODES * (CLIENT_ID_SIZE + sizeof(IP_Port))) || 564 if(length > (5 + CLIENT_ID_SIZE + MAX_SENT_NODES * (CLIENT_ID_SIZE + sizeof(IP_Port))) ||
565 (length - 5 - CLIENT_ID_SIZE) % (CLIENT_ID_SIZE + sizeof(IP_Port)) != 0) 565 (length - 5 - CLIENT_ID_SIZE) % (CLIENT_ID_SIZE + sizeof(IP_Port)) != 0)
566 { 566 {
567 return 1; 567 return 1;
diff --git a/core/Lossless_UDP.c b/core/Lossless_UDP.c
new file mode 100644
index 00000000..3f058c44
--- /dev/null
+++ b/core/Lossless_UDP.c
@@ -0,0 +1,436 @@
1/* Lossless_UDP.c
2*
3* An implementation of the Lossless_UDP protocol as seen in docs/Lossless_UDP.txt
4*
5*/
6#include "Lossless_UDP.h"
7
8
9//maximum data packets in sent and recieve queues.
10#define MAX_QUEUE_NUM 32
11
12//maximum length of the data in the data packets
13#define PDATA_SIZE 1024
14
15//maximum number of data packets that can be sent/recieved at the same time
16#define MAX_PACKET_NUM (MAX_QUEUE_NUM/4)
17
18//Lossless UDP connection timeout.
19#define CONNEXION_TIMEOUT 10
20
21typedef struct
22{
23 char data[PDATA_SIZE];
24 uint16_t size;
25}Data;
26
27typedef struct
28{
29 IP_Port ip_port;
30 char status;//0 if connection is dead, 1 if attempting handshake,
31 //2 if handshake is done (we start sending SYNC packets)
32 //3 if we are sending SYNC packets and can send data
33
34 char inbound; //1 or 2 if connection was initiated by someone else, 0 if not.
35 //2 if incoming_connection() has not returned it yet, 1 if it has.
36
37 uint16_t SYNC_rate;//current SYNC packet send rate packets per second.
38 uint16_t data_rate;//current data packet send rate packets per second.
39 uint64_t last_SYNC; //time at which our last SYNC packet was sent.
40 uint64_t last_recv; //time at which we last recieved something from the other
41 uint16_t SYNC_packetsize;
42 char SYNC_packet[(MAX_PACKET_NUM*4 + 4 + 4 + 3)]; //the SYNC packet itself
43 Data sendbuffer[MAX_PACKET_NUM];//packet send buffer.
44 Data recvbuffer[MAX_PACKET_NUM];//packet recieve buffer.
45 uint32_t recv_packetnum; //number of data packets recieved (also used as handshake_id1)
46 uint32_t sent_packetnum; //number of data packets sent
47 uint32_t successful_sent;//we know all packets before that number were successfully sent
48 uint32_t successful_read;//packet number of last packet read with the read_packet function
49 uint32_t req_packets[MAX_PACKET_NUM]; //list of currently requested packet numbers.
50 uint16_t num_req_paquets; //total number of currently requested packets
51 uint8_t counter;
52}Connection;
53
54
55#define MAX_CONNECTIONS 256
56
57Connection connections[MAX_CONNECTIONS];
58
59
60//Functions
61
62//initialize a new connection to ip_port
63//returns an integer corresponding to the connection id.
64//return -1 if it could not initialize the connection.
65int new_connection(IP_Port ip_port)
66{
67 uint32_t i;
68 for(i = 0; i < MAX_CONNECTIONS; i++)
69 {
70 if(connections[i].status == 0)
71 {
72 connections[i].status = 1;
73 connections[i].inbound = 0;
74 connections[i].recv_packetnum = random_int(); //handshake_id1
75 return i;
76 }
77 }
78 return -1;
79}
80
81//returns an integer corresponding to the next connection in our incoming connection list
82//return -1 if there are no new incoming connections in the list.
83int incoming_connection()
84{
85 uint32_t i;
86 for(i = 0; i < MAX_CONNECTIONS; i++)
87 {
88 if(connections[i].inbound == 2)
89 {
90 connections[i].inbound = 1;
91 return i;
92 }
93 }
94 return -1;
95}
96
97//return -1 if it could not kill the connection.
98//return 0 if killed successfully
99int kill_connection(int connection_id)
100{
101 if(connections[connection_id].status > 0)
102 {
103 connections[connection_id].status = 0;
104 return 0;
105 }
106 return -1;
107}
108
109//return 0 if there is no received data in the buffer.
110//return length of received packet if successful
111int read_packet(int connection_id, char * data)
112{
113 //NOTE: like this to handle overflow
114 if(connections[connection_id].recv_packetnum - connections[connection_id].successful_read < MAX_QUEUE_NUM &&
115 connections[connection_id].recv_packetnum - connections[connection_id].successful_read != 0)
116 {
117 uint16_t index = (connections[connection_id].successful_read % MAX_QUEUE_NUM);
118 memcpy(data, connections[connection_id].sendbuffer[index].data,
119 connections[connection_id].sendbuffer[index].size);
120 connections[connection_id].successful_read++;
121 return connections[connection_id].sendbuffer[index].size;
122 }
123 return 0;
124}
125
126//return 0 if data could not be put in packet queue
127//return 1 if data was put into the queue
128int write_packet(int connection_id, char * data, uint32_t length)
129{
130 //NOTE: like this to handle overflow
131 if(connections[connection_id].sent_packetnum - connections[connection_id].successful_sent < MAX_QUEUE_NUM)
132 {
133 uint16_t index = (connections[connection_id].successful_sent % MAX_QUEUE_NUM);
134 memcpy(connections[connection_id].sendbuffer[index].data, data, length);
135 connections[connection_id].sendbuffer[index].size = length;
136 return 1;
137 }
138 return 0;
139}
140
141//returns the number of packets in the queue waiting to be successfully sent.
142int sendqueue(int connection_id)
143{
144 return connections[connection_id].sent_packetnum - connections[connection_id].successful_sent;
145}
146
147//returns the number of packets in the queue waiting to be successfully read with read_packet(...)
148int recvqueue(int connection_id)
149{
150 return connections[connection_id].recv_packetnum - connections[connection_id].successful_read;
151}
152
153//check if connection is connected
154//return 0 no.
155//return 1 if attempting handshake
156//return 2 if handshake is done
157//return 3 if fully connected
158int is_connected(int connection_id)
159{
160 return connections[connection_id].status;
161}
162
163//add a packet number to the list of packet numbers we are requesting
164//return 0 if added successfully
165//return 1 if it did not because the list was full (should never ever happen)
166int request_packet(int connection_id, uint32_t number)
167{
168 if(connections[connection_id].num_req_paquets >= MAX_PACKET_NUM)
169 {
170 connections[connection_id].req_packets[connections[connection_id].num_req_paquets] = number;
171 connections[connection_id].num_req_paquets++;
172 return 0;
173 }
174 return 1;
175
176}
177
178//remove a packet number from the list of packet numbers we are requesting
179//return 0 if removed successfully
180//return 1 if it did not because it was not in the list.
181int unrequest_packet(int connection_id, uint32_t number)
182{
183 uint32_t i;
184 for(i = 0; i < connections[connection_id].num_req_paquets; i++)
185 {
186 if(connections[connection_id].req_packets[i] == number)
187 {
188 connections[connection_id].num_req_paquets--;
189 connections[connection_id].req_packets[i] =
190 connections[connection_id].req_packets[connections[connection_id].num_req_paquets];
191 return 0;
192 }
193 }
194 return 1;
195}
196
197
198
199//Packet sending functions
200//One per packet type.
201//see docs/Lossless_UDP.txt for more information.
202
203
204int send_handshake(IP_Port ip_port, uint32_t handshake_id1, uint32_t handshake_id2)
205{
206 char packet[1 + 4 + 4];
207 packet[0] = 16;
208 memcpy(packet + 1, &handshake_id1, 4);
209 memcpy(packet + 5, &handshake_id2, 4);
210 return sendpacket(ip_port, packet, sizeof(packet));
211
212}
213
214
215int send_SYNC(IP_Port ip_port, char type, uint8_t counter, uint32_t recv_packetnum,
216 uint32_t sent_packetnum, uint32_t * requested, uint32_t number)
217{
218 if(number > MAX_PACKET_NUM)
219 {
220 return -1;
221 }
222 char packet[(MAX_PACKET_NUM*4 + 4 + 4 + 3)];
223 uint16_t index = 0;
224
225 packet[0] = 17;
226 packet[1] = type;
227 index += 2;
228 memcpy(packet + index, &counter, 1);
229 index += 1;
230 memcpy(packet + index, &recv_packetnum, 4);
231 index += 4;
232 memcpy(packet + index, &sent_packetnum, 4);
233 index += 4;
234 memcpy(packet + index, requested, 4 * number);
235
236 return sendpacket(ip_port, packet, (number*4 + 4 + 4 + 3));
237
238}
239
240
241int send_data(IP_Port ip_port, uint32_t packet_num, char * data, uint32_t length)
242{
243 if(length > PDATA_SIZE)
244 {
245 return -1;
246 }
247 char packet[1 + 4 + PDATA_SIZE];
248
249 packet[0] = 18;
250 memcpy(packet + 1, &packet_num, 4);
251 memcpy(packet + 5, data, length);
252 return sendpacket(ip_port, packet, 1 + 4 + length);
253}
254
255
256//END of packet sending functions
257
258//get connection id from IP_Port
259//return -1 if there are no connections like we are looking for
260//return id
261int getconnection_id(IP_Port ip_port)
262{
263 uint32_t i;
264 for(i = 0; i < MAX_CONNECTIONS; i++ )
265 {
266 if(connections[i].ip_port.ip.i == ip_port.ip.i &&
267 connections[i].ip_port.port == ip_port.port && connections[i].status > 0)
268 {
269 return i;
270 }
271 }
272 return -1;
273}
274
275//table of random numbers used below.
276uint32_t randtable[6][256];
277
278
279//generate a handshake_id which depends on the ip_port.
280//this function will always give one unique handshake_id per ip_port.
281//TODO: make this better
282uint32_t handshake_id(IP_Port source)
283{
284 uint32_t id = 0, i;
285 for(i = 0; i < 6; i++)
286 {
287 if(randtable[i][((uint8_t *)&source)[i]] == 0)
288 {
289 randtable[i][((uint8_t *)&source)[i]] = random_int();
290 }
291 id ^= randtable[i][((uint8_t *)&source)[i]];
292 }
293 if(id == 0)//id can't be zero
294 {
295 id = 1;
296 }
297 return id;
298}
299
300//Packet handling functions
301//One to handle each type of packets we recieve
302//return 0 if handled correctly, 1 if packet is bad.
303int handle_handshake(char * packet, uint32_t length, IP_Port source)
304{
305 if(length != (1 + 4 + 4))
306 {
307 return 1;
308 }
309 uint32_t handshake_id1, handshake_id2;
310 memcpy(&handshake_id1, packet + 1, length);
311 memcpy(&handshake_id2, packet + 5, length);
312
313 if(handshake_id2 == 0)
314 {
315 send_handshake(source, handshake_id1, handshake_id(source));
316 return 0;
317 }
318 int connection = getconnection_id(source);
319 if(connection != 1)
320 {
321 return 0;
322 }
323 if(handshake_id1 == connections[connection].recv_packetnum)//if handshake_id1 is what we sent previously.
324 {
325 connections[connection].status = 2;
326 }
327 return 0;
328
329}
330
331
332handle_SYNC(char * packet, uint32_t length, IP_Port source)
333{
334 if(length < 4 + 4 + 3)
335 {
336 return 1;
337 }
338 if(length > (MAX_PACKET_NUM*4 + 4 + 4 + 3) ||
339 ((length - 4 - 4 - 3) % 4) != 0)
340 {
341 return 1;
342 }
343 uint32_t reqpackets[MAX_PACKET_NUM];
344 int connection = getconnection_id(source);
345 char type;
346 uint8_t counter;
347 uint32_t recv_packetnum, sent_packetnum;
348 uint32_t requested[MAX_PACKET_NUM];
349 int16_t index = 2;
350
351 memcpy(&counter, packet + index, 1);
352 index += 1;
353 memcpy(&recv_packetnum, packet + index, 4);
354 index += 4;
355 memcpy(&sent_packetnum,packet + index, 4);
356 index += 4;
357
358 //memcpy(requested, packet + index, 4 * number);
359
360
361 if(connection == -1) //we are not connected to the person who sent us that packet
362 {
363 if(handshake_id(source) == recv_packetnum)
364 {
365 //TODO: handle new inbound connection
366 }
367 else
368 {
369 return 1;
370 }
371 }
372 if(connections[connection].status == 2) //we have just recieved our first SYNC packet from the other.
373 {
374 if(connections[connection].recv_packetnum == recv_packetnum &&
375 connections[connection].sent_packetnum == sent_packetnum)
376 {
377 connections[connection].status = 3;
378 connections[connection].counter = counter + 1;
379 connections[connection].last_recv = current_time();
380 }
381
382 }
383 if(connections[connection].status == 3) //we are connected and the other person just sent us a SYNC packet
384 {
385
386 //TODO: finish this function.
387
388
389 }
390
391}
392
393
394handle_data(char * packet, uint32_t length, IP_Port source)
395{
396
397
398
399}
400
401//END of packet handling functions
402
403
404//if we receive a Lossless_UDP packet we call this function so it can be handled.
405//Return 0 if packet is handled correctly.
406//return 1 if it didn't handle the packet or if the packet was shit.
407int LosslessUDP_handlepacket(char * packet, uint32_t length, IP_Port source)
408{
409
410 switch (packet[0]) {
411 case 16:
412 return handle_handshake(packet, length, source);
413
414 case 17:
415 return handle_SYNC(packet, length, source);
416
417 case 18:
418 return handle_data(packet, length, source);
419
420 default:
421 return 1;
422
423 }
424
425 return 0;
426
427}
428
429
430//Call this function a couple times per second
431//It's the main loop.
432void doLossless_UDP()
433{
434
435
436} \ No newline at end of file
diff --git a/core/Lossless_UDP.h b/core/Lossless_UDP.h
new file mode 100644
index 00000000..38b41309
--- /dev/null
+++ b/core/Lossless_UDP.h
@@ -0,0 +1,58 @@
1/* Lossless_UDP.h
2*
3* An implementation of the Lossless_UDP protocol as seen in docs/Lossless_UDP.txt
4*
5*/
6#ifndef LOSSLESS_UDP_H
7#define LOSSLESS_UDP_H
8
9#include "network.h"
10
11
12
13
14//Functions
15
16//initialize a new connection to ip_port
17//returns an integer corresponding to the connection id.
18//return -1 if it could not initialize the connection.
19int new_connection(IP_Port ip_port);
20
21//returns an integer corresponding to the next connection in our imcoming connection list
22//return -1 if there are no new incoming connections in the list.
23int incoming_connection();
24
25//return -1 if it could not kill the connection.
26//return 0 if killed successfully
27int kill_connection(int connection_id);
28
29//return 0 if there is no received data in the buffer.
30//return length of recieved packet if successful
31int read_packet(int connection_id, char * data);
32
33//return 0 if data could not be put in packet queue
34//return 1 if data was put into the queue
35int write_packet(int connection_id, char * data, uint32_t length);
36
37//returns the number of packets in the queue waiting to be successfully sent.
38int sendqueue(int connection_id);
39
40//returns the number of packets in the queue waiting to be successfully read with read_packet(...)
41int recvqueue(int connection_id);
42
43//check if connection is connected
44//return 0 no.
45//return 1 if yes
46//return 2 if the initial attempt isn't over yet.
47int is_connected(int connection_id);
48
49//Call this function a couple times per second
50//It's the main loop.
51void doLossless_UDP();
52
53//if we receive a Lossless_UDP packet we call this function so it can be handled.
54//Return 0 if packet is handled correctly.
55//return 1 if it didn't handle the packet or if the packet was shit.
56int LosslessUDP_handlepacket(char * packet, uint32_t length, IP_Port source);
57
58#endif \ No newline at end of file
diff --git a/docs/Lossless_UDP.txt b/docs/Lossless_UDP.txt
index 54eede16..09a2c133 100644
--- a/docs/Lossless_UDP.txt
+++ b/docs/Lossless_UDP.txt
@@ -17,7 +17,7 @@ Lossless UDP:
17 Bob receives the packet. 17 Bob receives the packet.
18 Bob copies the handshake packet he got from alice but caternates a random 4 byte number to it (handshake_id2) 18 Bob copies the handshake packet he got from alice but caternates a random 4 byte number to it (handshake_id2)
19 Alice receives the packet, checks if handshake_id1 matches the one she sent. 19 Alice receives the packet, checks if handshake_id1 matches the one she sent.
20 If it does she starts sending SYNC packets with sent_packetnum = handshake_id2 . 20 If it does she starts sending SYNC packets with sent_packetnum = handshake_id2 and recv_packetnum = handshake_id1.
21 Bob receives the packet, 21 Bob receives the packet,
22 if (handshake_id2) matches Bob adds Alice to his connections list and starts sending SYNC packets to alice. 22 if (handshake_id2) matches Bob adds Alice to his connections list and starts sending SYNC packets to alice.
23 Alice receives the SYNC packets and starts sending them too. 23 Alice receives the SYNC packets and starts sending them too.
@@ -64,9 +64,7 @@ Lossless UDP:
64 The client receives a Connection handshake packet(not initiating connection): 64 The client receives a Connection handshake packet(not initiating connection):
65 If handshake_id2 is zero: 65 If handshake_id2 is zero:
66 add our random handshake_id2 to it and send it back 66 add our random handshake_id2 to it and send it back
67 If handshake_id2 is non zero 67
68 check if it matches what we sent.
69 If it does add the client sending it to our connection list.
70 68
71 The client receives a Connection handshake packet(initiating connection): 69 The client receives a Connection handshake packet(initiating connection):
72 check if handshake_id1 matches what we sent. 70 check if handshake_id1 matches what we sent.
@@ -80,7 +78,7 @@ Lossless UDP:
80 78
81 Keep track of the percent of packets dropped, if it is too high, lower the send rate. If it is low, increase it. 79 Keep track of the percent of packets dropped, if it is too high, lower the send rate. If it is low, increase it.
82 80
83 81 Have a send packets buffer that we can write to and a recieved packets buffer that we can read from.
84 82
85 83
86 84
@@ -90,7 +88,7 @@ Lossless UDP:
90 [byte with value: 16 (10 in hex)][4 byte (handshake_id1)][4 bytes (handshake_id2)] 88 [byte with value: 16 (10 in hex)][4 byte (handshake_id1)][4 bytes (handshake_id2)]
91 89
92 SYNC packets: 90 SYNC packets:
93 [byte with value: 17 (11 in hex)][byte (00 for keep alive, 01 for request)][byte (counter)][4 byte (recv_packetnum)][4 byte (sent_packetnum)][sequence of requested packet ids[4 bytes each](not present in keep alive)] 91 [byte with value: 17 (11 in hex)][byte (type) (00 for keep alive, 01 for request)][byte (counter)][4 byte (recv_packetnum)][4 byte (sent_packetnum)][sequence of requested packet ids[4 bytes each](not present in keep alive)]
94 92
95 93
96 data packets: 94 data packets:
diff --git a/testing/Lossless_UDP_testclient.c b/testing/Lossless_UDP_testclient.c
index 241f5bdc..bd4b1e23 100644
--- a/testing/Lossless_UDP_testclient.c
+++ b/testing/Lossless_UDP_testclient.c
@@ -68,12 +68,15 @@ int main(int argc, char *argv[])
68 uint64_t timer = current_time(); 68 uint64_t timer = current_time();
69 while(1) 69 while(1)
70 { 70 {
71 if(is_connected(connection) != 2) 71
72 if(is_connected(connection) == 3)
72 { 73 {
73 if(is_connected(connection) == 1) 74 printf("Connecting took: %llu us", (unsigned long long)(current_time() - timer));
74 { 75 break;
75 printf("Connecting took: %llu us", (unsigned long long)(current_time() - timer)); 76 }
76 } 77 if(is_connected(connection) == 0)
78 {
79 printf("Connection timeout after: %llu us", (unsigned long long)(current_time() - timer));
77 break; 80 break;
78 } 81 }
79 c_sleep(1); 82 c_sleep(1);
diff --git a/testing/Lossless_UDP_testserver.c b/testing/Lossless_UDP_testserver.c
index 9816b8b0..c898d887 100644
--- a/testing/Lossless_UDP_testserver.c
+++ b/testing/Lossless_UDP_testserver.c
@@ -76,7 +76,7 @@ int main(int argc, char *argv[])
76 connection = incoming_connection(); 76 connection = incoming_connection();
77 if(connection != -1) 77 if(connection != -1)
78 { 78 {
79 if(is_connected(connection) == 1) 79 if(is_connected(connection) == 3)
80 { 80 {
81 printf("Recieved the connection."); 81 printf("Recieved the connection.");
82 } 82 }