websocket-sharp/websocket-sharp/WsFrame.cs

714 lines
18 KiB
C#
Raw Normal View History

2013-04-08 14:11:57 +08:00
#region License
2013-01-11 19:32:38 +08:00
/*
2012-07-31 09:36:52 +08:00
* WsFrame.cs
*
* The MIT License
*
2013-01-15 14:29:05 +08:00
* Copyright (c) 2012-2013 sta.blockhead
2012-07-31 09:36:52 +08:00
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.IO;
2012-10-04 14:04:21 +08:00
using System.Collections;
2012-07-31 09:36:52 +08:00
using System.Collections.Generic;
using System.Text;
2013-10-01 13:52:39 +08:00
namespace WebSocketSharp
{
2013-01-15 14:29:05 +08:00
internal class WsFrame : IEnumerable<byte>
2012-07-31 09:36:52 +08:00
{
#region Internal Static Fields
internal static readonly byte [] EmptyUnmaskPingData;
#endregion
#region Static Constructor
static WsFrame ()
{
EmptyUnmaskPingData = CreatePingFrame (Mask.UNMASK).ToByteArray ();
}
#endregion
2013-04-08 14:11:57 +08:00
#region Private Constructors
2012-07-31 09:36:52 +08:00
2013-10-01 13:52:39 +08:00
private WsFrame ()
2012-07-31 09:36:52 +08:00
{
}
#endregion
#region Public Constructors
2013-10-01 13:52:39 +08:00
public WsFrame (Opcode opcode, PayloadData payload)
: this (opcode, Mask.MASK, payload)
2012-07-31 09:36:52 +08:00
{
}
2013-10-01 13:52:39 +08:00
public WsFrame (Opcode opcode, Mask mask, PayloadData payload)
: this (Fin.FINAL, opcode, mask, payload)
2012-07-31 09:36:52 +08:00
{
}
2013-10-01 13:52:39 +08:00
public WsFrame (Fin fin, Opcode opcode, Mask mask, PayloadData payload)
: this (fin, opcode, mask, payload, false)
2013-04-23 17:08:42 +08:00
{
}
2013-10-01 13:52:39 +08:00
public WsFrame (
Fin fin, Opcode opcode, Mask mask, PayloadData payload, bool compressed)
2012-07-31 09:36:52 +08:00
{
2013-04-12 13:42:25 +08:00
Fin = fin;
2013-10-01 13:52:39 +08:00
Rsv1 = isData (opcode) && compressed ? Rsv.ON : Rsv.OFF;
Rsv2 = Rsv.OFF;
Rsv3 = Rsv.OFF;
2013-04-12 13:42:25 +08:00
Opcode = opcode;
Mask = mask;
2012-08-19 15:41:59 +08:00
/* PayloadLen */
2013-10-01 13:52:39 +08:00
var dataLen = payload.Length;
var payloadLen = dataLen < 126
2013-10-01 13:52:39 +08:00
? (byte) dataLen
: dataLen < 0x010000
2013-10-01 13:52:39 +08:00
? (byte) 126
: (byte) 127;
PayloadLen = payloadLen;
/* ExtPayloadLen */
ExtPayloadLen = payloadLen < 126
2013-10-01 13:52:39 +08:00
? new byte []{}
: payloadLen == 126
2013-10-08 10:36:47 +08:00
? ((ushort) dataLen).ToByteArrayInternally (ByteOrder.BIG)
: dataLen.ToByteArrayInternally (ByteOrder.BIG);
/* MaskingKey */
var masking = mask == Mask.MASK;
var maskingKey = masking
2013-10-01 13:52:39 +08:00
? createMaskingKey ()
: new byte []{};
MaskingKey = maskingKey;
/* PayloadData */
if (masking)
2013-10-01 13:52:39 +08:00
payload.Mask (maskingKey);
2013-10-01 13:52:39 +08:00
PayloadData = payload;
2012-07-31 09:36:52 +08:00
}
#endregion
2013-04-12 13:42:25 +08:00
#region Internal Properties
2013-04-23 17:08:42 +08:00
internal bool IsBinary {
get {
return Opcode == Opcode.BINARY;
2013-04-23 17:08:42 +08:00
}
}
internal bool IsClose {
get {
return Opcode == Opcode.CLOSE;
2013-04-23 17:08:42 +08:00
}
}
internal bool IsCompressed {
get {
return Rsv1 == Rsv.ON;
}
}
internal bool IsContinuation {
get {
return Opcode == Opcode.CONT;
2013-04-23 17:08:42 +08:00
}
}
2013-04-12 13:42:25 +08:00
internal bool IsControl {
get {
var opcode = Opcode;
return opcode == Opcode.CLOSE || opcode == Opcode.PING || opcode == Opcode.PONG;
2013-04-12 13:42:25 +08:00
}
}
2012-10-09 11:14:55 +08:00
2013-04-12 13:42:25 +08:00
internal bool IsData {
get {
var opcode = Opcode;
return opcode == Opcode.BINARY || opcode == Opcode.TEXT;
2013-04-12 13:42:25 +08:00
}
}
2012-10-09 11:14:55 +08:00
2013-04-12 13:42:25 +08:00
internal bool IsFinal {
2013-03-25 14:17:31 +08:00
get {
return Fin == Fin.FINAL;
2013-03-25 14:17:31 +08:00
}
}
2013-04-23 17:08:42 +08:00
internal bool IsFragmented {
get {
return Fin == Fin.MORE || Opcode == Opcode.CONT;
2013-04-23 17:08:42 +08:00
}
}
2013-04-12 13:42:25 +08:00
internal bool IsMasked {
2012-11-13 15:38:48 +08:00
get {
return Mask == Mask.MASK;
}
}
internal bool IsPerMessageCompressed {
get {
var opcode = Opcode;
return (opcode == Opcode.BINARY || opcode == Opcode.TEXT) && Rsv1 == Rsv.ON;
2012-10-09 11:14:55 +08:00
}
}
2013-04-23 17:08:42 +08:00
internal bool IsPing {
get {
return Opcode == Opcode.PING;
2013-04-23 17:08:42 +08:00
}
}
internal bool IsPong {
get {
return Opcode == Opcode.PONG;
2013-04-23 17:08:42 +08:00
}
}
internal bool IsText {
get {
return Opcode == Opcode.TEXT;
2013-04-23 17:08:42 +08:00
}
}
2013-04-12 13:42:25 +08:00
internal ulong Length {
2012-11-13 15:38:48 +08:00
get {
2013-10-01 13:52:39 +08:00
return 2 + (ulong) (ExtPayloadLen.Length + MaskingKey.Length) + PayloadData.Length;
2012-10-09 11:14:55 +08:00
}
}
#endregion
2013-04-12 13:42:25 +08:00
#region Public Properties
public Fin Fin { get; private set; }
public Rsv Rsv1 { get; private set; }
public Rsv Rsv2 { get; private set; }
public Rsv Rsv3 { get; private set; }
public Opcode Opcode { get; private set; }
public Mask Mask { get; private set; }
public byte PayloadLen { get; private set; }
2013-10-01 13:52:39 +08:00
public byte [] ExtPayloadLen { get; private set; }
2013-04-12 13:42:25 +08:00
2013-10-01 13:52:39 +08:00
public byte [] MaskingKey { get; private set; }
2013-04-12 13:42:25 +08:00
public PayloadData PayloadData { get; private set; }
#endregion
2012-10-04 14:04:21 +08:00
#region Private Methods
2012-07-31 09:36:52 +08:00
2013-10-01 13:52:39 +08:00
private static byte [] createMaskingKey ()
{
2013-10-01 13:52:39 +08:00
var key = new byte [4];
var rand = new Random ();
rand.NextBytes (key);
return key;
}
2013-10-01 13:52:39 +08:00
private static void dump (WsFrame frame)
2012-07-31 09:36:52 +08:00
{
2013-04-12 13:42:25 +08:00
var len = frame.Length;
2013-10-01 13:52:39 +08:00
var count = (long) (len / 4);
var remainder = (int) (len % 4);
2013-04-12 13:42:25 +08:00
int countDigit;
string countFmt;
if (count < 10000)
{
countDigit = 4;
countFmt = "{0,4}";
}
else if (count < 0x010000)
{
countDigit = 4;
countFmt = "{0,4:X}";
}
else if (count < 0x0100000000)
{
countDigit = 8;
countFmt = "{0,8:X}";
}
else
{
countDigit = 16;
countFmt = "{0,16:X}";
}
2013-10-01 13:52:39 +08:00
var spFmt = String.Format ("{{0,{0}}}", countDigit);
var headerFmt = String.Format (@"
2013-04-12 13:42:25 +08:00
{0} 01234567 89ABCDEF 01234567 89ABCDEF
{0}+--------+--------+--------+--------+", spFmt);
2013-10-01 13:52:39 +08:00
var footerFmt = String.Format (" {0}+--------+--------+--------+--------+", spFmt);
2013-04-12 13:42:25 +08:00
2013-04-15 12:47:51 +08:00
Func<Action<string, string, string, string>> linePrinter = () =>
2013-04-12 13:42:25 +08:00
{
long lineCount = 0;
2013-10-01 13:52:39 +08:00
var lineFmt = String.Format (" {0}|{{1,8}} {{2,8}} {{3,8}} {{4,8}}|", countFmt);
2013-04-12 13:42:25 +08:00
return (arg1, arg2, arg3, arg4) =>
{
2013-10-01 13:52:39 +08:00
Console.WriteLine (lineFmt, ++lineCount, arg1, arg2, arg3, arg4);
2013-04-12 13:42:25 +08:00
};
};
2013-10-01 13:52:39 +08:00
var printLine = linePrinter ();
2013-04-12 13:42:25 +08:00
2013-10-01 13:52:39 +08:00
Console.WriteLine (headerFmt, String.Empty);
2013-04-12 13:42:25 +08:00
2013-10-01 13:52:39 +08:00
var buffer = frame.ToByteArray ();
2013-04-12 13:42:25 +08:00
int i, j;
for (i = 0; i <= count; i++)
{
j = i * 4;
if (i < count)
2013-10-01 13:52:39 +08:00
printLine (
Convert.ToString (buffer [j], 2).PadLeft (8, '0'),
Convert.ToString (buffer [j + 1], 2).PadLeft (8, '0'),
Convert.ToString (buffer [j + 2], 2).PadLeft (8, '0'),
Convert.ToString (buffer [j + 3], 2).PadLeft (8, '0'));
2013-04-12 13:42:25 +08:00
else if (remainder > 0)
2013-10-01 13:52:39 +08:00
printLine (
Convert.ToString (buffer [j], 2).PadLeft (8, '0'),
remainder >= 2 ? Convert.ToString (buffer [j + 1], 2).PadLeft (8, '0') : String.Empty,
remainder == 3 ? Convert.ToString (buffer [j + 2], 2).PadLeft (8, '0') : String.Empty,
2013-04-12 13:42:25 +08:00
String.Empty);
}
2013-10-01 13:52:39 +08:00
Console.WriteLine (footerFmt, String.Empty);
2012-07-31 09:36:52 +08:00
}
2013-10-01 13:52:39 +08:00
private static bool isBinary (Opcode opcode)
2013-04-23 17:08:42 +08:00
{
return opcode == Opcode.BINARY;
}
2013-10-01 13:52:39 +08:00
private static bool isClose (Opcode opcode)
2013-04-23 17:08:42 +08:00
{
return opcode == Opcode.CLOSE;
}
2013-10-01 13:52:39 +08:00
private static bool isContinuation (Opcode opcode)
2013-04-23 17:08:42 +08:00
{
return opcode == Opcode.CONT;
}
2013-10-01 13:52:39 +08:00
private static bool isControl (Opcode opcode)
2013-04-12 13:42:25 +08:00
{
return opcode == Opcode.CLOSE || opcode == Opcode.PING || opcode == Opcode.PONG;
2013-04-12 13:42:25 +08:00
}
2013-10-01 13:52:39 +08:00
private static bool isData (Opcode opcode)
2013-04-12 13:42:25 +08:00
{
return opcode == Opcode.TEXT || opcode == Opcode.BINARY;
2013-04-12 13:42:25 +08:00
}
2013-10-01 13:52:39 +08:00
private static bool isFinal (Fin fin)
2013-04-12 13:42:25 +08:00
{
return fin == Fin.FINAL;
}
2013-10-01 13:52:39 +08:00
private static bool isMasked (Mask mask)
2013-04-12 13:42:25 +08:00
{
return mask == Mask.MASK;
2012-07-31 09:36:52 +08:00
}
2013-10-01 13:52:39 +08:00
private static bool isPing (Opcode opcode)
2013-04-23 17:08:42 +08:00
{
return opcode == Opcode.PING;
}
2013-10-01 13:52:39 +08:00
private static bool isPong (Opcode opcode)
2013-04-23 17:08:42 +08:00
{
return opcode == Opcode.PONG;
}
2013-10-01 13:52:39 +08:00
private static bool isText (Opcode opcode)
2013-04-23 17:08:42 +08:00
{
return opcode == Opcode.TEXT;
}
2013-10-01 13:52:39 +08:00
private static WsFrame parse (byte [] header, Stream stream, bool unmask)
2012-11-13 15:38:48 +08:00
{
/* Header */
2012-10-04 14:04:21 +08:00
2012-07-31 09:36:52 +08:00
// FIN
2013-10-01 13:52:39 +08:00
var fin = (header [0] & 0x80) == 0x80 ? Fin.FINAL : Fin.MORE;
2012-07-31 09:36:52 +08:00
// RSV1
2013-10-01 13:52:39 +08:00
var rsv1 = (header [0] & 0x40) == 0x40 ? Rsv.ON : Rsv.OFF;
2012-07-31 09:36:52 +08:00
// RSV2
2013-10-01 13:52:39 +08:00
var rsv2 = (header [0] & 0x20) == 0x20 ? Rsv.ON : Rsv.OFF;
2012-07-31 09:36:52 +08:00
// RSV3
2013-10-01 13:52:39 +08:00
var rsv3 = (header [0] & 0x10) == 0x10 ? Rsv.ON : Rsv.OFF;
2012-10-04 14:04:21 +08:00
// Opcode
2013-10-01 13:52:39 +08:00
var opcode = (Opcode) (header [0] & 0x0f);
2012-07-31 09:36:52 +08:00
// MASK
2013-10-01 13:52:39 +08:00
var mask = (header [1] & 0x80) == 0x80 ? Mask.MASK : Mask.UNMASK;
2012-07-31 09:36:52 +08:00
// Payload len
2013-10-01 13:52:39 +08:00
var payloadLen = (byte) (header [1] & 0x7f);
2012-10-04 14:04:21 +08:00
2013-10-01 13:52:39 +08:00
if (isControl (opcode) && payloadLen > 125)
return CreateCloseFrame (
Mask.UNMASK,
CloseStatusCode.INCONSISTENT_DATA,
"The payload length of a control frame must be 125 bytes or less.");
var frame = new WsFrame {
2013-04-12 13:42:25 +08:00
Fin = fin,
Rsv1 = rsv1,
Rsv2 = rsv2,
Rsv3 = rsv3,
Opcode = opcode,
Mask = mask,
2012-11-13 15:38:48 +08:00
PayloadLen = payloadLen
};
2012-10-04 14:04:21 +08:00
/* Extended Payload Length */
2012-11-13 15:38:48 +08:00
var extLen = payloadLen < 126
? 0
: payloadLen == 126
? 2
: 8;
2012-12-05 21:10:15 +08:00
var extPayloadLen = extLen > 0
2013-10-08 10:36:47 +08:00
? stream.ReadBytes (extLen)
2013-10-01 13:52:39 +08:00
: new byte []{};
2012-07-31 09:36:52 +08:00
if (extLen > 0 && extPayloadLen.Length != extLen)
2013-10-01 13:52:39 +08:00
return CreateCloseFrame (
Mask.UNMASK,
CloseStatusCode.ABNORMAL,
"'Extended Payload Length' of a frame cannot be read from the data stream.");
2012-08-10 21:20:42 +08:00
frame.ExtPayloadLen = extPayloadLen;
2012-12-05 21:10:15 +08:00
/* Masking Key */
2012-12-05 21:10:15 +08:00
2013-10-01 13:52:39 +08:00
var masked = mask == Mask.MASK;
var maskingKey = masked
2013-10-08 10:36:47 +08:00
? stream.ReadBytes (4)
2013-10-01 13:52:39 +08:00
: new byte []{};
2012-08-10 21:20:42 +08:00
if (masked && maskingKey.Length != 4)
2013-10-01 13:52:39 +08:00
return CreateCloseFrame (
Mask.UNMASK,
CloseStatusCode.ABNORMAL,
"'Masking Key' of a frame cannot be read from the data stream.");
2012-07-31 09:36:52 +08:00
frame.MaskingKey = maskingKey;
/* Payload Data */
ulong dataLen = payloadLen < 126
? payloadLen
: payloadLen == 126
2013-10-08 10:36:47 +08:00
? extPayloadLen.ToUInt16 (ByteOrder.BIG)
: extPayloadLen.ToUInt64 (ByteOrder.BIG);
2013-10-01 13:52:39 +08:00
byte [] data = null;
if (dataLen > 0)
{
if (payloadLen > 126 && dataLen > PayloadData.MaxLength)
{
var code = CloseStatusCode.TOO_BIG;
2013-10-01 13:52:39 +08:00
return CreateCloseFrame (Mask.UNMASK, code, code.GetMessage ());
}
2013-10-08 10:36:47 +08:00
data = payloadLen > 126
? stream.ReadBytes ((long) dataLen, 1024)
: stream.ReadBytes ((int) dataLen);
2013-10-01 13:52:39 +08:00
if (data.LongLength != (long) dataLen)
return CreateCloseFrame (
Mask.UNMASK,
CloseStatusCode.ABNORMAL,
"'Payload Data' of a frame cannot be read from the data stream.");
}
else
{
2013-10-01 13:52:39 +08:00
data = new byte []{};
}
2013-10-01 13:52:39 +08:00
var payload = new PayloadData (data, masked);
2013-04-12 13:42:25 +08:00
if (masked && unmask)
2012-07-31 09:36:52 +08:00
{
2013-10-01 13:52:39 +08:00
payload.Mask (maskingKey);
2013-04-12 13:42:25 +08:00
frame.Mask = Mask.UNMASK;
2013-10-01 13:52:39 +08:00
frame.MaskingKey = new byte []{};
2012-07-31 09:36:52 +08:00
}
2013-10-01 13:52:39 +08:00
frame.PayloadData = payload;
return frame;
2012-10-04 14:04:21 +08:00
}
2013-10-01 13:52:39 +08:00
private static void print (WsFrame frame)
2012-10-04 14:04:21 +08:00
{
var len = frame.ExtPayloadLen.Length;
var extPayloadLen = len == 2
2013-10-08 10:36:47 +08:00
? frame.ExtPayloadLen.ToUInt16 (ByteOrder.BIG).ToString ()
: len == 8
2013-10-08 10:36:47 +08:00
? frame.ExtPayloadLen.ToUInt64 (ByteOrder.BIG).ToString ()
: String.Empty;
2012-10-04 14:04:21 +08:00
var masked = frame.IsMasked;
var maskingKey = masked
2013-10-01 13:52:39 +08:00
? BitConverter.ToString (frame.MaskingKey)
: String.Empty;
2012-07-31 09:36:52 +08:00
var opcode = frame.Opcode;
var payloadData = frame.PayloadData.Length == 0
? String.Empty
: masked || frame.IsFragmented || frame.IsBinary || frame.IsClose
2013-10-01 13:52:39 +08:00
? BitConverter.ToString (frame.PayloadData.ToByteArray ())
: Encoding.UTF8.GetString (frame.PayloadData.ToByteArray ());
2012-07-31 09:36:52 +08:00
var format = @"
FIN: {0}
RSV1: {1}
RSV2: {2}
RSV3: {3}
Opcode: {4}
MASK: {5}
Payload Len: {6}
Extended Payload Len: {7}
Masking Key: {8}
Payload Data: {9}";
2013-10-01 13:52:39 +08:00
Console.WriteLine (
format, frame.Fin, frame.Rsv1, frame.Rsv2, frame.Rsv3, opcode, frame.Mask, frame.PayloadLen, extPayloadLen, maskingKey, payloadData);
2013-04-23 17:08:42 +08:00
}
#endregion
2013-10-01 13:52:39 +08:00
#region Internal Methods
internal static WsFrame CreateCloseFrame (Mask mask, PayloadData payload)
{
return new WsFrame (Opcode.CLOSE, mask, payload);
}
internal static WsFrame CreatePongFrame (Mask mask, PayloadData payload)
{
return new WsFrame (Opcode.PONG, mask, payload);
}
#endregion
2012-07-31 09:36:52 +08:00
#region Public Methods
2013-10-01 13:52:39 +08:00
public static WsFrame CreateCloseFrame (Mask mask, byte [] data)
{
return new WsFrame (Opcode.CLOSE, mask, new PayloadData (data));
}
public static WsFrame CreateCloseFrame (Mask mask, CloseStatusCode code, string reason)
{
return new WsFrame (Opcode.CLOSE, mask, new PayloadData (((ushort) code).Append (reason)));
}
public static WsFrame CreateFrame (
Fin fin, Opcode opcode, Mask mask, byte [] data, bool compressed)
{
return new WsFrame (fin, opcode, mask, new PayloadData (data), compressed);
}
public static WsFrame CreatePingFrame (Mask mask)
{
return new WsFrame (Opcode.PING, mask, new PayloadData ());
}
public static WsFrame CreatePingFrame (Mask mask, byte [] data)
{
return new WsFrame (Opcode.PING, mask, new PayloadData (data));
}
public IEnumerator<byte> GetEnumerator ()
2012-07-31 09:36:52 +08:00
{
2013-10-01 13:52:39 +08:00
foreach (byte b in ToByteArray ())
2012-07-31 09:36:52 +08:00
yield return b;
2012-10-04 14:04:21 +08:00
}
2013-10-01 13:52:39 +08:00
public static WsFrame Parse (byte [] src)
2012-10-04 14:04:21 +08:00
{
2013-10-18 22:07:43 +08:00
return Parse (src, true, null);
2012-10-04 14:04:21 +08:00
}
2013-10-01 13:52:39 +08:00
public static WsFrame Parse (Stream stream)
2013-04-12 13:42:25 +08:00
{
2013-10-18 22:07:43 +08:00
return Parse (stream, true, null);
2013-04-12 13:42:25 +08:00
}
2013-10-18 22:07:43 +08:00
public static WsFrame Parse (byte [] src, Action<Exception> error)
2012-10-04 14:04:21 +08:00
{
2013-10-18 22:07:43 +08:00
return Parse (src, true, error);
}
public static WsFrame Parse (Stream stream, Action<Exception> error)
{
return Parse (stream, true, error);
2012-07-31 09:36:52 +08:00
}
2013-10-18 22:07:43 +08:00
public static WsFrame Parse (byte [] src, bool unmask, Action<Exception> error)
2012-07-31 09:36:52 +08:00
{
2013-10-18 22:07:43 +08:00
using (var stream = new MemoryStream (src))
{
return Parse (stream, unmask, error);
}
2012-10-04 14:04:21 +08:00
}
2013-10-01 13:52:39 +08:00
public static WsFrame Parse (Stream stream, bool unmask, Action<Exception> error)
2012-10-04 14:04:21 +08:00
{
2013-04-12 13:42:25 +08:00
WsFrame frame = null;
2013-10-18 22:07:43 +08:00
try {
2013-10-08 10:36:47 +08:00
var header = stream.ReadBytes (2);
frame = header.Length == 2
2013-10-01 13:52:39 +08:00
? parse (header, stream, unmask)
: CreateCloseFrame (
Mask.UNMASK,
CloseStatusCode.ABNORMAL,
2013-10-18 22:07:43 +08:00
"The header part of a frame cannot be read from the 'stream'.");
}
2013-10-18 22:07:43 +08:00
catch (Exception ex) {
if (error != null)
2013-10-01 13:52:39 +08:00
error (ex);
2013-04-12 13:42:25 +08:00
}
return frame;
2012-11-13 15:38:48 +08:00
}
2012-10-04 14:04:21 +08:00
2013-10-01 13:52:39 +08:00
public static void ParseAsync (Stream stream, Action<WsFrame> completed)
2012-11-13 15:38:48 +08:00
{
2013-10-01 13:52:39 +08:00
ParseAsync (stream, true, completed, null);
2012-11-13 15:38:48 +08:00
}
2013-10-01 13:52:39 +08:00
public static void ParseAsync (Stream stream, Action<WsFrame> completed, Action<Exception> error)
2012-11-13 15:38:48 +08:00
{
2013-10-01 13:52:39 +08:00
ParseAsync (stream, true, completed, error);
2013-04-07 16:05:48 +08:00
}
2012-11-13 15:38:48 +08:00
2013-10-01 13:52:39 +08:00
public static void ParseAsync (
2013-04-07 16:05:48 +08:00
Stream stream, bool unmask, Action<WsFrame> completed, Action<Exception> error)
{
2013-10-18 22:07:43 +08:00
stream.ReadBytesAsync (
2,
header =>
2012-11-13 15:38:48 +08:00
{
2013-10-18 22:07:43 +08:00
var frame = header.Length == 2
? parse (header, stream, unmask)
: CreateCloseFrame (
Mask.UNMASK,
CloseStatusCode.ABNORMAL,
"The header part of a frame cannot be read from the 'stream'.");
if (completed != null)
completed (frame);
},
ex =>
2012-11-13 15:38:48 +08:00
{
if (error != null)
2013-10-01 13:52:39 +08:00
error (ex);
2013-10-18 22:07:43 +08:00
});
2012-07-31 09:36:52 +08:00
}
2013-10-01 13:52:39 +08:00
public void Print (bool dumped)
2012-07-31 09:36:52 +08:00
{
2013-04-12 13:42:25 +08:00
if (dumped)
2013-10-01 13:52:39 +08:00
dump (this);
2012-07-31 09:36:52 +08:00
else
2013-10-01 13:52:39 +08:00
print (this);
2012-07-31 09:36:52 +08:00
}
2013-10-01 13:52:39 +08:00
public byte [] ToByteArray()
2012-07-31 09:36:52 +08:00
{
2013-10-01 13:52:39 +08:00
using (var buffer = new MemoryStream ())
{
2013-10-01 13:52:39 +08:00
int header = (int) Fin;
header = (header << 1) + (int) Rsv1;
header = (header << 1) + (int) Rsv2;
header = (header << 1) + (int) Rsv3;
header = (header << 4) + (int) Opcode;
header = (header << 1) + (int) Mask;
header = (header << 7) + (int) PayloadLen;
2013-10-08 10:36:47 +08:00
buffer.Write (((ushort) header).ToByteArrayInternally (ByteOrder.BIG), 0, 2);
if (PayloadLen > 125)
2013-10-01 13:52:39 +08:00
buffer.Write (ExtPayloadLen, 0, ExtPayloadLen.Length);
if (Mask == Mask.MASK)
2013-10-01 13:52:39 +08:00
buffer.Write (MaskingKey, 0, MaskingKey.Length);
if (PayloadLen > 0)
{
2013-10-01 13:52:39 +08:00
var payload = PayloadData.ToByteArray ();
if (PayloadLen < 127)
2013-10-01 13:52:39 +08:00
buffer.Write (payload, 0, payload.Length);
else
2013-10-01 13:52:39 +08:00
buffer.WriteBytes (payload);
}
2012-07-31 09:36:52 +08:00
2013-10-01 13:52:39 +08:00
buffer.Close ();
return buffer.ToArray ();
}
2012-07-31 09:36:52 +08:00
}
2013-10-01 13:52:39 +08:00
public override string ToString ()
2012-07-31 09:36:52 +08:00
{
2013-10-01 13:52:39 +08:00
return BitConverter.ToString (ToByteArray ());
2013-04-12 13:42:25 +08:00
}
#endregion
#region Explicitly Implemented Interface Members
2013-10-01 13:52:39 +08:00
IEnumerator IEnumerable.GetEnumerator ()
2013-04-12 13:42:25 +08:00
{
2013-10-01 13:52:39 +08:00
return GetEnumerator ();
2012-07-31 09:36:52 +08:00
}
#endregion
}
}