WebSocketFrame.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. #region License
  2. /*
  3. * WebSocketFrame.cs
  4. *
  5. * The MIT License
  6. *
  7. * Copyright (c) 2012-2023 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. #region Contributors
  29. /*
  30. * Contributors:
  31. * - Chris Swiedler
  32. */
  33. #endregion
  34. using System;
  35. using System.Collections;
  36. using System.Collections.Generic;
  37. using System.IO;
  38. using System.Text;
  39. namespace WebSocketSharp
  40. {
  41. internal class WebSocketFrame : IEnumerable<byte>
  42. {
  43. #region Private Fields
  44. private static readonly int _defaultHeaderLength;
  45. private static readonly int _defaultMaskingKeyLength;
  46. private byte[] _extPayloadLength;
  47. private Fin _fin;
  48. private Mask _mask;
  49. private byte[] _maskingKey;
  50. private Opcode _opcode;
  51. private PayloadData _payloadData;
  52. private byte _payloadLength;
  53. private Rsv _rsv1;
  54. private Rsv _rsv2;
  55. private Rsv _rsv3;
  56. #endregion
  57. #region Static Constructor
  58. static WebSocketFrame ()
  59. {
  60. _defaultHeaderLength = 2;
  61. _defaultMaskingKeyLength = 4;
  62. }
  63. #endregion
  64. #region Private Constructors
  65. private WebSocketFrame ()
  66. {
  67. }
  68. #endregion
  69. #region Internal Constructors
  70. internal WebSocketFrame (
  71. Fin fin, Opcode opcode, byte[] data, bool compressed, bool mask
  72. )
  73. : this (fin, opcode, new PayloadData (data), compressed, mask)
  74. {
  75. }
  76. internal WebSocketFrame (
  77. Fin fin,
  78. Opcode opcode,
  79. PayloadData payloadData,
  80. bool compressed,
  81. bool mask
  82. )
  83. {
  84. _fin = fin;
  85. _opcode = opcode;
  86. _rsv1 = compressed ? Rsv.On : Rsv.Off;
  87. _rsv2 = Rsv.Off;
  88. _rsv3 = Rsv.Off;
  89. var len = payloadData.Length;
  90. if (len < 126) {
  91. _payloadLength = (byte) len;
  92. _extPayloadLength = WebSocket.EmptyBytes;
  93. }
  94. else if (len < 0x010000) {
  95. _payloadLength = (byte) 126;
  96. _extPayloadLength = ((ushort) len).ToByteArray (ByteOrder.Big);
  97. }
  98. else {
  99. _payloadLength = (byte) 127;
  100. _extPayloadLength = len.ToByteArray (ByteOrder.Big);
  101. }
  102. if (mask) {
  103. _mask = Mask.On;
  104. _maskingKey = createMaskingKey ();
  105. payloadData.Mask (_maskingKey);
  106. }
  107. else {
  108. _mask = Mask.Off;
  109. _maskingKey = WebSocket.EmptyBytes;
  110. }
  111. _payloadData = payloadData;
  112. }
  113. #endregion
  114. #region Internal Properties
  115. internal ulong ExactPayloadLength {
  116. get {
  117. return _payloadLength < 126
  118. ? _payloadLength
  119. : _payloadLength == 126
  120. ? _extPayloadLength.ToUInt16 (ByteOrder.Big)
  121. : _extPayloadLength.ToUInt64 (ByteOrder.Big);
  122. }
  123. }
  124. internal int ExtendedPayloadLengthWidth {
  125. get {
  126. return _payloadLength < 126
  127. ? 0
  128. : _payloadLength == 126
  129. ? 2
  130. : 8;
  131. }
  132. }
  133. #endregion
  134. #region Public Properties
  135. public byte[] ExtendedPayloadLength {
  136. get {
  137. return _extPayloadLength;
  138. }
  139. }
  140. public Fin Fin {
  141. get {
  142. return _fin;
  143. }
  144. }
  145. public bool IsBinary {
  146. get {
  147. return _opcode == Opcode.Binary;
  148. }
  149. }
  150. public bool IsClose {
  151. get {
  152. return _opcode == Opcode.Close;
  153. }
  154. }
  155. public bool IsCompressed {
  156. get {
  157. return _rsv1 == Rsv.On;
  158. }
  159. }
  160. public bool IsContinuation {
  161. get {
  162. return _opcode == Opcode.Cont;
  163. }
  164. }
  165. public bool IsControl {
  166. get {
  167. return _opcode >= Opcode.Close;
  168. }
  169. }
  170. public bool IsData {
  171. get {
  172. return _opcode == Opcode.Text || _opcode == Opcode.Binary;
  173. }
  174. }
  175. public bool IsFinal {
  176. get {
  177. return _fin == Fin.Final;
  178. }
  179. }
  180. public bool IsFragment {
  181. get {
  182. return _fin == Fin.More || _opcode == Opcode.Cont;
  183. }
  184. }
  185. public bool IsMasked {
  186. get {
  187. return _mask == Mask.On;
  188. }
  189. }
  190. public bool IsPing {
  191. get {
  192. return _opcode == Opcode.Ping;
  193. }
  194. }
  195. public bool IsPong {
  196. get {
  197. return _opcode == Opcode.Pong;
  198. }
  199. }
  200. public bool IsText {
  201. get {
  202. return _opcode == Opcode.Text;
  203. }
  204. }
  205. public ulong Length {
  206. get {
  207. return (ulong) (
  208. _defaultHeaderLength
  209. + _extPayloadLength.Length
  210. + _maskingKey.Length
  211. )
  212. + _payloadData.Length;
  213. }
  214. }
  215. public Mask Mask {
  216. get {
  217. return _mask;
  218. }
  219. }
  220. public byte[] MaskingKey {
  221. get {
  222. return _maskingKey;
  223. }
  224. }
  225. public Opcode Opcode {
  226. get {
  227. return _opcode;
  228. }
  229. }
  230. public PayloadData PayloadData {
  231. get {
  232. return _payloadData;
  233. }
  234. }
  235. public byte PayloadLength {
  236. get {
  237. return _payloadLength;
  238. }
  239. }
  240. public Rsv Rsv1 {
  241. get {
  242. return _rsv1;
  243. }
  244. }
  245. public Rsv Rsv2 {
  246. get {
  247. return _rsv2;
  248. }
  249. }
  250. public Rsv Rsv3 {
  251. get {
  252. return _rsv3;
  253. }
  254. }
  255. #endregion
  256. #region Private Methods
  257. private static byte[] createMaskingKey ()
  258. {
  259. var key = new byte[_defaultMaskingKeyLength];
  260. WebSocket.RandomNumber.GetBytes (key);
  261. return key;
  262. }
  263. private static WebSocketFrame processHeader (byte[] header)
  264. {
  265. if (header.Length != _defaultHeaderLength) {
  266. var msg = "The header part of a frame could not be read.";
  267. throw new WebSocketException (msg);
  268. }
  269. // FIN
  270. var fin = (header[0] & 0x80) == 0x80 ? Fin.Final : Fin.More;
  271. // RSV1
  272. var rsv1 = (header[0] & 0x40) == 0x40 ? Rsv.On : Rsv.Off;
  273. // RSV2
  274. var rsv2 = (header[0] & 0x20) == 0x20 ? Rsv.On : Rsv.Off;
  275. // RSV3
  276. var rsv3 = (header[0] & 0x10) == 0x10 ? Rsv.On : Rsv.Off;
  277. // Opcode
  278. var opcode = (byte) (header[0] & 0x0f);
  279. // MASK
  280. var mask = (header[1] & 0x80) == 0x80 ? Mask.On : Mask.Off;
  281. // Payload Length
  282. var payloadLen = (byte) (header[1] & 0x7f);
  283. if (!opcode.IsSupportedOpcode ()) {
  284. var msg = "The opcode of a frame is not supported.";
  285. throw new WebSocketException (CloseStatusCode.UnsupportedData, msg);
  286. }
  287. var frame = new WebSocketFrame ();
  288. frame._fin = fin;
  289. frame._rsv1 = rsv1;
  290. frame._rsv2 = rsv2;
  291. frame._rsv3 = rsv3;
  292. frame._opcode = (Opcode) opcode;
  293. frame._mask = mask;
  294. frame._payloadLength = payloadLen;
  295. return frame;
  296. }
  297. private static WebSocketFrame readExtendedPayloadLength (
  298. Stream stream, WebSocketFrame frame
  299. )
  300. {
  301. var len = frame.ExtendedPayloadLengthWidth;
  302. if (len == 0) {
  303. frame._extPayloadLength = WebSocket.EmptyBytes;
  304. return frame;
  305. }
  306. var bytes = stream.ReadBytes (len);
  307. if (bytes.Length != len) {
  308. var msg = "The extended payload length of a frame could not be read.";
  309. throw new WebSocketException (msg);
  310. }
  311. frame._extPayloadLength = bytes;
  312. return frame;
  313. }
  314. private static void readExtendedPayloadLengthAsync (
  315. Stream stream,
  316. WebSocketFrame frame,
  317. Action<WebSocketFrame> completed,
  318. Action<Exception> error
  319. )
  320. {
  321. var len = frame.ExtendedPayloadLengthWidth;
  322. if (len == 0) {
  323. frame._extPayloadLength = WebSocket.EmptyBytes;
  324. completed (frame);
  325. return;
  326. }
  327. stream.ReadBytesAsync (
  328. len,
  329. bytes => {
  330. if (bytes.Length != len) {
  331. var msg = "The extended payload length of a frame could not be read.";
  332. throw new WebSocketException (msg);
  333. }
  334. frame._extPayloadLength = bytes;
  335. completed (frame);
  336. },
  337. error
  338. );
  339. }
  340. private static WebSocketFrame readHeader (Stream stream)
  341. {
  342. var bytes = stream.ReadBytes (_defaultHeaderLength);
  343. return processHeader (bytes);
  344. }
  345. private static void readHeaderAsync (
  346. Stream stream, Action<WebSocketFrame> completed, Action<Exception> error
  347. )
  348. {
  349. stream.ReadBytesAsync (
  350. _defaultHeaderLength,
  351. bytes => {
  352. var frame = processHeader (bytes);
  353. completed (frame);
  354. },
  355. error
  356. );
  357. }
  358. private static WebSocketFrame readMaskingKey (
  359. Stream stream, WebSocketFrame frame
  360. )
  361. {
  362. if (!frame.IsMasked) {
  363. frame._maskingKey = WebSocket.EmptyBytes;
  364. return frame;
  365. }
  366. var bytes = stream.ReadBytes (_defaultMaskingKeyLength);
  367. if (bytes.Length != _defaultMaskingKeyLength) {
  368. var msg = "The masking key of a frame could not be read.";
  369. throw new WebSocketException (msg);
  370. }
  371. frame._maskingKey = bytes;
  372. return frame;
  373. }
  374. private static void readMaskingKeyAsync (
  375. Stream stream,
  376. WebSocketFrame frame,
  377. Action<WebSocketFrame> completed,
  378. Action<Exception> error
  379. )
  380. {
  381. if (!frame.IsMasked) {
  382. frame._maskingKey = WebSocket.EmptyBytes;
  383. completed (frame);
  384. return;
  385. }
  386. stream.ReadBytesAsync (
  387. _defaultMaskingKeyLength,
  388. bytes => {
  389. if (bytes.Length != _defaultMaskingKeyLength) {
  390. var msg = "The masking key of a frame could not be read.";
  391. throw new WebSocketException (msg);
  392. }
  393. frame._maskingKey = bytes;
  394. completed (frame);
  395. },
  396. error
  397. );
  398. }
  399. private static WebSocketFrame readPayloadData (
  400. Stream stream, WebSocketFrame frame
  401. )
  402. {
  403. var exactPayloadLen = frame.ExactPayloadLength;
  404. if (exactPayloadLen > PayloadData.MaxLength) {
  405. var msg = "The payload data of a frame is too big.";
  406. throw new WebSocketException (CloseStatusCode.TooBig, msg);
  407. }
  408. if (exactPayloadLen == 0) {
  409. frame._payloadData = PayloadData.Empty;
  410. return frame;
  411. }
  412. var len = (long) exactPayloadLen;
  413. var bytes = frame._payloadLength > 126
  414. ? stream.ReadBytes (len, 1024)
  415. : stream.ReadBytes ((int) len);
  416. if (bytes.LongLength != len) {
  417. var msg = "The payload data of a frame could not be read.";
  418. throw new WebSocketException (msg);
  419. }
  420. frame._payloadData = new PayloadData (bytes, len);
  421. return frame;
  422. }
  423. private static void readPayloadDataAsync (
  424. Stream stream,
  425. WebSocketFrame frame,
  426. Action<WebSocketFrame> completed,
  427. Action<Exception> error
  428. )
  429. {
  430. var exactPayloadLen = frame.ExactPayloadLength;
  431. if (exactPayloadLen > PayloadData.MaxLength) {
  432. var msg = "The payload data of a frame is too big.";
  433. throw new WebSocketException (CloseStatusCode.TooBig, msg);
  434. }
  435. if (exactPayloadLen == 0) {
  436. frame._payloadData = PayloadData.Empty;
  437. completed (frame);
  438. return;
  439. }
  440. var len = (long) exactPayloadLen;
  441. Action<byte[]> comp =
  442. bytes => {
  443. if (bytes.LongLength != len) {
  444. var msg = "The payload data of a frame could not be read.";
  445. throw new WebSocketException (msg);
  446. }
  447. frame._payloadData = new PayloadData (bytes, len);
  448. completed (frame);
  449. };
  450. if (frame._payloadLength > 126) {
  451. stream.ReadBytesAsync (len, 1024, comp, error);
  452. return;
  453. }
  454. stream.ReadBytesAsync ((int) len, comp, error);
  455. }
  456. private string toDumpString ()
  457. {
  458. var len = Length;
  459. var cnt = (long) (len / 4);
  460. var rem = (int) (len % 4);
  461. string spFmt;
  462. string cntFmt;
  463. if (cnt < 10000) {
  464. spFmt = "{0,4}";
  465. cntFmt = "{0,4}";
  466. }
  467. else if (cnt < 0x010000) {
  468. spFmt = "{0,4}";
  469. cntFmt = "{0,4:X}";
  470. }
  471. else if (cnt < 0x0100000000) {
  472. spFmt = "{0,8}";
  473. cntFmt = "{0,8:X}";
  474. }
  475. else {
  476. spFmt = "{0,16}";
  477. cntFmt = "{0,16:X}";
  478. }
  479. var baseFmt = @"{0} 01234567 89ABCDEF 01234567 89ABCDEF
  480. {0}+--------+--------+--------+--------+
  481. ";
  482. var headerFmt = String.Format (baseFmt, spFmt);
  483. baseFmt = "{0}|{{1,8}} {{2,8}} {{3,8}} {{4,8}}|\n";
  484. var lineFmt = String.Format (baseFmt, cntFmt);
  485. baseFmt = "{0}+--------+--------+--------+--------+";
  486. var footerFmt = String.Format (baseFmt, spFmt);
  487. var buff = new StringBuilder (64);
  488. Func<Action<string, string, string, string>> lineWriter =
  489. () => {
  490. long lineCnt = 0;
  491. return (arg1, arg2, arg3, arg4) => {
  492. buff.AppendFormat (
  493. lineFmt, ++lineCnt, arg1, arg2, arg3, arg4
  494. );
  495. };
  496. };
  497. var writeLine = lineWriter ();
  498. var bytes = ToArray ();
  499. buff.AppendFormat (headerFmt, String.Empty);
  500. for (long i = 0; i <= cnt; i++) {
  501. var j = i * 4;
  502. if (i < cnt) {
  503. var arg1 = Convert.ToString (bytes[j], 2).PadLeft (8, '0');
  504. var arg2 = Convert.ToString (bytes[j + 1], 2).PadLeft (8, '0');
  505. var arg3 = Convert.ToString (bytes[j + 2], 2).PadLeft (8, '0');
  506. var arg4 = Convert.ToString (bytes[j + 3], 2).PadLeft (8, '0');
  507. writeLine (arg1, arg2, arg3, arg4);
  508. continue;
  509. }
  510. if (rem > 0) {
  511. var arg1 = Convert.ToString (bytes[j], 2).PadLeft (8, '0');
  512. var arg2 = rem >= 2
  513. ? Convert.ToString (bytes[j + 1], 2).PadLeft (8, '0')
  514. : String.Empty;
  515. var arg3 = rem == 3
  516. ? Convert.ToString (bytes[j + 2], 2).PadLeft (8, '0')
  517. : String.Empty;
  518. writeLine (arg1, arg2, arg3, String.Empty);
  519. }
  520. }
  521. buff.AppendFormat (footerFmt, String.Empty);
  522. return buff.ToString ();
  523. }
  524. private string toString ()
  525. {
  526. var extPayloadLen = _payloadLength >= 126
  527. ? ExactPayloadLength.ToString ()
  528. : String.Empty;
  529. var maskingKey = _mask == Mask.On
  530. ? BitConverter.ToString (_maskingKey)
  531. : String.Empty;
  532. var payloadData = _payloadLength >= 126
  533. ? "***"
  534. : _payloadLength > 0
  535. ? _payloadData.ToString ()
  536. : String.Empty;
  537. var fmt = @" FIN: {0}
  538. RSV1: {1}
  539. RSV2: {2}
  540. RSV3: {3}
  541. Opcode: {4}
  542. MASK: {5}
  543. Payload Length: {6}
  544. Extended Payload Length: {7}
  545. Masking Key: {8}
  546. Payload Data: {9}";
  547. return String.Format (
  548. fmt,
  549. _fin,
  550. _rsv1,
  551. _rsv2,
  552. _rsv3,
  553. _opcode,
  554. _mask,
  555. _payloadLength,
  556. extPayloadLen,
  557. maskingKey,
  558. payloadData
  559. );
  560. }
  561. #endregion
  562. #region Internal Methods
  563. internal static WebSocketFrame CreateCloseFrame (
  564. PayloadData payloadData, bool mask
  565. )
  566. {
  567. return new WebSocketFrame (
  568. Fin.Final, Opcode.Close, payloadData, false, mask
  569. );
  570. }
  571. internal static WebSocketFrame CreatePingFrame (bool mask)
  572. {
  573. return new WebSocketFrame (
  574. Fin.Final, Opcode.Ping, PayloadData.Empty, false, mask
  575. );
  576. }
  577. internal static WebSocketFrame CreatePingFrame (byte[] data, bool mask)
  578. {
  579. return new WebSocketFrame (
  580. Fin.Final, Opcode.Ping, new PayloadData (data), false, mask
  581. );
  582. }
  583. internal static WebSocketFrame CreatePongFrame (
  584. PayloadData payloadData, bool mask
  585. )
  586. {
  587. return new WebSocketFrame (
  588. Fin.Final, Opcode.Pong, payloadData, false, mask
  589. );
  590. }
  591. internal static WebSocketFrame ReadFrame (Stream stream, bool unmask)
  592. {
  593. var frame = readHeader (stream);
  594. readExtendedPayloadLength (stream, frame);
  595. readMaskingKey (stream, frame);
  596. readPayloadData (stream, frame);
  597. if (unmask)
  598. frame.Unmask ();
  599. return frame;
  600. }
  601. internal static void ReadFrameAsync (
  602. Stream stream,
  603. bool unmask,
  604. Action<WebSocketFrame> completed,
  605. Action<Exception> error
  606. )
  607. {
  608. readHeaderAsync (
  609. stream,
  610. frame =>
  611. readExtendedPayloadLengthAsync (
  612. stream,
  613. frame,
  614. frame1 =>
  615. readMaskingKeyAsync (
  616. stream,
  617. frame1,
  618. frame2 =>
  619. readPayloadDataAsync (
  620. stream,
  621. frame2,
  622. frame3 => {
  623. if (unmask)
  624. frame3.Unmask ();
  625. completed (frame3);
  626. },
  627. error
  628. ),
  629. error
  630. ),
  631. error
  632. ),
  633. error
  634. );
  635. }
  636. internal string ToString (bool dump)
  637. {
  638. return dump ? toDumpString () : toString ();
  639. }
  640. internal void Unmask ()
  641. {
  642. if (_mask == Mask.Off)
  643. return;
  644. _payloadData.Mask (_maskingKey);
  645. _maskingKey = WebSocket.EmptyBytes;
  646. _mask = Mask.Off;
  647. }
  648. #endregion
  649. #region Public Methods
  650. public IEnumerator<byte> GetEnumerator ()
  651. {
  652. foreach (var b in ToArray ())
  653. yield return b;
  654. }
  655. public byte[] ToArray ()
  656. {
  657. using (var buff = new MemoryStream ()) {
  658. var header = (int) _fin;
  659. header = (header << 1) + (int) _rsv1;
  660. header = (header << 1) + (int) _rsv2;
  661. header = (header << 1) + (int) _rsv3;
  662. header = (header << 4) + (int) _opcode;
  663. header = (header << 1) + (int) _mask;
  664. header = (header << 7) + (int) _payloadLength;
  665. var uint16Header = (ushort) header;
  666. var rawHeader = uint16Header.ToByteArray (ByteOrder.Big);
  667. buff.Write (rawHeader, 0, _defaultHeaderLength);
  668. if (_payloadLength >= 126)
  669. buff.Write (_extPayloadLength, 0, _extPayloadLength.Length);
  670. if (_mask == Mask.On)
  671. buff.Write (_maskingKey, 0, _defaultMaskingKeyLength);
  672. if (_payloadLength > 0) {
  673. var bytes = _payloadData.ToArray ();
  674. if (_payloadLength > 126)
  675. buff.WriteBytes (bytes, 1024);
  676. else
  677. buff.Write (bytes, 0, bytes.Length);
  678. }
  679. buff.Close ();
  680. return buff.ToArray ();
  681. }
  682. }
  683. public override string ToString ()
  684. {
  685. var val = ToArray ();
  686. return BitConverter.ToString (val);
  687. }
  688. #endregion
  689. #region Explicit Interface Implementations
  690. IEnumerator IEnumerable.GetEnumerator ()
  691. {
  692. return GetEnumerator ();
  693. }
  694. #endregion
  695. }
  696. }