using System; using System.IO; using System.Text; using ln.types; using ln.logging; namespace ln.http.websocket { public class WebSocketFrame { public bool FIN; public bool RSV1; public bool RSV2; public bool RSV3; public WebSocketOpcode Opcode = WebSocketOpcode.INVALIDOPCODE; public bool Mask; public int MaskingKey; public byte[] ExtensionData; public byte[] ApplicationData; public byte[] Payload => ExtensionData.Concat(ApplicationData); public WebSocketFrame() { ExtensionData = new byte[0]; ApplicationData = new byte[0]; } public WebSocketFrame(WebSocketOpcode opcode) :this(opcode,new byte[0]) { } public WebSocketFrame(WebSocketOpcode opcode,byte[] applicationData) { Opcode = opcode; ExtensionData = new byte[0]; ApplicationData = applicationData; } public WebSocketFrame(string applicationData) :this(Encoding.UTF8.GetBytes(applicationData),new byte[0]) { Opcode = WebSocketOpcode.TEXT; } public WebSocketFrame(byte[] applicationData) : this(applicationData, new byte[0]) { } public WebSocketFrame(byte[] applicationData,byte[] extensionData) { FIN = true; Opcode = WebSocketOpcode.BINARY; ExtensionData = extensionData; ApplicationData = applicationData; } public WebSocketFrame(Stream stream) { ReadFrom(stream); } public void ReadFrom(Stream stream) { int firstByte = stream.ReadByte(); if (firstByte == -1) throw new IOException(); FIN = (firstByte & 0x80) != 0; RSV1 = (firstByte & 0x40) != 0; RSV3 = (firstByte & 0x20) != 0; RSV1 = (firstByte & 0x10) != 0; Opcode = (WebSocketOpcode)(firstByte & 0x0F); Logging.Log(LogLevel.DEBUG, "WebSocket: FirstByte=0x{0:x8}",firstByte); int secondByte = stream.ReadByte(); if (secondByte == -1) throw new IOException(); Logging.Log(LogLevel.DEBUG, "WebSocket: SecondByte=0x{0:x8}", secondByte); Mask = (secondByte & 0x80) != 0; int pLength = (secondByte) & 0x7F; if (pLength == 126) { pLength = stream.ReadUShort(true); } else if (pLength == 127) { ulong ulpLength = stream.ReadULong(true); if (ulpLength > int.MaxValue) throw new NotSupportedException(String.Format("Maximum supported frame size is: {0} bytes", int.MaxValue)); pLength = (int)ulpLength; } if (Mask) { MaskingKey = stream.ReadInteger(); } ExtensionData = new byte[0]; ApplicationData = stream.ReadBytes(pLength); if (Mask) { MaskPayload(ApplicationData, MaskingKey); } } public void WriteTo(Stream stream) { stream.WriteByte( (byte)( (FIN ? 0x80 : 0x00) | (RSV1 ? 0x40 : 0x00) | (RSV2 ? 0x20 : 0x00) | (RSV3 ? 0x10 : 0x00) | (((int)Opcode) & 0x0F) ) ); int dLength = ExtensionData.Length + ApplicationData.Length; int pLength = 0; if (dLength < 126) { pLength = (dLength) | (Mask ? 0x80 : 0x00); stream.WriteByte((byte)pLength); } else if (dLength < (1U<<16)) { pLength = (126) | (Mask ? 0x80 : 0x00); stream.WriteByte((byte)pLength); stream.WriteBytes(((ushort)dLength).GetBytes(true)); } else { pLength = (127) | (Mask ? 0x80 : 0x00); stream.WriteByte((byte)pLength); stream.WriteBytes(((ulong)dLength).GetBytes(true)); } byte[] payload = Payload; if (Mask) { stream.WriteBytes(MaskingKey.GetBytes()); MaskPayload(payload, MaskingKey); } stream.WriteBytes(payload); stream.Flush(); } public static void MaskPayload(byte[] data,int maskingKey) { byte[] mk = BitConverter.GetBytes(maskingKey); for (int n = 0; n < data.Length; n++) { data[n] = (byte)(data[n] ^ mk[n % 4]); } } static Random random = new Random(); } }