1 /*
2 DSFML - The Simple and Fast Multimedia Library for D
3 
4 Copyright (c) 2013 - 2015 Jeremy DeHaan (dehaan.jeremiah@gmail.com)
5 
6 This software is provided 'as-is', without any express or implied warranty.
7 In no event will the authors be held liable for any damages arising from the use of this software.
8 
9 Permission is granted to anyone to use this software for any purpose, including commercial applications,
10 and to alter it and redistribute it freely, subject to the following restrictions:
11 
12 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
13 If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
14 
15 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
16 
17 3. This notice may not be removed or altered from any source distribution
18 */
19 
20 ///A module contianing the Packet class.
21 module dsfml.network.packet;
22 
23 import std.traits;
24 import std.range;
25 
26 /**
27  *Utility class to build blocks of data to transfer over the network.
28  *
29  *Packets provide a safe and easy way to serialize data, in order to send it over the network using sockets (sf::TcpSocket, sf::UdpSocket).
30  */
31 class Packet
32 {
33 	
34 	private
35 	{
36 		ubyte[] m_data;    /// Data stored in the packet
37 		size_t  m_readPos; /// Current reading position in the packet
38 		bool    m_isValid; /// Reading state of the packet
39 	}
40 	
41 	///Default constructor
42 	this()
43 	{
44 		m_readPos = 0;
45 		m_isValid = true;
46 	}
47 	
48 	///Destructor
49 	~this()
50 	{
51 		import dsfml.system.config;
52 		mixin(destructorOutput);
53 	}
54 
55 	///Get a slice of the data contained in the packet.
56 	///
57 	///Returns: Slice containing the data.
58 	const(void)[] getData() const
59 	{
60 		return m_data;
61 	}
62 
63 	///Append data to the end of the packet.
64 	///Params:
65 	///		data = Pointer to the sequence of bytes to append.
66 	void append(const(void)[] data)
67 	{
68 		if(data != null && data.length > 0)
69 		{
70 			m_data ~= cast(ubyte[])data;
71 		}
72 	}
73 
74 	///Clear the packet.
75 	///
76 	///After calling Clear, the packet is empty.
77 	void clear()
78 	{
79 		m_data.length = 0;
80 		m_readPos = 0;
81 		m_isValid = true;
82 	}
83 
84 	///Tell if the reading position has reached the end of the packet.
85 	///
86 	///This function is useful to know if there is some data left to be read, without actually reading it.
87 	///
88 	///Returns: True if all data was read, false otherwise.
89 	bool endOfPacket() const
90 	{
91 		return m_readPos >= m_data.length;
92 	}
93 	
94 	
95 	///Reads a primitive data type or string from the packet.
96 	///The value in the packet at the current read position is set to value.
97 	///
98 	///Returns: True if last data extraction from packet was successful.
99 	bool read(T)(out T value)
100 	if(isScalarType!T)
101 	{
102 		import std.bitmanip;
103 		
104 		if (checkSize(T.sizeof))
105 		{
106 			value = std.bitmanip.peek!T(m_data, m_readPos);
107 			m_readPos += T.sizeof;
108 		}
109 
110 		return m_isValid;
111 	}
112 	
113 	///Ditto
114 	bool read(T)(out T value) 
115 	if(isSomeString!T)
116 	{
117 		import std.conv;
118 		
119 		//Get the element type of the string
120 		static if(isNarrowString!T)
121 		{
122 			alias ET = Unqual!(ElementEncodingType!T);
123 		}
124 		else
125 		{
126 			alias ET = Unqual!(ElementType!T);
127 		}
128 
129 		//get string length
130 		uint length;
131 		read(length);
132 		ET[] temp = new ET[](length);
133 		
134 		//read each dchar of the string and put it in. 
135 		for(int i = 0; i < length && m_isValid; ++i)
136 		{
137 			read!ET(temp[i]);
138 		}
139 		
140 		value = temp.to!T();
141 		
142 		return m_isValid;
143 	}
144 	
145 	
146 	///Writes a scalar data type or string to the packet.
147 	void write(T)(T value)
148 	if(isScalarType!T)
149 	{
150 		import std.bitmanip;
151 		
152 		size_t index = m_data.length;
153 		m_data.reserve(value.sizeof);
154 		m_data.length += value.sizeof;
155 		
156 		std.bitmanip.write!T(m_data, value, index);
157 	}
158 	
159 	///Ditto
160 	void write(T)(T value)
161 	if(isSomeString!T)
162 	{
163 		//write length of string.
164 		write(cast(uint) value.length);
165 		//write append the string data
166 		for(int i = 0; i < value.length; ++i)
167 		{
168 			write(value[i]);
169 		}
170 	}
171 
172 	///Called before the packet is sent over the network.
173 	///
174 	///This function can be defined by derived classes to transform the data before it is sent; this can be used for compression, encryption, etc.
175 	///The function must return an array of the modified data, as well as the number of bytes pointed. The default implementation provides the packet's data without transforming it.
176 	///
177 	///Returns:  Array of bytes to send
178 	const(void)[] onSend()
179 	{
180 		return getData();
181 	}
182 
183 	///Called after the packet is received over the network.
184 	///
185 	///This function can be defined by derived classes to transform the data after it is received; this can be used for uncompression, decryption, etc.
186 	///The function receives an array of the received data, and must fill the packet with the transformed bytes. The default implementation fills the packet directly without transforming the data.
187 	///
188 	///Params:
189 	///		data = Array of the received bytes. 
190 	void onRecieve(const(void)[] data)
191 	{
192 		append(data);
193 	}
194 
195 	version(unittest)
196 	{
197 		shared static this()
198 		{
199 			//XInitThreads();
200 		}
201 
202 
203 	}
204 	
205 	private bool checkSize(size_t size)
206 	{
207 		m_isValid = m_isValid && (m_readPos + size <= m_data.length);
208 
209 		return m_isValid;
210 	}
211 	
212 }
213 
214 /**
215  *Utility class used internally to interact with DSFML-C to transfer Packet's data.
216  */
217 package class SfPacket
218 {
219 	package sfPacket* sfPtr;
220 	
221 	///Default constructor
222 	this()
223 	{
224 		sfPtr = sfPacket_create();
225 	}
226 	
227 	///Destructor
228 	~this()
229 	{
230 		import dsfml.system.config;
231 		mixin(destructorOutput);
232 		sfPacket_destroy(sfPtr);
233 	}
234 	
235 	
236 	///Get a slice of the data contained in the packet.
237 	///
238 	///Returns: Slice containing the data.
239 	const(void)[] getData() const
240 	{
241 		return sfPacket_getData(sfPtr)[0 .. sfPacket_getDataSize(sfPtr)];
242 	}
243 
244 	///Append data to the end of the packet.
245 	///Params:
246 	///		data = Pointer to the sequence of bytes to append.
247 	void append(const(void)[] data)
248 	{
249 		sfPacket_append(sfPtr, data.ptr, void.sizeof * data.length);
250 	}
251 }
252 
253 
254 unittest
255 {
256 	//TODO: Expand to use more of the mehtods found in Packet
257 	version(DSFML_Unittest_Network)
258 	{
259 		import std.stdio;
260 
261 		import dsfml.network.socket;
262 		import dsfml.network.tcpsocket;
263 		import dsfml.network.tcplistener;
264 		import dsfml.network.ipaddress;
265 		
266 		import core.time;
267 
268 		writeln("Unittest for Packet");
269 
270 		//packet to send data
271 		auto sendPacket = new Packet();
272 		//Packet to receive data
273 		auto receivePacket = new Packet();
274 
275 		//Let's greet the server!
276 		sendPacket.write("Hello, I'm a client!");
277 		sendPacket.write(42);
278 		sendPacket.write(cast(double) 3.141592);
279 		sendPacket.write(false);
280 		
281 		receivePacket.onRecieve(sendPacket.onSend());
282 
283 		//What did we get from the client?
284 		string message;
285 		int sentInt;
286 		double sentDouble;
287 		bool sentBool;
288 		assert(receivePacket.read!string(message));
289 		assert(message == "Hello, I'm a client!");
290 		
291 		assert(receivePacket.read(sentInt));
292 		assert(sentInt == 42);
293 		
294 		assert(receivePacket.read(sentDouble));
295 		assert(sentDouble == 3.141592);
296 		
297 		assert(receivePacket.read(sentBool));
298 		assert(!sentBool);
299 		writeln("Gotten from client: ", message, ", ", sentInt, ", ", sentDouble, ", ", sentBool);
300 
301 		//clear the packets to send/get new information
302 		sendPacket.clear();
303 		receivePacket.clear();
304 
305 		//Respond back to the client
306 		sendPacket.write("Hello, I'm your server.");
307 		sendPacket.write(420UL);
308 		sendPacket.write(cast(float) 2.7182818);
309 		sendPacket.write(true);
310 
311 		receivePacket.onRecieve(sendPacket.onSend());
312 
313 		ulong sentULong;
314 		float sentFloat;
315 		assert(receivePacket.read!string(message));
316 		assert(message == "Hello, I'm your server.");
317 		
318 		assert(receivePacket.read(sentULong));
319 		assert(sentULong == 420UL);
320 		
321 		assert(receivePacket.read(sentFloat));
322 		assert(sentFloat == 2.7182818f);
323 		
324 		assert(receivePacket.read(sentBool));
325 		assert(sentBool);
326 		writeln("Gotten from server: ", message, ", ", sentULong, ", ", sentFloat, ", ", sentBool);
327 
328 		writeln("Done!");
329 		writeln();
330 	}
331 }
332 
333 package extern(C):
334 
335 struct sfPacket;
336 
337 ///Create a new packet
338 sfPacket* sfPacket_create();
339 
340 
341 ///Create a new packet by copying an existing one
342 sfPacket* sfPacket_copy(const sfPacket* packet);
343 
344 
345 ///Destroy a packet
346 void sfPacket_destroy(sfPacket* packet);
347 
348 
349 ///Append data to the end of a packet
350 void sfPacket_append(sfPacket* packet, const void* data, size_t sizeInBytes);
351 
352 
353 ///Clear a packet
354 void sfPacket_clear(sfPacket* packet);
355 
356 
357 ///Get a pointer to the data contained in a packet
358 const(void)* sfPacket_getData(const sfPacket* packet);
359 
360 
361 ///Get the size of the data contained in a packet
362 size_t sfPacket_getDataSize(const sfPacket* packet);
363 
364 
365 ///Tell if the reading position has reached the end of a packet
366 bool sfPacket_endOfPacket(const sfPacket* packet);
367 
368 
369 ///Test the validity of a packet, for reading
370 bool sfPacket_canRead(const sfPacket* packet);
371 
372 
373 ///Functions to extract data from a packet
374 bool    sfPacket_readBool(sfPacket* packet);
375 byte    sfPacket_readInt8(sfPacket* packet);
376 ubyte   sfPacket_readUint8(sfPacket* packet);
377 short   sfPacket_readInt16(sfPacket* packet);
378 ushort  sfPacket_readUint16(sfPacket* packet);
379 int     sfPacket_readInt32(sfPacket* packet);
380 uint    sfPacket_readUint32(sfPacket* packet);
381 float    sfPacket_readFloat(sfPacket* packet);
382 double   sfPacket_readDouble(sfPacket* packet);
383 ///void     sfPacket_readString(sfPacket* packet, char* string);
384 ///void     sfPacket_readWideString(sfPacket* packet, wchar_t* string);///Remove in lieu of readUint16 and readUint32 for W and D chars in D?
385 
386 ///Functions to insert data into a packet
387 void sfPacket_writeBool(sfPacket* packet, bool);
388 void sfPacket_writeInt8(sfPacket* packet, byte);
389 void sfPacket_writeUint8(sfPacket* packet, ubyte);
390 void sfPacket_writeInt16(sfPacket* packet, short);
391 void sfPacket_writeUint16(sfPacket* packet, ushort);
392 void sfPacket_writeInt32(sfPacket* packet, int);
393 void sfPacket_writeUint32(sfPacket* packet, uint);
394 void sfPacket_writeFloat(sfPacket* packet, float);
395 void sfPacket_writeDouble(sfPacket* packet, double);