1 /** 
2  * Socket encoding/decoding functions
3  */
4 module bformat.sockets;
5 
6 import std.socket : Socket, SocketFlags, MSG_WAITALL;
7 
8 /** 
9  * Receives a message from the provided socket
10  * by decoding the streamed bytes into bformat
11  * and finally placing the resulting payload in
12  * the provided array
13  *
14  * Params:
15  *   originator = the socket to receive from
16  *   receiveMessage = the nbuffer to receive into
17  *
18  * Returns: true if the receive succeeded, false otheriwse
19  */
20 public bool receiveMessage(Socket originator, ref byte[] receiveMessage)
21 {
22 	/* Construct a buffer to receive into */
23 	byte[] receiveBuffer;
24 
25 	bool status = true;
26 
27 
28 	/* The amount of bytes received */
29 	long bytesReceived;
30 
31 	/* Get the length of the message */
32 	byte[4] messageLengthBytes;
33 	bytesReceived = originator.receive(messageLengthBytes, cast(SocketFlags)MSG_WAITALL);
34 
35 	/* If there was an error reading from the socket */
36 	if(!(bytesReceived > 0))
37 	{
38 		status =  false;
39 	}
40 	/* If the receive was successful */
41 	else
42 	{
43 		/* Response message length */
44 		uint messageLength;
45 
46 		/* Little endian version you simply read if off the bone (it's already in the correct order) */
47 		version(LittleEndian)
48 		{
49 			messageLength = *cast(int*)messageLengthBytes.ptr;
50 		}
51 
52 		/* Big endian requires we byte-sapped the little-endian encoded number */
53 		version(BigEndian)
54 		{
55 			byte[] swappedLength;
56 			swappedLength.length = 4;
57 
58 			swappedLength[0] = messageLengthBytes[3];
59 			swappedLength[1] = messageLengthBytes[2];
60 			swappedLength[2] = messageLengthBytes[1];
61 			swappedLength[3] = messageLengthBytes[0];
62 
63 			messageLength = *cast(int*)swappedLength.ptr;
64 		}
65 
66 
67 		/* Read the full message */
68 		receiveBuffer.length = messageLength;
69 		bytesReceived = originator.receive(receiveBuffer, cast(SocketFlags)MSG_WAITALL);
70 
71 		/* If there was an error reading from the socket */
72 		if(!(bytesReceived > 0))
73 		{
74 			status = false;
75 		}
76 		/* If there was no error receiving the message */
77 		else
78 		{
79 			receiveMessage = receiveBuffer;
80 		}
81 	}
82 
83 	return status;
84 }
85 
86 /** 
87  * Encodes the provided message into the bformat format
88  * and sends it over the provided socket
89  *
90  * Params:
91  *   recipient = the socket to send over
92  *   message = the message to encode and send
93  *
94  * Returns: true if the send succeeded, false otherwise
95  */
96 public bool sendMessage(Socket recipient, byte[] message)
97 {
98 	/* The message buffer */
99 	byte[] messageBuffer;
100 
101 	/* Encode the 4 byte message length header (little endian) */
102 	int payloadLength = cast(int)message.length;
103 	byte* lengthBytes = cast(byte*)&payloadLength;
104 
105 	/* On little endian simply get the bytes as is (it would be encoded as little endian) */
106 	version(LittleEndian)
107 	{
108 		messageBuffer ~= *(lengthBytes+0);
109 		messageBuffer ~= *(lengthBytes+1);
110 		messageBuffer ~= *(lengthBytes+2);
111 		messageBuffer ~= *(lengthBytes+3);
112 	}
113 
114 	/* On Big Endian you must swap the big-endian-encoded number to be in little endian ordering */
115 	version(BigEndian)
116 	{
117 		messageBuffer ~= *(lengthBytes+3);
118 		messageBuffer ~= *(lengthBytes+2);
119 		messageBuffer ~= *(lengthBytes+1);
120 		messageBuffer ~= *(lengthBytes+0);
121 	}
122 	
123 
124 	/* Add the message to the buffer */
125 	messageBuffer ~= cast(byte[])message;
126 
127 	/* Send the message */
128 	long bytesSent = recipient.send(messageBuffer);
129 
130 	/* TODO: Compact this */
131 	return bytesSent > 0;
132 }