websocket-sharp/websocket-sharp/WebSocketFrame.cs

696 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
/*
* WebSocketFrame.cs
2012-07-31 09:36:52 +08:00
*
* The MIT License
*
2014-06-11 15:46:07 +08:00
* Copyright (c) 2012-2014 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.
2014-06-11 15:46:07 +08:00
*
2012-07-31 09:36:52 +08:00
* 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;
2012-10-04 14:04:21 +08:00
using System.Collections;
2012-07-31 09:36:52 +08:00
using System.Collections.Generic;
2014-06-11 15:46:07 +08:00
using System.IO;
2012-07-31 09:36:52 +08:00
using System.Text;
2013-10-01 13:52:39 +08:00
namespace WebSocketSharp
{
internal class WebSocketFrame : IEnumerable<byte>
2012-07-31 09:36:52 +08:00
{
2014-06-11 15:46:07 +08:00
#region Private Fields
private byte [] _extPayloadLength;
private Fin _fin;
private Mask _mask;
private byte [] _maskingKey;
private Opcode _opcode;
private PayloadData _payloadData;
private byte _payloadLength;
private Rsv _rsv1;
private Rsv _rsv2;
private Rsv _rsv3;
#endregion
#region Internal Static Fields
internal static readonly byte [] EmptyUnmaskPingData;
#endregion
#region Static Constructor
static WebSocketFrame ()
{
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
private WebSocketFrame ()
2012-07-31 09:36:52 +08:00
{
}
#endregion
#region Public Constructors
public WebSocketFrame (Opcode opcode, PayloadData payload)
2014-06-11 15:46:07 +08:00
: this (Fin.Final, opcode, Mask.Mask, payload, false)
2012-07-31 09:36:52 +08:00
{
}
public WebSocketFrame (Opcode opcode, Mask mask, PayloadData payload)
2014-06-11 15:46:07 +08:00
: this (Fin.Final, opcode, mask, payload, false)
2012-07-31 09:36:52 +08:00
{
}
public WebSocketFrame (Fin fin, Opcode opcode, Mask mask, PayloadData payload)
2013-10-01 13:52:39 +08:00
: this (fin, opcode, mask, payload, false)
2013-04-23 17:08:42 +08:00
{
}
public WebSocketFrame (Fin fin, Opcode opcode, Mask mask, PayloadData payload, bool compressed)
2012-07-31 09:36:52 +08:00
{
2014-06-11 15:46:07 +08:00
_fin = fin;
_rsv1 = isData (opcode) && compressed ? Rsv.On : Rsv.Off;
_rsv2 = Rsv.Off;
_rsv3 = Rsv.Off;
_opcode = opcode;
_mask = mask;
2014-06-11 15:46:07 +08:00
var len = payload.Length;
if (len < 126) {
_payloadLength = (byte) len;
_extPayloadLength = new byte [0];
}
else if (len < 0x010000) {
_payloadLength = (byte) 126;
_extPayloadLength = ((ushort) len).ToByteArrayInternally (ByteOrder.Big);
}
else {
_payloadLength = (byte) 127;
_extPayloadLength = len.ToByteArrayInternally (ByteOrder.Big);
}
2014-06-11 15:46:07 +08:00
if (mask == Mask.Mask) {
_maskingKey = createMaskingKey ();
payload.Mask (_maskingKey);
}
else {
_maskingKey = new byte [0];
}
2014-06-11 15:46:07 +08:00
_payloadData = payload;
2012-07-31 09:36:52 +08:00
}
#endregion
2014-06-11 15:46:07 +08:00
#region Public Properties
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public byte [] ExtendedPayloadLength {
2013-04-23 17:08:42 +08:00
get {
2014-06-11 15:46:07 +08:00
return _extPayloadLength;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public Fin Fin {
2013-04-23 17:08:42 +08:00
get {
2014-06-11 15:46:07 +08:00
return _fin;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsBinary {
2013-04-23 17:08:42 +08:00
get {
2014-06-11 15:46:07 +08:00
return _opcode == Opcode.Binary;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsClose {
2013-04-23 17:08:42 +08:00
get {
2014-06-11 15:46:07 +08:00
return _opcode == Opcode.Close;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsCompressed {
2013-04-12 13:42:25 +08:00
get {
2014-06-11 15:46:07 +08:00
return _rsv1 == Rsv.On;
2013-04-12 13:42:25 +08:00
}
}
2012-10-09 11:14:55 +08:00
2014-06-11 15:46:07 +08:00
public bool IsContinuation {
2013-04-12 13:42:25 +08:00
get {
2014-06-11 15:46:07 +08:00
return _opcode == Opcode.Cont;
2013-04-12 13:42:25 +08:00
}
}
2012-10-09 11:14:55 +08:00
2014-06-11 15:46:07 +08:00
public bool IsControl {
2013-03-25 14:17:31 +08:00
get {
2014-06-11 15:46:07 +08:00
return _opcode == Opcode.Close || _opcode == Opcode.Ping || _opcode == Opcode.Pong;
2013-03-25 14:17:31 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsData {
2013-04-23 17:08:42 +08:00
get {
2014-06-11 15:46:07 +08:00
return _opcode == Opcode.Binary || _opcode == Opcode.Text;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsFinal {
2012-11-13 15:38:48 +08:00
get {
2014-06-11 15:46:07 +08:00
return _fin == Fin.Final;
}
}
2014-06-11 15:46:07 +08:00
public bool IsFragmented {
get {
2014-06-11 15:46:07 +08:00
return _fin == Fin.More || _opcode == Opcode.Cont;
2012-10-09 11:14:55 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsMasked {
2013-04-23 17:08:42 +08:00
get {
2014-06-11 15:46:07 +08:00
return _mask == Mask.Mask;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsPerMessageCompressed {
2013-04-23 17:08:42 +08:00
get {
2014-06-11 15:46:07 +08:00
return (_opcode == Opcode.Binary || _opcode == Opcode.Text) && _rsv1 == Rsv.On;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsPing {
2013-04-23 17:08:42 +08:00
get {
2014-06-11 15:46:07 +08:00
return _opcode == Opcode.Ping;
2013-04-23 17:08:42 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsPong {
2012-11-13 15:38:48 +08:00
get {
2014-06-11 15:46:07 +08:00
return _opcode == Opcode.Pong;
2012-10-09 11:14:55 +08:00
}
}
2014-06-11 15:46:07 +08:00
public bool IsText {
get {
return _opcode == Opcode.Text;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public ulong Length {
get {
return 2 + (ulong) (_extPayloadLength.Length + _maskingKey.Length) + _payloadData.Length;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public Mask Mask {
get {
return _mask;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public byte [] MaskingKey {
get {
return _maskingKey;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public Opcode Opcode {
get {
return _opcode;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public PayloadData PayloadData {
get {
return _payloadData;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public byte PayloadLength {
get {
return _payloadLength;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public Rsv Rsv1 {
get {
return _rsv1;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public Rsv Rsv2 {
get {
return _rsv2;
}
}
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
public Rsv Rsv3 {
get {
return _rsv3;
}
}
2013-04-12 13:42:25 +08:00
#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;
}
private static string dump (WebSocketFrame frame)
2012-07-31 09:36:52 +08:00
{
2013-04-12 13:42:25 +08:00
var len = frame.Length;
2014-06-11 15:46:07 +08:00
var cnt = (long) (len / 4);
2013-11-05 20:42:59 +08:00
var rem = (int) (len % 4);
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
int cntDigit;
string cntFmt;
if (cnt < 10000) {
cntDigit = 4;
cntFmt = "{0,4}";
2013-04-12 13:42:25 +08:00
}
2014-06-11 15:46:07 +08:00
else if (cnt < 0x010000) {
cntDigit = 4;
cntFmt = "{0,4:X}";
2013-04-12 13:42:25 +08:00
}
2014-06-11 15:46:07 +08:00
else if (cnt < 0x0100000000) {
cntDigit = 8;
cntFmt = "{0,8:X}";
2013-04-12 13:42:25 +08:00
}
2014-06-11 15:46:07 +08:00
else {
cntDigit = 16;
cntFmt = "{0,16:X}";
2013-04-12 13:42:25 +08:00
}
2014-06-11 15:46:07 +08:00
var spFmt = String.Format ("{{0,{0}}}", cntDigit);
2013-11-05 20:42:59 +08:00
var headerFmt = String.Format (
@"{0} 01234567 89ABCDEF 01234567 89ABCDEF
{0}+--------+--------+--------+--------+\n", spFmt);
var lineFmt = String.Format ("{0}|{{1,8}} {{2,8}} {{3,8}} {{4,8}}|\n", cntFmt);
2013-11-05 20:42:59 +08:00
var footerFmt = String.Format ("{0}+--------+--------+--------+--------+", spFmt);
2013-04-12 13:42:25 +08:00
2014-06-11 15:46:07 +08:00
var output = new StringBuilder (64);
Func<Action<string, string, string, string>> linePrinter = () => {
long lineCnt = 0;
2013-04-12 13:42:25 +08:00
return (arg1, arg2, arg3, arg4) =>
2014-06-11 15:46:07 +08:00
output.AppendFormat (lineFmt, ++lineCnt, arg1, arg2, arg3, arg4);
2013-04-12 13:42:25 +08:00
};
2014-06-11 15:46:07 +08:00
output.AppendFormat (headerFmt, String.Empty);
2013-04-12 13:42:25 +08:00
var printLine = linePrinter ();
2013-11-05 20:42:59 +08:00
var frameAsBytes = frame.ToByteArray ();
for (long i = 0; i <= cnt; i++) {
2014-06-11 15:46:07 +08:00
var j = i * 4;
if (i < cnt)
2013-10-01 13:52:39 +08:00
printLine (
2013-11-05 20:42:59 +08:00
Convert.ToString (frameAsBytes [j], 2).PadLeft (8, '0'),
Convert.ToString (frameAsBytes [j + 1], 2).PadLeft (8, '0'),
Convert.ToString (frameAsBytes [j + 2], 2).PadLeft (8, '0'),
Convert.ToString (frameAsBytes [j + 3], 2).PadLeft (8, '0'));
else if (rem > 0)
2013-10-01 13:52:39 +08:00
printLine (
2013-11-05 20:42:59 +08:00
Convert.ToString (frameAsBytes [j], 2).PadLeft (8, '0'),
rem >= 2 ? Convert.ToString (frameAsBytes [j + 1], 2).PadLeft (8, '0') : String.Empty,
rem == 3 ? Convert.ToString (frameAsBytes [j + 2], 2).PadLeft (8, '0') : String.Empty,
2013-04-12 13:42:25 +08:00
String.Empty);
}
2014-06-11 15:46:07 +08:00
output.AppendFormat (footerFmt, String.Empty);
return output.ToString ();
2013-04-23 17:08:42 +08:00
}
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
}
private static WebSocketFrame 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
var fin = (header [0] & 0x80) == 0x80 ? Fin.Final : Fin.More;
2012-07-31 09:36:52 +08:00
// RSV1
var rsv1 = (header [0] & 0x40) == 0x40 ? Rsv.On : Rsv.Off;
2012-07-31 09:36:52 +08:00
// RSV2
var rsv2 = (header [0] & 0x20) == 0x20 ? Rsv.On : Rsv.Off;
2012-07-31 09:36:52 +08:00
// RSV3
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
var mask = (header [1] & 0x80) == 0x80 ? Mask.Mask : Mask.Unmask;
2014-06-11 15:46:07 +08:00
// Payload Length
2013-10-01 13:52:39 +08:00
var payloadLen = (byte) (header [1] & 0x7f);
2012-10-04 14:04:21 +08:00
2013-11-05 20:42:59 +08:00
// Check if correct frame.
var incorrect = isControl (opcode) && fin == Fin.More
2014-06-11 15:46:07 +08:00
? "A control frame is fragmented."
: !isData (opcode) && rsv1 == Rsv.On
? "A non data frame is compressed."
: null;
2013-11-05 20:42:59 +08:00
if (incorrect != null)
throw new WebSocketException (CloseStatusCode.IncorrectData, incorrect);
2013-11-05 20:42:59 +08:00
// Check if consistent frame.
2013-10-01 13:52:39 +08:00
if (isControl (opcode) && payloadLen > 125)
2013-11-05 20:42:59 +08:00
throw new WebSocketException (
CloseStatusCode.InconsistentData,
2014-06-11 15:46:07 +08:00
"The length of payload data of a control frame is greater than 125 bytes.");
var frame = new WebSocketFrame ();
2014-06-11 15:46:07 +08:00
frame._fin = fin;
frame._rsv1 = rsv1;
frame._rsv2 = rsv2;
frame._rsv3 = rsv3;
frame._opcode = opcode;
frame._mask = mask;
frame._payloadLength = payloadLen;
2012-10-04 14:04:21 +08:00
/* Extended Payload Length */
2012-11-13 15:38:48 +08:00
2014-06-11 15:46:07 +08:00
var size = payloadLen < 126
? 0
: payloadLen == 126
? 2
: 8;
2012-12-05 21:10:15 +08:00
2014-06-11 15:46:07 +08:00
var extPayloadLen = size > 0 ? stream.ReadBytes (size) : new byte [0];
if (size > 0 && extPayloadLen.Length != size)
2013-11-05 20:42:59 +08:00
throw new WebSocketException (
"The 'Extended Payload Length' of a frame cannot be read from the data source.");
2012-08-10 21:20:42 +08:00
2014-06-11 15:46:07 +08:00
frame._extPayloadLength = extPayloadLen;
2012-12-05 21:10:15 +08:00
/* Masking Key */
2012-12-05 21:10:15 +08:00
var masked = mask == Mask.Mask;
2014-06-11 15:46:07 +08:00
var maskingKey = masked ? stream.ReadBytes (4) : new byte [0];
if (masked && maskingKey.Length != 4)
2013-11-05 20:42:59 +08:00
throw new WebSocketException (
"The 'Masking Key' of a frame cannot be read from the data source.");
2012-07-31 09:36:52 +08:00
2014-06-11 15:46:07 +08:00
frame._maskingKey = maskingKey;
/* Payload Data */
2014-06-11 15:46:07 +08:00
ulong len = payloadLen < 126
? payloadLen
: payloadLen == 126
? extPayloadLen.ToUInt16 (ByteOrder.Big)
: extPayloadLen.ToUInt64 (ByteOrder.Big);
2013-10-01 13:52:39 +08:00
byte [] data = null;
2014-06-11 15:46:07 +08:00
if (len > 0) {
2013-11-05 20:42:59 +08:00
// Check if allowable payload data length.
2014-06-11 15:46:07 +08:00
if (payloadLen > 126 && len > PayloadData.MaxLength)
2013-11-11 16:17:27 +08:00
throw new WebSocketException (
2014-06-11 15:46:07 +08:00
CloseStatusCode.TooBig,
"The length of 'Payload Data' of a frame is greater than the allowable length.");
2013-10-08 10:36:47 +08:00
data = payloadLen > 126
2014-06-11 15:46:07 +08:00
? stream.ReadBytes ((long) len, 1024)
: stream.ReadBytes ((int) len);
2013-10-01 13:52:39 +08:00
2014-06-11 15:46:07 +08:00
if (data.LongLength != (long) len)
2013-11-05 20:42:59 +08:00
throw new WebSocketException (
"The 'Payload Data' of a frame cannot be read from the data source.");
}
2014-06-11 15:46:07 +08:00
else {
data = new byte [0];
}
2013-10-01 13:52:39 +08:00
var payload = new PayloadData (data, masked);
2014-06-11 15:46:07 +08:00
if (masked && unmask) {
2013-10-01 13:52:39 +08:00
payload.Mask (maskingKey);
2014-06-11 15:46:07 +08:00
frame._mask = Mask.Unmask;
frame._maskingKey = new byte [0];
2012-07-31 09:36:52 +08:00
}
2014-06-11 15:46:07 +08:00
frame._payloadData = payload;
return frame;
2012-10-04 14:04:21 +08:00
}
private static string print (WebSocketFrame frame)
2012-10-04 14:04:21 +08:00
{
2013-11-05 20:42:59 +08:00
/* Opcode */
2014-06-11 15:46:07 +08:00
var opcode = frame._opcode.ToString ();
2013-11-05 20:42:59 +08:00
2014-06-11 15:46:07 +08:00
/* Payload Length */
2013-11-05 20:42:59 +08:00
2014-06-11 15:46:07 +08:00
var payloadLen = frame._payloadLength;
2013-11-05 20:42:59 +08:00
2014-06-11 15:46:07 +08:00
/* Extended Payload Length */
2013-11-05 20:42:59 +08:00
2014-06-11 15:46:07 +08:00
var ext = frame._extPayloadLength;
2013-11-05 20:42:59 +08:00
var size = ext.Length;
2014-06-11 15:46:07 +08:00
var extPayloadLen = size == 2
? ext.ToUInt16 (ByteOrder.Big).ToString ()
: size == 8
? ext.ToUInt64 (ByteOrder.Big).ToString ()
: String.Empty;
2013-11-05 20:42:59 +08:00
/* Masking Key */
2012-10-04 14:04:21 +08:00
var masked = frame.IsMasked;
2014-06-11 15:46:07 +08:00
var maskingKey = masked ? BitConverter.ToString (frame._maskingKey) : String.Empty;
2013-11-05 20:42:59 +08:00
/* Payload Data */
2014-06-11 15:46:07 +08:00
var payload = payloadLen == 0
? String.Empty
: size > 0
? String.Format ("A {0} frame.", opcode.ToLower ())
: !masked && !frame.IsFragmented && frame.IsText
? Encoding.UTF8.GetString (frame._payloadData.ApplicationData)
: frame._payloadData.ToString ();
2013-11-05 20:42:59 +08:00
var format =
@" FIN: {0}
RSV1: {1}
RSV2: {2}
RSV3: {3}
Opcode: {4}
MASK: {5}
Payload Length: {6}
Extended Payload Length: {7}
Masking Key: {8}
Payload Data: {9}";
2013-11-05 20:42:59 +08:00
return String.Format (
format,
2014-06-11 15:46:07 +08:00
frame._fin,
frame._rsv1,
frame._rsv2,
frame._rsv3,
2013-11-05 20:42:59 +08:00
opcode,
2014-06-11 15:46:07 +08:00
frame._mask,
2013-11-05 20:42:59 +08:00
payloadLen,
2014-06-11 15:46:07 +08:00
extPayloadLen,
maskingKey,
payload);
2013-04-23 17:08:42 +08:00
}
#endregion
2013-10-01 13:52:39 +08:00
#region Internal Methods
internal static WebSocketFrame CreateCloseFrame (Mask mask, PayloadData payload)
2013-10-01 13:52:39 +08:00
{
return new WebSocketFrame (Opcode.Close, mask, payload);
2013-10-01 13:52:39 +08:00
}
internal static WebSocketFrame CreatePongFrame (Mask mask, PayloadData payload)
2013-10-01 13:52:39 +08:00
{
return new WebSocketFrame (Opcode.Pong, mask, payload);
2013-10-01 13:52:39 +08:00
}
#endregion
2012-07-31 09:36:52 +08:00
#region Public Methods
public static WebSocketFrame CreateCloseFrame (Mask mask, byte [] data)
2013-10-01 13:52:39 +08:00
{
return new WebSocketFrame (Opcode.Close, mask, new PayloadData (data));
2013-10-01 13:52:39 +08:00
}
public static WebSocketFrame CreateCloseFrame (Mask mask, CloseStatusCode code, string reason)
2013-10-01 13:52:39 +08:00
{
return new WebSocketFrame (
Opcode.Close, mask, new PayloadData (((ushort) code).Append (reason)));
2013-10-01 13:52:39 +08:00
}
public static WebSocketFrame CreateFrame (
2013-10-01 13:52:39 +08:00
Fin fin, Opcode opcode, Mask mask, byte [] data, bool compressed)
{
return new WebSocketFrame (fin, opcode, mask, new PayloadData (data), compressed);
2013-10-01 13:52:39 +08:00
}
public static WebSocketFrame CreatePingFrame (Mask mask)
2013-10-01 13:52:39 +08:00
{
return new WebSocketFrame (Opcode.Ping, mask, new PayloadData ());
2013-10-01 13:52:39 +08:00
}
public static WebSocketFrame CreatePingFrame (Mask mask, byte [] data)
2013-10-01 13:52:39 +08:00
{
return new WebSocketFrame (Opcode.Ping, mask, new PayloadData (data));
2013-10-01 13:52:39 +08:00
}
public IEnumerator<byte> GetEnumerator ()
2012-07-31 09:36:52 +08:00
{
2014-06-11 15:46:07 +08:00
foreach (var b in ToByteArray ())
2012-07-31 09:36:52 +08:00
yield return b;
2012-10-04 14:04:21 +08:00
}
public static WebSocketFrame Parse (byte [] src)
2012-10-04 14:04:21 +08:00
{
2013-11-05 20:42:59 +08:00
return Parse (src, true);
2012-10-04 14:04:21 +08:00
}
public static WebSocketFrame Parse (Stream stream)
2013-04-12 13:42:25 +08:00
{
2013-11-05 20:42:59 +08:00
return Parse (stream, true);
2012-07-31 09:36:52 +08:00
}
public static WebSocketFrame Parse (byte [] src, bool unmask)
2012-07-31 09:36:52 +08:00
{
2013-10-18 22:07:43 +08:00
using (var stream = new MemoryStream (src))
2013-11-05 20:42:59 +08:00
return Parse (stream, unmask);
2012-10-04 14:04:21 +08:00
}
public static WebSocketFrame Parse (Stream stream, bool unmask)
2012-10-04 14:04:21 +08:00
{
2013-11-05 20:42:59 +08:00
var header = stream.ReadBytes (2);
if (header.Length != 2)
throw new WebSocketException (
"The header part of a frame cannot be read from the data source.");
2013-04-12 13:42:25 +08:00
2013-11-05 20:42:59 +08:00
return parse (header, stream, unmask);
2012-11-13 15:38:48 +08:00
}
2012-10-04 14:04:21 +08:00
public static void ParseAsync (Stream stream, Action<WebSocketFrame> 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
}
2014-06-11 15:46:07 +08:00
public static void ParseAsync (
Stream stream, Action<WebSocketFrame> 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 (
Stream stream, bool unmask, Action<WebSocketFrame> completed, Action<Exception> error)
2013-04-07 16:05:48 +08:00
{
2013-10-18 22:07:43 +08:00
stream.ReadBytesAsync (
2,
2014-06-11 15:46:07 +08:00
header => {
2013-11-05 20:42:59 +08:00
if (header.Length != 2)
throw new WebSocketException (
"The header part of a frame cannot be read from the data source.");
2013-10-18 22:07:43 +08:00
2013-11-05 20:42:59 +08:00
var frame = parse (header, stream, unmask);
2013-10-18 22:07:43 +08:00
if (completed != null)
completed (frame);
},
2013-10-20 23:17:51 +08:00
error);
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-11-05 20:42:59 +08:00
Console.WriteLine (dumped ? dump (this) : print (this));
}
public string PrintToString (bool dumped)
{
2014-06-11 15:46:07 +08:00
return dumped
? dump (this)
: print (this);
2012-07-31 09:36:52 +08:00
}
2014-06-11 15:46:07 +08:00
public byte [] ToByteArray ()
2012-07-31 09:36:52 +08:00
{
2014-06-11 15:46:07 +08:00
using (var buff = new MemoryStream ()) {
var 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) _payloadLength;
buff.Write (((ushort) header).ToByteArrayInternally (ByteOrder.Big), 0, 2);
2014-06-11 15:46:07 +08:00
if (_payloadLength > 125)
buff.Write (_extPayloadLength, 0, _extPayloadLength.Length);
2014-06-11 15:46:07 +08:00
if (_mask == Mask.Mask)
buff.Write (_maskingKey, 0, _maskingKey.Length);
2014-06-11 15:46:07 +08:00
if (_payloadLength > 0) {
var payload = _payloadData.ToByteArray ();
if (_payloadLength < 127)
buff.Write (payload, 0, payload.Length);
else
2014-06-11 15:46:07 +08:00
buff.WriteBytes (payload);
}
2012-07-31 09:36:52 +08:00
2014-06-11 15:46:07 +08:00
buff.Close ();
return buff.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
}
}