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 /**
24  *Utility class to build blocks of data to transfer over the network.
25  *
26  *Packets provide a safe and easy way to serialize data, in order to send it over the network using sockets (sf::TcpSocket, sf::UdpSocket).
27  */
28 class Packet
29 {
30 	package sfPacket* sfPtr;
31 	
32 	///Default constructor
33 	this()
34 	{
35 		sfPtr = sfPacket_create();
36 	}
37 	
38 	///Destructor
39 	~this()
40 	{
41 		import dsfml.system.config;
42 		mixin(destructorOutput);
43 		sfPacket_destroy(sfPtr);
44 	}
45 
46 	///Get a slice of the data contained in the packet.
47 	///
48 	///Returns: Slice containing the data.
49 	const(void)[] getData() const
50 	{
51 		return sfPacket_getData(sfPtr)[0..sfPacket_getDataSize(sfPtr)];
52 	}
53 
54 	///Append data to the end of the packet.
55 	///Params:
56     ///		data = Pointer to the sequence of bytes to append.
57 	void append(const(void)[] data)
58 	{
59 		sfPacket_append(sfPtr, data.ptr, void.sizeof*data.length);
60 	}
61 
62 	
63 	///Test the validity of a packet, for reading
64 	///
65 	///This function allows to test the packet, to check if
66 	///a reading operation was successful.
67 	///
68 	///A packet will be in an invalid state if it has no more
69 	///data to read.
70 	///
71 	///Returns: True if last data extraction from packet was successful.
72 	bool canRead() const
73 	{
74 		return (sfPacket_canRead(sfPtr));
75 	}
76 
77 	///Clear the packet.
78 	///
79 	///After calling Clear, the packet is empty.
80 	void clear()
81 	{
82 		sfPacket_clear(sfPtr);
83 	}
84 
85 	///Tell if the reading position has reached the end of the packet.
86 	///
87 	///This function is useful to know if there is some data left to be read, without actually reading it.
88 	///
89 	///Returns: True if all data was read, false otherwise.
90 	bool endOfPacket() const
91 	{
92 		return (sfPacket_endOfPacket(sfPtr));
93 	}
94 
95 	///Reads a bool from the packet.
96 	bool readBool()
97 	{
98 		return cast(bool)readByte();
99 	}
100 
101 	///Reads a byte from the packet.
102 	byte readByte()
103 	{
104 		return sfPacket_readInt8(sfPtr);
105 	}
106 	
107 	///Reads a ubyte from the packet.
108 	ubyte readUbyte()
109 	{
110 		return sfPacket_readUint8(sfPtr);
111 	}
112 	
113 	///Reads a short from the packet.
114 	short readShort()
115 	{
116 		return sfPacket_readInt16(sfPtr);
117 	}
118 
119 	///Reads a ushort from the packet.
120 	ushort readUshort()
121 	{
122 		return sfPacket_readUint16(sfPtr);
123 	}
124 
125 	///Reads a int from the packet.
126 	int readInt()
127 	{
128 		return sfPacket_readInt32(sfPtr);
129 	}
130 
131 	///Reads a uint from the packet.
132 	uint readUint()
133 	{
134 		return sfPacket_readUint32(sfPtr);
135 	}
136 	
137 	///Reads a float from the packet.
138 	float readFloat()
139 	{
140 		return sfPacket_readFloat(sfPtr);
141 	}
142 	
143 	///Reads a double from the packet.
144 	double readDouble()
145 	{
146 		return sfPacket_readDouble(sfPtr);
147 	}
148 	
149 	///Reads a string from the packet.
150 	string readString()
151 	{
152 		import std.conv;
153 
154 		//get string length
155 		uint length = readUint();
156 		char[] temp = new char[](length);
157 
158 		//read each char of the string and put it in. 
159 		for(int i = 0; i < length;++i)
160 		{
161 			temp[i] = cast(char)readUbyte();
162 		}
163 
164 		return temp.to!string();
165 	}
166 	
167 	///Reads a wstring from the packet.
168 	wstring readWstring()
169 	{
170 		import std.conv;
171 
172 		//get string length
173 		uint length = readUint();
174 		wchar[] temp = new wchar[](length);
175 		
176 		//read each wchar of the string and put it in. 
177 		for(int i = 0; i < length;++i)
178 		{
179 			temp[i] = cast(wchar)readUshort();
180 		}
181 		
182 		return temp.to!wstring();
183 	}
184 
185 	///Reads a dstring from the packet.
186 	dstring readDstring()
187 	{
188 		import std.conv;
189 
190 		//get string length
191 		uint length = readUint();
192 		dchar[] temp = new dchar[](length);
193 		
194 		//read each dchar of the string and put it in. 
195 		for(int i = 0; i < length;++i)
196 		{
197 			temp[i] = cast(dchar)readUint();
198 		}
199 		
200 		return temp.to!dstring();
201 	}
202 
203 	///Write a bool the the end of the packet.
204 	void writeBool(bool value)
205 	{
206 		writeUbyte(cast(ubyte)value);
207 	}
208 
209 	///Write a byte the the end of the packet.
210 	void writeByte(byte value)
211 	{
212 		sfPacket_writeInt8(sfPtr,value);
213 	}
214 
215 	///Write a ubyte the the end of the packet.
216 	void writeUbyte(ubyte value)
217 	{
218 		sfPacket_writeUint8(sfPtr, value);
219 	}
220 	
221 	///Write a short the the end of the packet.
222 	void writeShort(short value)
223 	{
224 		sfPacket_writeInt16(sfPtr, value);
225 	}
226 	
227 	///Write a ushort the the end of the packet.
228 	void writeUshort(ushort value)
229 	{
230 		sfPacket_writeUint16(sfPtr, value);
231 	}
232 	
233 	///Write a int the the end of the packet.
234 	void writeInt(int value)
235 	{
236 		sfPacket_writeInt32(sfPtr, value);
237 	}
238 	
239 	///Write a uint the the end of the packet.
240 	void writeUint(uint value)
241 	{
242 		sfPacket_writeUint32(sfPtr, value);
243 	}
244 	
245 	///Write a float the the end of the packet.
246 	void writeFloat(float value)
247 	{
248 		sfPacket_writeFloat(sfPtr, value);
249 	}
250 
251 	///Write a double the the end of the packet.
252 	void writeDouble(double value)
253 	{
254 		sfPacket_writeDouble(sfPtr, value);
255 	}
256 	
257 	///Write a string the the end of the packet.
258 	void writeString(string value)
259 	{
260 		//write length of string.
261 		writeUint(cast(uint)value.length);
262 		//write append the string data
263 
264 		append(value);
265 	}
266 	
267 	///Write a wstring the the end of the packet.
268 	void writeWstring(wstring value)
269 	{
270 		//write length of string.
271 		writeUint(cast(uint)value.length);
272 		//write append the string data
273 		for(int i = 0; i<value.length;++i)
274 		{
275 			writeUshort(cast(ushort)value[i]);
276 		}
277 	}
278 
279 	///Write a dstring the the end of the packet.
280 	void writeDstring(dstring value)
281 	{
282 		//write length of string.
283 		writeUint(cast(uint)value.length);
284 		//write append the string data
285 		for(int i = 0; i<value.length;++i)
286 		{
287 			writeUint(cast(uint)value[i]);
288 		}
289 	}
290 
291 	///Called before the packet is sent over the network.
292 	///
293 	///This function can be defined by derived classes to transform the data before it is sent; this can be used for compression, encryption, etc.
294 	///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.
295 	///
296 	///Returns:  Array of bytes to send
297 	const(void)[] onSend()
298 	{
299 		return getData();
300 	}
301 
302 	///Called after the packet is received over the network.
303 	///
304 	///This function can be defined by derived classes to transform the data after it is received; this can be used for uncompression, decryption, etc.
305 	///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.
306 	///
307 	///Params:
308     //		data = Array of the received bytes. 
309 	void onRecieve(const(void)[] data)
310 	{
311 		append(data);
312 	}
313 
314 	version(unittest)
315 	{
316 		shared static this()
317 		{
318     		//XInitThreads();
319 		}
320 
321 
322 	}
323 	
324 }
325 
326 
327 
328 unittest
329 {
330 	//TODO: Expand to use more of the mehtods found in Packet
331 	version(DSFML_Unittest_Network)
332 	{
333 		import std.stdio;
334 
335 
336 		import dsfml.network.socket;
337 		import dsfml.network.tcpsocket;
338 		import dsfml.network.tcplistener;
339 		import dsfml.network.ipaddress;
340 		import dsfml.system.time;
341 
342 		
343 		writeln("Unittest for Packet");
344 		//socket connecting to server
345 		auto clientSocket = new TcpSocket();
346 		
347 		//listener looking for new sockets
348 		auto listener = new TcpListener();
349 		listener.listen(46932);
350 		
351 		//get our client socket to connect to the server
352 		clientSocket.connect(IpAddress.LocalHost, 46932);
353 		
354 		
355 		
356 		//packet to send data
357 		auto sendPacket = new Packet();
358 		
359 		
360 		//Packet to receive data
361 		auto receivePacket = new Packet();
362 		
363 		//socket on the server side connected to the client's socket
364 		auto serverSocket = new TcpSocket();
365 		
366 		//accepts a new connection and binds it to the socket in the parameter
367 		listener.accept(serverSocket);
368 		
369 		//Let's greet the server!
370 		sendPacket.writeString("Hello, I'm a client!");
371 		clientSocket.send(sendPacket);
372 		
373 		//And get the data on the server side
374 		serverSocket.receive(receivePacket);
375 		
376 		//What did we get from the client?
377 		writeln("Gotten from client: " ,receivePacket.readString());
378 		
379 		//clear the packets to send/get new information
380 		sendPacket.clear();
381 		receivePacket.clear();
382 		
383 		//Respond back to the client
384 		sendPacket.writeString("Hello, I'm your server.");
385 		
386 		serverSocket.send(sendPacket);
387 
388 		clientSocket.receive(receivePacket);
389 
390 
391 		
392 		writeln("Gotten from server: ", receivePacket.readString());
393 		
394 		clientSocket.disconnect();
395 		
396 		writeln("Done!");
397 		writeln();
398 	}
399 }
400 
401 package extern(C):
402 
403 struct sfPacket;
404 
405 ///Create a new packet
406 sfPacket* sfPacket_create();
407 
408 
409 ///Create a new packet by copying an existing one
410 sfPacket* sfPacket_copy(const sfPacket* packet);
411 
412 
413 ///Destroy a packet
414 void sfPacket_destroy(sfPacket* packet);
415 
416 
417 ///Append data to the end of a packet
418 void sfPacket_append(sfPacket* packet, const void* data, size_t sizeInBytes);
419 
420 
421 ///Clear a packet
422 void sfPacket_clear(sfPacket* packet);
423 
424 
425 ///Get a pointer to the data contained in a packet
426 const(void)* sfPacket_getData(const sfPacket* packet);
427 
428 
429 ///Get the size of the data contained in a packet
430 size_t sfPacket_getDataSize(const sfPacket* packet);
431 
432 
433 ///Tell if the reading position has reached the end of a packet
434 bool sfPacket_endOfPacket(const sfPacket* packet);
435 
436 
437 ///Test the validity of a packet, for reading
438 bool sfPacket_canRead(const sfPacket* packet);
439 
440 
441 ///Functions to extract data from a packet
442 bool    sfPacket_readBool(sfPacket* packet);
443 byte    sfPacket_readInt8(sfPacket* packet);
444 ubyte   sfPacket_readUint8(sfPacket* packet);
445 short   sfPacket_readInt16(sfPacket* packet);
446 ushort  sfPacket_readUint16(sfPacket* packet);
447 int     sfPacket_readInt32(sfPacket* packet);
448 uint    sfPacket_readUint32(sfPacket* packet);
449 float    sfPacket_readFloat(sfPacket* packet);
450 double   sfPacket_readDouble(sfPacket* packet);
451 ///void     sfPacket_readString(sfPacket* packet, char* string);
452 ///void     sfPacket_readWideString(sfPacket* packet, wchar_t* string);///Remove in lieu of readUint16 and readUint32 for W and D chars in D?
453 
454 ///Functions to insert data into a packet
455 void sfPacket_writeBool(sfPacket* packet, bool);
456 void sfPacket_writeInt8(sfPacket* packet, byte);
457 void sfPacket_writeUint8(sfPacket* packet, ubyte);
458 void sfPacket_writeInt16(sfPacket* packet, short);
459 void sfPacket_writeUint16(sfPacket* packet, ushort);
460 void sfPacket_writeInt32(sfPacket* packet, int);
461 void sfPacket_writeUint32(sfPacket* packet, uint);
462 void sfPacket_writeFloat(sfPacket* packet, float);
463 void sfPacket_writeDouble(sfPacket* packet, double);
464