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