1 module draklib.protocol.reliability;
2 import draklib.core : RakNetInfo;
3 import draklib.bytestream : ByteStream, OutOfBoundsException;
4 import draklib.protocol.packet;
5 import draklib.util;
6 
7 /// Header for the Container Packet's PID.
8 /// Information taken from 
9 /// https://github.com/OculusVR/RakNet/blob/master/Source/ReliabilityLayer.cpp#L110
10 
11 deprecated("Implementation seems to be incorrect") struct ContainerHeader {
12 	bool isACK;
13 	bool isNACK;
14 	bool isPacketPair;
15 	bool hasBAndAS;
16 	bool isContinuousSend;
17 	bool needsBAndAs;
18 	bool isValid;
19 
20 	ubyte encode() {
21 		bool[] bits = new bool[8];
22 		bits[0] = isValid; //IsValid
23 		if(isACK) {
24 			bits[1] = true;
25 			bits[2] = hasBAndAS;
26 		} else if(isNACK) {
27 			bits[1] = false;
28 			bits[2] = true;
29 		} else {
30 			bits[1] = false;
31 			bits[2] = false;
32 			bits[3] = isPacketPair;
33 			bits[4] = isContinuousSend;
34 			bits[5] = needsBAndAs;
35 		}
36 
37 		return writeBits(bits);
38 	}
39 
40 	void decode(in ubyte header) {
41 		bool[] vals = readBits(header);
42 		isValid = vals[0];
43 		isACK = vals[1];
44 		if(isACK) {
45 			isNACK = false;
46 			isPacketPair = false;
47 			hasBAndAS = vals[2];
48 		} else {
49 			isNACK = vals[2];
50 			if(isNACK) {
51 				isPacketPair = false;
52 			} else {
53 				isPacketPair = vals[3];
54 				isContinuousSend = vals[4];
55 				needsBAndAs = vals[5];
56 			}
57 		}
58 	}
59 }
60 
61 enum Reliability {
62 	UNRELIABLE = 0,
63 	UNRELIABLE_SEQUENCED = 1,
64 	RELIABLE = 2,
65 	RELIABLE_ORDERED = 3,
66 	RELIABLE_SEQUENCED = 4,
67 	UNRELIABLE_WITH_ACK_RECEIPT = 5,
68 	RELIABLE_WITH_ACK_RECEIPT = 6,
69 	RELIABLE_ORDERED_WITH_ACK_RECEIPT = 7
70 }
71 
72 class AcknowledgePacket : Packet {
73 	uint[] nums;
74 
75 	override {
76 		protected void _encode(ref ByteStream stream) {
77 			assert(nums !is null, "no sequence numbers provided");
78 			uint count = cast(uint) nums.length;
79 			uint records = 0;
80 
81 			stream.setPosition(3);
82 			if(count > 0) {
83 				uint pointer = 0;
84 				uint start = nums[0];
85 				uint last = nums[0];
86 
87 				while(pointer + 1 < count) {
88 					uint current = nums[pointer++];
89 					uint diff = current - last;
90 					if(diff == 1) {
91 						last = current;
92 					} else if(diff > 1) { // Skip duplicated packets
93 						if(start == last) {
94 							stream.writeByte(0); // False
95 							stream.writeUInt24_LE(start);
96 							start = last = current;
97 						} else {
98 							stream.writeByte(1); // True
99 							stream.writeUInt24_LE(start);
100 							stream.writeUInt24_LE(last);
101 							start = last = current;
102 						}
103 						records = records + 1;
104 					}
105 				}
106 
107 				if(start == last) {
108 					stream.writeByte(1); // True
109 					stream.writeUInt24_LE(start);
110 				} else {
111 					stream.writeByte(0); // False
112 					stream.writeUInt24_LE(start);
113 					stream.writeUInt24_LE(last);
114 				}
115 				records = records + 1;
116 			}
117 
118 			uint oldPos = stream.getPosition();
119 
120 			stream.setPosition(1);
121 			stream.writeUShort(cast(ushort)records);
122 			stream.trimTo(oldPos);
123 		}
124 
125 		protected void _decode(ref ByteStream stream) {
126 			nums = cast(uint[]) [];
127 
128 			uint count = stream.readUShort();
129 			uint cnt = 0;
130 			for(uint i = 0; i < count && stream.getRemainingLength() > 0 && cnt < 4096; i++) {
131 				if(stream.readByte == 0) {
132 					uint start = stream.readUInt24_LE();
133 					uint end = stream.readUInt24_LE();
134 					if((end - start) > 512) {
135 						end = start + 512;
136 					}
137 					for(uint c = start; c <= end; c++) {
138 						cnt = cnt + 1;
139 						nums ~= c;
140 					}
141 				} else {
142 					nums ~= stream.readUInt24_LE();
143 				}
144 			}
145 		}
146 
147 		uint getSize() {
148 			return 2048;
149 		}
150 	}
151 }
152 
153 class ACKPacket : AcknowledgePacket {
154 	override {
155 		ubyte getID() {
156 			return RakNetInfo.ACK;
157 		}
158 	}
159 }
160 
161 class NACKPacket : AcknowledgePacket {
162 	override {
163 		ubyte getID() {
164 			return RakNetInfo.NACK;
165 		}
166 	}
167 }
168 
169 class ContainerPacket : Packet {
170 	//ContainerHeader header;
171 	ubyte header;
172 	uint sequenceNumber;
173 	EncapsulatedPacket[] packets;
174 
175 	override {
176 		void decode(byte[] data) {
177 			ByteStream stream = ByteStream.wrap(data);
178 			/*
179 			header = ContainerHeader();
180 			header.decode(stream.readUByte());
181 			*/
182 			header = stream.readUByte();
183 			_decode(stream);
184 		}
185 
186 		protected void _encode(ref ByteStream stream) {
187 			stream.writeUInt24_LE(sequenceNumber);
188 			foreach(packet; packets) {
189 				packet._encode(stream);
190 			}
191 		}
192 		
193 		protected void _decode(ref ByteStream stream) {
194 			packets = cast(EncapsulatedPacket[]) [];
195 
196 			sequenceNumber = stream.readUInt24_LE();
197 			while(stream.getRemainingLength() > 0) {
198 				try {
199 					EncapsulatedPacket ep = new EncapsulatedPacket();
200 					ep._decode(stream);
201 					packets ~= ep;
202 				} catch(OutOfBoundsException e) {
203 					debug {
204 						import std.stdio;
205 						writeln("WARNING: OutofBoundsException while processing ContainerPacket!");
206 					}
207 				}
208 			}
209 		}
210 		
211 		ubyte getID() {
212 			return header;
213 		}
214 		
215 		uint getSize() {
216 			uint size = 4;
217 			foreach(pk; packets) {
218 				size = size + pk.getSize();
219 			}
220 			return size;
221 		}
222 	}
223 }
224 
225 class EncapsulatedPacket : Packet {
226 	byte reliability;
227 	bool split = false;
228 	int messageIndex = -1;
229 	int orderIndex = -1;
230 	byte orderChannel = -1;
231 	uint splitCount;
232 	ushort splitID;
233 	uint splitIndex;
234 	byte[] payload;
235 
236 	override {
237 		protected void _encode(ref ByteStream stream) {
238 			stream.writeByte(cast(byte) ((reliability << 5) | (split ? 0b00010000 : 0)));
239 			stream.writeUShort(cast(ushort) (payload.length * 8));
240 			if(reliability > 0) {
241 				if(reliability >= Reliability.RELIABLE && reliability != Reliability.UNRELIABLE_WITH_ACK_RECEIPT) {
242 					stream.writeUInt24_LE(messageIndex);
243 				}
244 				if(reliability <= Reliability.RELIABLE_SEQUENCED && reliability != Reliability.RELIABLE) {
245 					stream.writeUInt24_LE(orderIndex);
246 					stream.writeByte(orderChannel);
247 				}
248 			}
249 			if(split) {
250 				stream.writeUInt(splitCount);
251 				stream.writeUShort(splitID);
252 				stream.writeUInt(splitIndex);
253 			}
254 			
255 			stream.write(payload);
256 		}
257 		
258 		protected void _decode(ref ByteStream stream) {
259 			ubyte header = stream.readUByte();
260 			reliability = (header & 0b11100000) >> 5;
261 			split = (header & 0b00010000) > 0;
262 			//writeln(reliability, " ", split);
263 
264 			import std.math : ceil;
265 
266 			ushort len = cast(ushort) ceil(cast(float) stream.readUShort() / 8);
267 			if(reliability > 0) {
268 				if(reliability >= Reliability.RELIABLE && Reliability.UNRELIABLE_WITH_ACK_RECEIPT) {
269 					messageIndex = stream.readUInt24_LE();
270 				}
271 				if(reliability <= Reliability.RELIABLE_SEQUENCED && reliability != Reliability.RELIABLE) {
272 					orderIndex = stream.readUInt24_LE();
273 					orderChannel = stream.readByte();
274 				}
275 			}
276 			if(split) {
277 				splitCount = stream.readUInt();
278 				splitID = stream.readUShort();
279 				splitIndex = stream.readUInt();
280 			}
281 			payload = stream.read(len);
282 		}
283 		
284 		ubyte getID() {
285 			return 0;
286 		}
287 		
288 		uint getSize() {
289 			return cast(uint) (3 + (messageIndex != -1 ? 3 : 0) + ((orderIndex != -1 && orderChannel != -1) ? 4 : 0) + (split ? 10 : 0) + (payload.length));
290 		}
291 	}
292 }