LengthPrefixedFrameBuilder.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. using System;
  2. using MECF.Framework.Common.Communications.Tcp.Socket.Framing.Base;
  3. namespace MECF.Framework.Common.Communications.Tcp.Socket.Framing
  4. {
  5. // A high-level overview of the framing is given in the following figure.
  6. // 0 1 2 3
  7. // 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
  8. // +-+-------------+-----------------------------------------------+
  9. // |M| Payload len | Extended payload length |
  10. // |A| (7) | (16/64) |
  11. // |S| | (if payload len==126/127) |
  12. // |K| | |
  13. // +-+-------------+- - - - - - - - - - - - - - - - - - - - - - - -+
  14. // | Extended payload length continued, if payload len == 127 |
  15. // + - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - +
  16. // | | Masking-key, if MASK set to 1 |
  17. // +---------------+- - - - - - - - - - - - - - - - - - - - - - - -+
  18. // | | Payload Data :
  19. // +----------------- - - - - - - - - - - - - - - - - - - - - - - -+
  20. // : Payload Data continued ... :
  21. // + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
  22. // | Payload Data continued ... |
  23. // +---------------------------------------------------------------+
  24. public sealed class LengthPrefixedFrameBuilder : FrameBuilder
  25. {
  26. public LengthPrefixedFrameBuilder(bool isMasked = false)
  27. : this(new LengthPrefixedFrameEncoder(isMasked), new LengthPrefixedFrameDecoder(isMasked))
  28. {
  29. }
  30. public LengthPrefixedFrameBuilder(LengthPrefixedFrameEncoder encoder, LengthPrefixedFrameDecoder decoder)
  31. : base(encoder, decoder)
  32. {
  33. }
  34. }
  35. public sealed class LengthPrefixedFrameEncoder : IFrameEncoder
  36. {
  37. private static readonly Random _rng = new Random(DateTime.UtcNow.Millisecond);
  38. private static readonly int MaskingKeyLength = 4;
  39. public LengthPrefixedFrameEncoder(bool isMasked = false)
  40. {
  41. IsMasked = isMasked;
  42. }
  43. public bool IsMasked { get; private set; }
  44. public void EncodeFrame(byte[] payload, int offset, int count, out byte[] frameBuffer, out int frameBufferOffset, out int frameBufferLength)
  45. {
  46. var buffer = Encode(payload, offset, count, IsMasked);
  47. frameBuffer = buffer;
  48. frameBufferOffset = 0;
  49. frameBufferLength = buffer.Length;
  50. }
  51. private static byte[] Encode(byte[] payload, int offset, int count, bool isMasked = false)
  52. {
  53. byte[] fragment;
  54. // Payload length: 7 bits, 7+16 bits, or 7+64 bits.
  55. // The length of the "Payload data", in bytes:
  56. // if 0-125, that is the payload length.
  57. // If 126, the following 2 bytes interpreted as a 16-bit unsigned integer are the payload length.
  58. // If 127, the following 8 bytes interpreted as a 64-bit unsigned integer are the payload length.
  59. if (count < 126)
  60. {
  61. fragment = new byte[1 + (isMasked ? MaskingKeyLength : 0) + count];
  62. fragment[0] = (byte)count;
  63. }
  64. else if (count < 65536)
  65. {
  66. fragment = new byte[1 + 2 + (isMasked ? MaskingKeyLength : 0) + count];
  67. fragment[0] = (byte)126;
  68. fragment[1] = (byte)(count / 256);
  69. fragment[2] = (byte)(count % 256);
  70. }
  71. else
  72. {
  73. fragment = new byte[1 + 8 + (isMasked ? MaskingKeyLength : 0) + count];
  74. fragment[0] = (byte)127;
  75. int left = count;
  76. for (int i = 8; i > 0; i--)
  77. {
  78. fragment[i] = (byte)(left % 256);
  79. left = left / 256;
  80. if (left == 0)
  81. break;
  82. }
  83. }
  84. // Mask: 1 bit
  85. // Defines whether the "Payload data" is masked.
  86. if (isMasked)
  87. fragment[0] = (byte)(fragment[0] | 0x80);
  88. // Masking-key: 0 or 4 bytes
  89. // The masking key is a 32-bit value chosen at random by the client.
  90. if (isMasked)
  91. {
  92. int maskingKeyIndex = fragment.Length - (MaskingKeyLength + count);
  93. for (var i = maskingKeyIndex; i < maskingKeyIndex + MaskingKeyLength; i++)
  94. {
  95. fragment[i] = (byte)_rng.Next(0, 255);
  96. }
  97. if (count > 0)
  98. {
  99. int payloadIndex = fragment.Length - count;
  100. for (var i = 0; i < count; i++)
  101. {
  102. fragment[payloadIndex + i] = (byte)(payload[offset + i] ^ fragment[maskingKeyIndex + i % MaskingKeyLength]);
  103. }
  104. }
  105. }
  106. else
  107. {
  108. if (count > 0)
  109. {
  110. int payloadIndex = fragment.Length - count;
  111. Array.Copy(payload, offset, fragment, payloadIndex, count);
  112. }
  113. }
  114. return fragment;
  115. }
  116. }
  117. public sealed class LengthPrefixedFrameDecoder : IFrameDecoder
  118. {
  119. private static readonly int MaskingKeyLength = 4;
  120. public LengthPrefixedFrameDecoder(bool isMasked = false)
  121. {
  122. IsMasked = isMasked;
  123. }
  124. public bool IsMasked { get; private set; }
  125. public bool TryDecodeFrame(byte[] buffer, int offset, int count, out int frameLength, out byte[] payload, out int payloadOffset, out int payloadCount)
  126. {
  127. frameLength = 0;
  128. payload = null;
  129. payloadOffset = 0;
  130. payloadCount = 0;
  131. var frameHeader = DecodeHeader(buffer, offset, count);
  132. if (frameHeader != null && frameHeader.Length + frameHeader.PayloadLength <= count)
  133. {
  134. if (IsMasked)
  135. {
  136. payload = DecodeMaskedPayload(buffer, offset, frameHeader.MaskingKeyOffset, frameHeader.Length, frameHeader.PayloadLength);
  137. payloadOffset = 0;
  138. payloadCount = payload.Length;
  139. }
  140. else
  141. {
  142. payload = buffer;
  143. payloadOffset = offset + frameHeader.Length;
  144. payloadCount = frameHeader.PayloadLength;
  145. }
  146. frameLength = frameHeader.Length + frameHeader.PayloadLength;
  147. return true;
  148. }
  149. return false;
  150. }
  151. internal sealed class Header
  152. {
  153. public bool IsMasked { get; set; }
  154. public int PayloadLength { get; set; }
  155. public int MaskingKeyOffset { get; set; }
  156. public int Length { get; set; }
  157. public override string ToString()
  158. {
  159. return string.Format("IsMasked[{0}], PayloadLength[{1}], MaskingKeyOffset[{2}], Length[{3}]",
  160. IsMasked, PayloadLength, MaskingKeyOffset, Length);
  161. }
  162. }
  163. private static Header DecodeHeader(byte[] buffer, int offset, int count)
  164. {
  165. if (count < 1)
  166. return null;
  167. // parse fixed header
  168. var header = new Header()
  169. {
  170. IsMasked = ((buffer[offset + 0] & 0x80) == 0x80),
  171. PayloadLength = (buffer[offset + 0] & 0x7f),
  172. Length = 1,
  173. };
  174. // parse extended payload length
  175. if (header.PayloadLength >= 126)
  176. {
  177. if (header.PayloadLength == 126)
  178. header.Length += 2;
  179. else
  180. header.Length += 8;
  181. if (count < header.Length)
  182. return null;
  183. if (header.PayloadLength == 126)
  184. {
  185. header.PayloadLength = buffer[offset + 1] * 256 + buffer[offset + 2];
  186. }
  187. else
  188. {
  189. int totalLength = 0;
  190. int level = 1;
  191. for (int i = 7; i >= 0; i--)
  192. {
  193. totalLength += buffer[offset + i + 1] * level;
  194. level *= 256;
  195. }
  196. header.PayloadLength = totalLength;
  197. }
  198. }
  199. // parse masking key
  200. if (header.IsMasked)
  201. {
  202. if (count < header.Length + MaskingKeyLength)
  203. return null;
  204. header.MaskingKeyOffset = header.Length;
  205. header.Length += MaskingKeyLength;
  206. }
  207. return header;
  208. }
  209. private static byte[] DecodeMaskedPayload(byte[] buffer, int offset, int maskingKeyOffset, int payloadOffset, int payloadCount)
  210. {
  211. var payload = new byte[payloadCount];
  212. for (var i = 0; i < payloadCount; i++)
  213. {
  214. payload[i] = (byte)(buffer[offset + payloadOffset + i] ^ buffer[offset + maskingKeyOffset + i % MaskingKeyLength]);
  215. }
  216. return payload;
  217. }
  218. }
  219. }