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 }