WsFrame.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. #region MIT License
  2. /**
  3. * WsFrame.cs
  4. *
  5. * The MIT License
  6. *
  7. * Copyright (c) 2012 sta.blockhead
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. */
  27. #endregion
  28. using System;
  29. using System.IO;
  30. using System.Collections;
  31. using System.Collections.Generic;
  32. using System.Text;
  33. namespace WebSocketSharp.Frame
  34. {
  35. public class WsFrame : IEnumerable<byte>
  36. {
  37. #region Field
  38. private const int _readBufferLen = 1024;
  39. #endregion
  40. #region Private Constructor
  41. private WsFrame()
  42. {
  43. Rsv1 = Rsv.OFF;
  44. Rsv2 = Rsv.OFF;
  45. Rsv3 = Rsv.OFF;
  46. ExtPayloadLen = new byte[] { };
  47. MaskingKey = new byte[] { };
  48. }
  49. #endregion
  50. #region Public Constructors
  51. public WsFrame(Opcode opcode, PayloadData payloadData)
  52. : this(Fin.FINAL, opcode, payloadData)
  53. {
  54. }
  55. public WsFrame(Fin fin, Opcode opcode, PayloadData payloadData)
  56. : this(fin, opcode, Mask.MASK, payloadData)
  57. {
  58. }
  59. public WsFrame(Fin fin, Opcode opcode, Mask mask, PayloadData payloadData)
  60. : this()
  61. {
  62. Fin = fin;
  63. Opcode = opcode;
  64. //Masked = payloadData.Length != 0 ? mask : Mask.UNMASK;
  65. //client->server always mask whatever having payload
  66. //https://github.com/wsky/websocket-sharp/issues/2
  67. Masked = mask;
  68. PayloadData = payloadData;
  69. init();
  70. }
  71. #endregion
  72. #region Properties
  73. public Fin Fin { get; private set; }
  74. public Rsv Rsv1 { get; private set; }
  75. public Rsv Rsv2 { get; private set; }
  76. public Rsv Rsv3 { get; private set; }
  77. public Opcode Opcode { get; private set; }
  78. public Mask Masked { get; private set; }
  79. public byte PayloadLen { get; private set; }
  80. public byte[] ExtPayloadLen { get; private set; }
  81. public byte[] MaskingKey { get; private set; }
  82. public PayloadData PayloadData { get; private set; }
  83. public ulong Length
  84. {
  85. get
  86. {
  87. return 2 + (ulong)(ExtPayloadLen.Length + MaskingKey.Length) + PayloadLength;
  88. }
  89. }
  90. public ulong PayloadLength
  91. {
  92. get
  93. {
  94. return PayloadData.Length;
  95. }
  96. }
  97. #endregion
  98. #region Private Methods
  99. IEnumerator IEnumerable.GetEnumerator()
  100. {
  101. return GetEnumerator();
  102. }
  103. private void init()
  104. {
  105. setPayloadLen(PayloadLength);
  106. if (Masked == Mask.MASK)
  107. maskPayloadData();
  108. }
  109. private void maskPayloadData()
  110. {
  111. var key = new byte[4];
  112. var rand = new Random();
  113. rand.NextBytes(key);
  114. MaskingKey = key;
  115. PayloadData.Mask(key);
  116. }
  117. private static WsFrame parse(Stream stream, bool unmask)
  118. {
  119. return parse(Ext.ReadBytes(stream, 2), stream, unmask);
  120. }
  121. private static WsFrame parse(byte[] header, Stream stream, bool unmask)
  122. {
  123. if (header == null || header.Length != 2)
  124. return null;
  125. try
  126. {
  127. var frame = readHeader(header);
  128. readExtPayloadLen(stream, frame);
  129. readMaskingKey(stream, frame);
  130. readPayloadData(stream, frame, unmask);
  131. return frame;
  132. }
  133. catch
  134. {
  135. return null;
  136. }
  137. }
  138. private static void readExtPayloadLen(Stream stream, WsFrame frame)
  139. {
  140. var length = frame.PayloadLen <= 125
  141. ? 0
  142. : frame.PayloadLen == 126
  143. ? 2
  144. : 8;
  145. if (length == 0)
  146. return;
  147. var extLen = Ext.ReadBytes(stream, length);
  148. if (extLen.Length != length)
  149. throw new IOException();
  150. frame.ExtPayloadLen = extLen;
  151. }
  152. private static WsFrame readHeader(byte[] header)
  153. {
  154. // FIN
  155. Fin fin = (header[0] & 0x80) == 0x80 ? Fin.FINAL : Fin.MORE;
  156. // RSV1
  157. Rsv rsv1 = (header[0] & 0x40) == 0x40 ? Rsv.ON : Rsv.OFF;
  158. // RSV2
  159. Rsv rsv2 = (header[0] & 0x20) == 0x20 ? Rsv.ON : Rsv.OFF;
  160. // RSV3
  161. Rsv rsv3 = (header[0] & 0x10) == 0x10 ? Rsv.ON : Rsv.OFF;
  162. // Opcode
  163. Opcode opcode = (Opcode)(header[0] & 0x0f);
  164. // MASK
  165. Mask masked = (header[1] & 0x80) == 0x80 ? Mask.MASK : Mask.UNMASK;
  166. // Payload len
  167. byte payloadLen = (byte)(header[1] & 0x7f);
  168. return new WsFrame
  169. {
  170. Fin = fin,
  171. Rsv1 = rsv1,
  172. Rsv2 = rsv2,
  173. Rsv3 = rsv3,
  174. Opcode = opcode,
  175. Masked = masked,
  176. PayloadLen = payloadLen
  177. };
  178. }
  179. private static void readMaskingKey(Stream stream, WsFrame frame)
  180. {
  181. if (frame.Masked == Mask.UNMASK)
  182. return;
  183. var maskingKey = Ext.ReadBytes(stream, 4);
  184. if (maskingKey.Length != 4)
  185. throw new IOException();
  186. frame.MaskingKey = maskingKey;
  187. }
  188. private static void readPayloadData(Stream stream, WsFrame frame, bool unmask)
  189. {
  190. ulong length = frame.PayloadLen <= 125
  191. ? frame.PayloadLen
  192. : frame.PayloadLen == 126
  193. ? Ext.To<ushort>(frame.ExtPayloadLen, ByteOrder.BIG)
  194. : Ext.To<ushort>(frame.ExtPayloadLen, ByteOrder.BIG);
  195. if (length == 0)
  196. {
  197. frame.PayloadData = new PayloadData(new byte[] { });
  198. return;
  199. }
  200. if (frame.PayloadLen > 126 && length > PayloadData.MaxLength)
  201. throw new WsReceivedTooBigMessageException();
  202. var buffer = Ext.ReadBytes(stream, (int)length);
  203. //var buffer = length <= (ulong)_readBufferLen
  204. // ? Ext.ReadBytes(stream, (int)length)
  205. // : Ext.ReadBytes(stream, (long)length, _readBufferLen);
  206. if (buffer.LongLength != (long)length)
  207. throw new IOException();
  208. var payloadData = frame.Masked == Mask.MASK
  209. ? new PayloadData(buffer, true)
  210. : new PayloadData(buffer);
  211. if (frame.Masked == Mask.MASK && unmask)
  212. {
  213. payloadData.Mask(frame.MaskingKey);
  214. frame.Masked = Mask.UNMASK;
  215. frame.MaskingKey = new byte[] { };
  216. }
  217. frame.PayloadData = payloadData;
  218. }
  219. private void setPayloadLen(ulong length)
  220. {
  221. if (length < 126)
  222. {
  223. PayloadLen = (byte)length;
  224. return;
  225. }
  226. if (length < 0x010000)
  227. {
  228. PayloadLen = (byte)126;
  229. ExtPayloadLen = Ext.ToBytes((ushort)length, ByteOrder.BIG);
  230. return;
  231. }
  232. PayloadLen = (byte)127;
  233. ExtPayloadLen = Ext.ToBytes(length, ByteOrder.BIG);
  234. }
  235. #endregion
  236. #region Public Methods
  237. public IEnumerator<byte> GetEnumerator()
  238. {
  239. foreach (byte b in ToBytes())
  240. yield return b;
  241. }
  242. public static WsFrame Parse(byte[] src)
  243. {
  244. return Parse(src, true);
  245. }
  246. public static WsFrame Parse(byte[] src, bool unmask)
  247. {
  248. using (MemoryStream ms = new MemoryStream(src))
  249. {
  250. return Parse(ms, unmask);
  251. }
  252. }
  253. public static WsFrame Parse(Stream stream)
  254. {
  255. return Parse(stream, true);
  256. }
  257. public static WsFrame Parse(Stream stream, bool unmask)
  258. {
  259. return parse(stream, unmask);
  260. }
  261. public static void ParseAsync(Stream stream, Action<WsFrame> completed)
  262. {
  263. ParseAsync(stream, true, completed);
  264. }
  265. public static void ParseAsync(Stream stream, bool unmask, Action<WsFrame> completed)
  266. {
  267. var headerLen = 2;
  268. var header = new byte[headerLen];
  269. AsyncCallback callback = (ar) =>
  270. {
  271. WsFrame frame = null;
  272. try
  273. {
  274. var readLen = stream.EndRead(ar);
  275. frame = readLen == 2
  276. ? parse(header, stream, unmask)
  277. : null;
  278. }
  279. catch
  280. {
  281. frame = null;
  282. }
  283. finally
  284. {
  285. if (completed != null)
  286. completed(frame);
  287. }
  288. };
  289. stream.BeginRead(header, 0, headerLen, callback, null);
  290. }
  291. public void Print()
  292. {
  293. byte[] buffer;
  294. long count, i, j;
  295. int countDigit, remainder;
  296. string countFmt, extPayloadLen, headerFmt, topLineFmt, bottomLineFmt, payloadData, spFmt;
  297. switch (ExtPayloadLen.Length)
  298. {
  299. case 2:
  300. extPayloadLen = Ext.To<ushort>(ExtPayloadLen, ByteOrder.BIG).ToString();
  301. break;
  302. case 8:
  303. extPayloadLen = Ext.To<ulong>(ExtPayloadLen, ByteOrder.BIG).ToString();
  304. break;
  305. default:
  306. extPayloadLen = String.Empty;
  307. break;
  308. }
  309. if (((Opcode.TEXT | Opcode.PING | Opcode.PONG) & Opcode) == Opcode &&
  310. Masked == Mask.UNMASK &&
  311. PayloadLength > 0)
  312. {
  313. payloadData = Encoding.UTF8.GetString(PayloadData.ToBytes());
  314. }
  315. else
  316. {
  317. payloadData = BitConverter.ToString(PayloadData.ToBytes());
  318. }
  319. headerFmt = @"
  320. WsFrame:
  321. FIN={0}, RSV1={1}, RSV2={2}, RSV3={3}, Opcode={4},
  322. MASK={5}, Payload Len={6}, Extended Payload Len={7},
  323. Masking Key ={8},
  324. Payload Data={9}";
  325. buffer = ToBytes();
  326. count = (long)(Length / 4);
  327. remainder = (int)(Length % 4);
  328. if (count < 10000)
  329. {
  330. countDigit = 4;
  331. countFmt = "{0,4}";
  332. }
  333. else if (count < 0x010000)
  334. {
  335. countDigit = 4;
  336. countFmt = "{0,4:X}";
  337. }
  338. else if (count < 0x0100000000)
  339. {
  340. countDigit = 8;
  341. countFmt = "{0,8:X}";
  342. }
  343. else
  344. {
  345. countDigit = 16;
  346. countFmt = "{0,16:X}";
  347. }
  348. spFmt = String.Format("{{0,{0}}}", countDigit);
  349. topLineFmt = String.Format(@"
  350. {0} 01234567 89ABCDEF 01234567 89ABCDEF
  351. {0}+--------+--------+--------+--------+", spFmt);
  352. Func<string, Action<string, string, string, string>> func = s =>
  353. {
  354. long lineCount = 0;
  355. string lineFmt = String.Format(" {0}|{{1,8}} {{2,8}} {{3,8}} {{4,8}}|", s);
  356. return (arg1, arg2, arg3, arg4) =>
  357. {
  358. Console.WriteLine(lineFmt, ++lineCount, arg1, arg2, arg3, arg4);
  359. };
  360. };
  361. var printLine = func(countFmt);
  362. bottomLineFmt = String.Format(" {0}+--------+--------+--------+--------+", spFmt);
  363. Console.WriteLine(headerFmt,
  364. Fin, Rsv1, Rsv2, Rsv3, Opcode,
  365. Masked, PayloadLen, extPayloadLen,
  366. BitConverter.ToString(MaskingKey),
  367. payloadData);
  368. Console.WriteLine(topLineFmt, String.Empty);
  369. for (i = 0; i <= count; i++)
  370. {
  371. j = i * 4;
  372. if (i < count)
  373. {
  374. printLine(
  375. Convert.ToString(buffer[j], 2).PadLeft(8, '0'),
  376. Convert.ToString(buffer[j + 1], 2).PadLeft(8, '0'),
  377. Convert.ToString(buffer[j + 2], 2).PadLeft(8, '0'),
  378. Convert.ToString(buffer[j + 3], 2).PadLeft(8, '0'));
  379. }
  380. else if (i == count && remainder > 0)
  381. {
  382. printLine(
  383. Convert.ToString(buffer[j], 2).PadLeft(8, '0'),
  384. remainder >= 2 ? Convert.ToString(buffer[j + 1], 2).PadLeft(8, '0') : String.Empty,
  385. remainder == 3 ? Convert.ToString(buffer[j + 2], 2).PadLeft(8, '0') : String.Empty,
  386. String.Empty);
  387. }
  388. }
  389. Console.WriteLine(bottomLineFmt, String.Empty);
  390. }
  391. public byte[] ToBytes()
  392. {
  393. var buffer = new List<byte>();
  394. var header = (int)Fin;
  395. header = (header << 1) + (int)Rsv1;
  396. header = (header << 1) + (int)Rsv2;
  397. header = (header << 1) + (int)Rsv3;
  398. header = (header << 4) + (int)Opcode;
  399. header = (header << 1) + (int)Masked;
  400. header = (header << 7) + (int)PayloadLen;
  401. buffer.AddRange(Ext.ToBytes((ushort)header, ByteOrder.BIG));
  402. if (PayloadLen >= 126)
  403. buffer.AddRange(ExtPayloadLen);
  404. if (Masked == Mask.MASK)
  405. buffer.AddRange(MaskingKey);
  406. if (PayloadLen > 0)
  407. buffer.AddRange(PayloadData.ToBytes());
  408. return buffer.ToArray();
  409. }
  410. public override string ToString()
  411. {
  412. return BitConverter.ToString(ToBytes());
  413. }
  414. #endregion
  415. }
  416. }