public void Write(WebSocketOpCode opCode, byte[] payload, bool isLastFrame) { // best to write everything to a memory stream before we push it onto the wire // not really necessary but I like it this way using (MemoryStream memoryStream = new MemoryStream()) { byte finBitSetAsByte = isLastFrame ? (byte)0x80 : (byte)0x00; byte byte1 = (byte)(finBitSetAsByte | (byte)opCode); memoryStream.WriteByte(byte1); // NB, dont set the mask flag. No need to mask data from server to client // depending on the size of the length we want to write it as a byte, ushort or ulong if (payload.Length < 126) { byte byte2 = (byte)payload.Length; memoryStream.WriteByte(byte2); } else if (payload.Length <= ushort.MaxValue) { byte byte2 = 126; memoryStream.WriteByte(byte2); BinaryReaderWriter.WriteUShort((ushort)payload.Length, memoryStream, false); } else { byte byte2 = 127; memoryStream.WriteByte(byte2); BinaryReaderWriter.WriteULong((ulong)payload.Length, memoryStream, false); } memoryStream.Write(payload, 0, payload.Length); byte[] buffer = memoryStream.ToArray(); _stream.Write(buffer, 0, buffer.Length); } }
public WebSocketFrame Read(Stream stream, Socket socket) { byte byte1; try { byte1 = (byte)stream.ReadByte(); } catch (IOException) { if (socket.Connected) { throw; } else { return(null); } } // process first byte byte finBitFlag = 0x80; byte opCodeFlag = 0x0F; bool isFinBitSet = (byte1 & finBitFlag) == finBitFlag; WebSocketOpCode opCode = (WebSocketOpCode)(byte1 & opCodeFlag); // read and process second byte byte byte2 = (byte)stream.ReadByte(); byte maskFlag = 0x80; bool isMaskBitSet = (byte2 & maskFlag) == maskFlag; uint len = ReadLength(byte2, stream); byte[] decodedPayload; // use the masking key to decode the data if needed if (isMaskBitSet) { const int maskKeyLen = 4; byte[] maskKey = BinaryReaderWriter.ReadExactly(maskKeyLen, stream); byte[] encodedPayload = BinaryReaderWriter.ReadExactly((int)len, stream); decodedPayload = new byte[len]; // apply the mask key for (int i = 0; i < encodedPayload.Length; i++) { decodedPayload[i] = (Byte)(encodedPayload[i] ^ maskKey[i % maskKeyLen]); } } else { decodedPayload = BinaryReaderWriter.ReadExactly((int)len, stream); } WebSocketFrame frame = new WebSocketFrame(isFinBitSet, opCode, decodedPayload, true); return(frame); }
public static long ReadLongExactly(Stream stream, bool isLittleEndian) { byte[] lenBuffer = BinaryReaderWriter.ReadExactly(8, stream); if (!isLittleEndian) { Array.Reverse(lenBuffer); // big endian } return(BitConverter.ToInt64(lenBuffer, 0)); }
public static ushort ReadUShortExactly(Stream stream, bool isLittleEndian) { byte[] lenBuffer = BinaryReaderWriter.ReadExactly(2, stream); if (!isLittleEndian) { Array.Reverse(lenBuffer); // big endian } return(BitConverter.ToUInt16(lenBuffer, 0)); }
private static uint ReadLength(byte byte2, Stream stream) { byte payloadLenFlag = 0x7F; uint len = (uint)(byte2 & payloadLenFlag); // read a short length or a long length depending on the value of len if (len == 126) { len = BinaryReaderWriter.ReadUShortExactly(stream, false); } else if (len == 127) { len = (uint)BinaryReaderWriter.ReadULongExactly(stream, false); const uint maxLen = 2147483648; // 2GB // protect ourselves against bad data if (len > maxLen || len < 0) { throw new ArgumentOutOfRangeException(string.Format("Payload length out of range. Min 0 max 2GB. Actual {0:#,##0} bytes.", len)); } } return(len); }