123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- using System;
- using MECF.Framework.Common.Communications.Tcp.Socket.Framing.Base;
- namespace MECF.Framework.Common.Communications.Tcp.Socket.Framing
- {
- // A high-level overview of the framing is given in the following figure.
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-------------+-----------------------------------------------+
- // |M| Payload len | Extended payload length |
- // |A| (7) | (16/64) |
- // |S| | (if payload len==126/127) |
- // |K| | |
- // +-+-------------+- - - - - - - - - - - - - - - - - - - - - - - -+
- // | Extended payload length continued, if payload len == 127 |
- // + - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - +
- // | | Masking-key, if MASK set to 1 |
- // +---------------+- - - - - - - - - - - - - - - - - - - - - - - -+
- // | | Payload Data :
- // +----------------- - - - - - - - - - - - - - - - - - - - - - - -+
- // : Payload Data continued ... :
- // + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
- // | Payload Data continued ... |
- // +---------------------------------------------------------------+
- public sealed class LengthPrefixedFrameBuilder : FrameBuilder
- {
- public LengthPrefixedFrameBuilder(bool isMasked = false)
- : this(new LengthPrefixedFrameEncoder(isMasked), new LengthPrefixedFrameDecoder(isMasked))
- {
- }
- public LengthPrefixedFrameBuilder(LengthPrefixedFrameEncoder encoder, LengthPrefixedFrameDecoder decoder)
- : base(encoder, decoder)
- {
- }
- }
- public sealed class LengthPrefixedFrameEncoder : IFrameEncoder
- {
- private static readonly Random _rng = new Random(DateTime.UtcNow.Millisecond);
- private static readonly int MaskingKeyLength = 4;
- public LengthPrefixedFrameEncoder(bool isMasked = false)
- {
- IsMasked = isMasked;
- }
- public bool IsMasked { get; private set; }
- public void EncodeFrame(byte[] payload, int offset, int count, out byte[] frameBuffer, out int frameBufferOffset, out int frameBufferLength)
- {
- var buffer = Encode(payload, offset, count, IsMasked);
- frameBuffer = buffer;
- frameBufferOffset = 0;
- frameBufferLength = buffer.Length;
- }
- private static byte[] Encode(byte[] payload, int offset, int count, bool isMasked = false)
- {
- byte[] fragment;
- // Payload length: 7 bits, 7+16 bits, or 7+64 bits.
- // The length of the "Payload data", in bytes:
- // if 0-125, that is the payload length.
- // If 126, the following 2 bytes interpreted as a 16-bit unsigned integer are the payload length.
- // If 127, the following 8 bytes interpreted as a 64-bit unsigned integer are the payload length.
- if (count < 126)
- {
- fragment = new byte[1 + (isMasked ? MaskingKeyLength : 0) + count];
- fragment[0] = (byte)count;
- }
- else if (count < 65536)
- {
- fragment = new byte[1 + 2 + (isMasked ? MaskingKeyLength : 0) + count];
- fragment[0] = (byte)126;
- fragment[1] = (byte)(count / 256);
- fragment[2] = (byte)(count % 256);
- }
- else
- {
- fragment = new byte[1 + 8 + (isMasked ? MaskingKeyLength : 0) + count];
- fragment[0] = (byte)127;
- int left = count;
- for (int i = 8; i > 0; i--)
- {
- fragment[i] = (byte)(left % 256);
- left = left / 256;
- if (left == 0)
- break;
- }
- }
- // Mask: 1 bit
- // Defines whether the "Payload data" is masked.
- if (isMasked)
- fragment[0] = (byte)(fragment[0] | 0x80);
- // Masking-key: 0 or 4 bytes
- // The masking key is a 32-bit value chosen at random by the client.
- if (isMasked)
- {
- int maskingKeyIndex = fragment.Length - (MaskingKeyLength + count);
- for (var i = maskingKeyIndex; i < maskingKeyIndex + MaskingKeyLength; i++)
- {
- fragment[i] = (byte)_rng.Next(0, 255);
- }
- if (count > 0)
- {
- int payloadIndex = fragment.Length - count;
- for (var i = 0; i < count; i++)
- {
- fragment[payloadIndex + i] = (byte)(payload[offset + i] ^ fragment[maskingKeyIndex + i % MaskingKeyLength]);
- }
- }
- }
- else
- {
- if (count > 0)
- {
- int payloadIndex = fragment.Length - count;
- Array.Copy(payload, offset, fragment, payloadIndex, count);
- }
- }
- return fragment;
- }
- }
- public sealed class LengthPrefixedFrameDecoder : IFrameDecoder
- {
- private static readonly int MaskingKeyLength = 4;
- public LengthPrefixedFrameDecoder(bool isMasked = false)
- {
- IsMasked = isMasked;
- }
- public bool IsMasked { get; private set; }
- 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;
- var frameHeader = DecodeHeader(buffer, offset, count);
- if (frameHeader != null && frameHeader.Length + frameHeader.PayloadLength <= count)
- {
- if (IsMasked)
- {
- payload = DecodeMaskedPayload(buffer, offset, frameHeader.MaskingKeyOffset, frameHeader.Length, frameHeader.PayloadLength);
- payloadOffset = 0;
- payloadCount = payload.Length;
- }
- else
- {
- payload = buffer;
- payloadOffset = offset + frameHeader.Length;
- payloadCount = frameHeader.PayloadLength;
- }
- frameLength = frameHeader.Length + frameHeader.PayloadLength;
- return true;
- }
- return false;
- }
- 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 string.Format("IsMasked[{0}], PayloadLength[{1}], MaskingKeyOffset[{2}], Length[{3}]",
- IsMasked, PayloadLength, MaskingKeyOffset, Length);
- }
- }
- private static Header DecodeHeader(byte[] buffer, int offset, int count)
- {
- if (count < 1)
- return null;
- // parse fixed header
- var header = new Header()
- {
- IsMasked = ((buffer[offset + 0] & 0x80) == 0x80),
- PayloadLength = (buffer[offset + 0] & 0x7f),
- Length = 1,
- };
- // parse extended payload length
- 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 totalLength = 0;
- int level = 1;
- for (int i = 7; i >= 0; i--)
- {
- totalLength += buffer[offset + i + 1] * level;
- level *= 256;
- }
- header.PayloadLength = totalLength;
- }
- }
- // parse masking key
- 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)
- {
- var payload = new byte[payloadCount];
- for (var i = 0; i < payloadCount; i++)
- {
- payload[i] = (byte)(buffer[offset + payloadOffset + i] ^ buffer[offset + maskingKeyOffset + i % MaskingKeyLength]);
- }
- return payload;
- }
- }
- }
|