124 lines
2.9 KiB
C#
124 lines
2.9 KiB
C#
using MECF.Framework.Common.Communications.Tcp.Socket.Framing.Base;
|
|
|
|
namespace MECF.Framework.Common.Communications.Tcp.Socket.Framing
|
|
{
|
|
public sealed class LengthPrefixedFrameDecoder : IFrameDecoder
|
|
{
|
|
internal sealed class Header
|
|
{
|
|
public bool IsMasked { get; set; }
|
|
|
|
public int PayloadLength { get; set; }
|
|
|
|
public int MaskingKeyOffset { get; set; }
|
|
|
|
public int Length { get; set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"IsMasked[{IsMasked}], PayloadLength[{PayloadLength}], MaskingKeyOffset[{MaskingKeyOffset}], Length[{Length}]";
|
|
}
|
|
}
|
|
|
|
private static readonly int MaskingKeyLength = 4;
|
|
|
|
public bool IsMasked { get; private set; }
|
|
|
|
public LengthPrefixedFrameDecoder(bool isMasked = false)
|
|
{
|
|
IsMasked = isMasked;
|
|
}
|
|
|
|
public bool TryDecodeFrame(byte[] buffer, int offset, int count, out int frameLength, out byte[] payload, out int payloadOffset, out int payloadCount)
|
|
{
|
|
frameLength = 0;
|
|
payload = null;
|
|
payloadOffset = 0;
|
|
payloadCount = 0;
|
|
Header header = DecodeHeader(buffer, offset, count);
|
|
if (header != null && header.Length + header.PayloadLength <= count)
|
|
{
|
|
if (IsMasked)
|
|
{
|
|
payload = DecodeMaskedPayload(buffer, offset, header.MaskingKeyOffset, header.Length, header.PayloadLength);
|
|
payloadOffset = 0;
|
|
payloadCount = payload.Length;
|
|
}
|
|
else
|
|
{
|
|
payload = buffer;
|
|
payloadOffset = offset + header.Length;
|
|
payloadCount = header.PayloadLength;
|
|
}
|
|
frameLength = header.Length + header.PayloadLength;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static Header DecodeHeader(byte[] buffer, int offset, int count)
|
|
{
|
|
if (count < 1)
|
|
{
|
|
return null;
|
|
}
|
|
Header header = new Header
|
|
{
|
|
IsMasked = ((buffer[offset] & 0x80) == 128),
|
|
PayloadLength = (buffer[offset] & 0x7F),
|
|
Length = 1
|
|
};
|
|
if (header.PayloadLength >= 126)
|
|
{
|
|
if (header.PayloadLength == 126)
|
|
{
|
|
header.Length += 2;
|
|
}
|
|
else
|
|
{
|
|
header.Length += 8;
|
|
}
|
|
if (count < header.Length)
|
|
{
|
|
return null;
|
|
}
|
|
if (header.PayloadLength == 126)
|
|
{
|
|
header.PayloadLength = buffer[offset + 1] * 256 + buffer[offset + 2];
|
|
}
|
|
else
|
|
{
|
|
int num = 0;
|
|
int num2 = 1;
|
|
for (int num3 = 7; num3 >= 0; num3--)
|
|
{
|
|
num += buffer[offset + num3 + 1] * num2;
|
|
num2 *= 256;
|
|
}
|
|
header.PayloadLength = num;
|
|
}
|
|
}
|
|
if (header.IsMasked)
|
|
{
|
|
if (count < header.Length + MaskingKeyLength)
|
|
{
|
|
return null;
|
|
}
|
|
header.MaskingKeyOffset = header.Length;
|
|
header.Length += MaskingKeyLength;
|
|
}
|
|
return header;
|
|
}
|
|
|
|
private static byte[] DecodeMaskedPayload(byte[] buffer, int offset, int maskingKeyOffset, int payloadOffset, int payloadCount)
|
|
{
|
|
byte[] array = new byte[payloadCount];
|
|
for (int i = 0; i < payloadCount; i++)
|
|
{
|
|
array[i] = (byte)(buffer[offset + payloadOffset + i] ^ buffer[offset + maskingKeyOffset + i % MaskingKeyLength]);
|
|
}
|
|
return array;
|
|
}
|
|
}
|
|
}
|