ln.http/websocket/WebSocketFrame.cs

172 lines
4.6 KiB
C#

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);
int secondByte = stream.ReadByte();
if (secondByte == -1)
throw new IOException();
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();
}
}