1 module bmessage;
2 
3 import std.socket : Socket, SocketFlags, MSG_WAITALL;
4 
5 public bool receiveMessage(Socket originator, ref byte[] receiveMessage)
6 {
7 	/* Construct a buffer to receive into */
8 	byte[] receiveBuffer;
9 
10 	/* The current byte */
11 	uint currentByte = 0;
12 
13 	/* The amount of bytes received */
14 	long bytesReceived;
15 
16 	/* Loop consume the next 4 bytes */
17 	while(currentByte < 4)
18 	{
19 		/* Temporary buffer */
20 		byte[4] tempBuffer;
21 
22 		/* Read at-most 4 bytes */
23 		bytesReceived = originator.receive(tempBuffer);
24 
25 		/* If there was an error reading from the socket */
26 		if(!(bytesReceived > 0))
27 		{
28 			return false;
29 		}
30 		/* If there is no error reading from the socket */
31 		else
32 		{
33 			/* Add the read bytes to the *real* buffer */
34 			receiveBuffer ~= tempBuffer[0..bytesReceived];
35 
36 			/* Increment the byte counter */
37 			currentByte += bytesReceived;
38 		}
39 	}
40 
41 	/* Response message length */
42 	int messageLength;
43 
44 	/* Little endian version you simply read if off the bone (it's already in the correct order) */
45 	version(LittleEndian)
46 	{
47 		messageLength = *cast(int*)receiveBuffer.ptr;
48 	}
49 
50 	/* Big endian requires we byte-sapped the little-endian encoded number */
51 	version(BigEndian)
52 	{
53 		byte[] swappedLength;
54 		swappedLength.length = 4;
55 
56 		swappedLength[0] = receiveBuffer[3];
57 		swappedLength[1] = receiveBuffer[2];
58 		swappedLength[2] = receiveBuffer[1];
59 		swappedLength[3] = receiveBuffer[0];
60 
61 		messageLength = *cast(int*)swappedLength.ptr;
62 	}
63 
64 	/* Full message buffer Reset buffer */
65 	byte[] fullMessage;
66 
67 	/* Reset the byte counter */
68 	currentByte = 0;
69 
70 	while(currentByte < messageLength)
71 	{
72 		/**
73 		 * Receive 20 bytes (at most) at a time and don't dequeue from
74 		 * the kernel's TCP stack's buffer.
75 		 */
76 		byte[20] tempBuffer;
77 		bytesReceived = originator.receive(tempBuffer, SocketFlags.PEEK);
78 
79 		/* Check for an error whilst receiving */
80 		if(!(bytesReceived > 0))
81 		{
82 			return false;
83 		}
84 		else
85 		{
86 			if(cast(uint)bytesReceived+currentByte > messageLength)
87 			{
88 				byte[] remainingBytes;
89 				remainingBytes.length = messageLength-currentByte;
90 
91 				/* Receive the remaining bytes */
92 				originator.receive(remainingBytes);
93 
94 				/* Increment counter of received bytes */
95 				currentByte += remainingBytes.length;
96 
97 				/* Append the received bytes to the FULL message buffer */
98 				fullMessage ~= remainingBytes;
99 
100 				// writeln("Received ", currentByte, "/", cast(uint)messageLength, " bytes");
101 			}
102 			else
103 			{
104 				/* Increment counter of received bytes */
105 				currentByte += bytesReceived;
106 	
107 				/* Append the received bytes to the FULL message buffer */
108 				fullMessage ~= tempBuffer[0..bytesReceived];
109 
110 				/* TODO: Bug when over send, we must not allow this */
111 				// writeln("Received ", currentByte, "/", cast(uint)messageLength, " bytes");	
112 
113 				/* Dequeue the received bytes */
114 				originator.receive(tempBuffer);
115 			}
116 		}
117 	}
118 
119 	/* Set the message in `receiveMessage */
120 	receiveMessage = fullMessage;
121 
122 	return true;
123 }
124 
125 public bool sendMessage(Socket recipient, byte[] message)
126 {
127 	/* The message buffer */
128 	byte[] messageBuffer;
129 
130 	/* Encode the 4 byte message length header (little endian) */
131 	int payloadLength = cast(int)message.length;
132 	byte* lengthBytes = cast(byte*)&payloadLength;
133 
134 	/* On little endian simply get the bytes as is (it would be encoded as little endian) */
135 	version(LittleEndian)
136 	{
137 		messageBuffer ~= *(lengthBytes+0);
138 		messageBuffer ~= *(lengthBytes+1);
139 		messageBuffer ~= *(lengthBytes+2);
140 		messageBuffer ~= *(lengthBytes+3);
141 	}
142 
143 	/* On Big Endian you must swap the big-endian-encoded number to be in little endian ordering */
144 	version(BigEndian)
145 	{
146 		messageBuffer ~= *(lengthBytes+3);
147 		messageBuffer ~= *(lengthBytes+2);
148 		messageBuffer ~= *(lengthBytes+1);
149 		messageBuffer ~= *(lengthBytes+0);
150 	}
151 	
152 
153 	/* Add the message to the buffer */
154 	messageBuffer ~= cast(byte[])message;
155 
156 	/* Send the message */
157 	long bytesSent = recipient.send(messageBuffer);
158 
159 	/* TODO: Compact this */
160 	return bytesSent > 0;
161 }