summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/DHT.c4
-rw-r--r--core/Lossless_UDP.c436
-rw-r--r--core/Lossless_UDP.h58
3 files changed, 496 insertions, 2 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