Modified closing and ping
This commit is contained in:
parent
f103cd2faf
commit
2b57a58da2
@ -41,7 +41,7 @@ namespace WebSocketSharp
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class CloseEventArgs : MessageEventArgs
|
public class CloseEventArgs : MessageEventArgs
|
||||||
{
|
{
|
||||||
#region Fields
|
#region Private Fields
|
||||||
|
|
||||||
private bool _clean;
|
private bool _clean;
|
||||||
private ushort _code;
|
private ushort _code;
|
||||||
@ -49,19 +49,19 @@ namespace WebSocketSharp
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Internal Constructors
|
||||||
|
|
||||||
internal CloseEventArgs (PayloadData data)
|
internal CloseEventArgs (PayloadData payload)
|
||||||
: base (Opcode.CLOSE, data)
|
: base (Opcode.CLOSE, payload)
|
||||||
{
|
{
|
||||||
_code = getCodeFrom (data);
|
_code = getCodeFrom (RawData);
|
||||||
_reason = getReasonFrom (data);
|
_reason = getReasonFrom (RawData);
|
||||||
_clean = false;
|
_clean = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Properties
|
#region Public Properties
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the status code for closure.
|
/// Gets the status code for closure.
|
||||||
@ -107,23 +107,19 @@ namespace WebSocketSharp
|
|||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
||||||
private static ushort getCodeFrom (PayloadData data)
|
private static ushort getCodeFrom (byte [] data)
|
||||||
{
|
{
|
||||||
var appData = data.ApplicationData;
|
return data.Length > 1
|
||||||
return appData.Length >= 2
|
? data.SubArray (0, 2).To<ushort> (ByteOrder.BIG)
|
||||||
? appData.SubArray (0, 2).To<ushort> (ByteOrder.BIG)
|
: (ushort) 0;
|
||||||
: (ushort) CloseStatusCode.NO_STATUS_CODE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string getReasonFrom (PayloadData data)
|
private static string getReasonFrom (byte [] data)
|
||||||
{
|
{
|
||||||
var appData = data.ApplicationData;
|
var len = data.Length;
|
||||||
var appDataLen = appData.Length;
|
return len > 2
|
||||||
if (appDataLen <= 2)
|
? Encoding.UTF8.GetString (data.SubArray (2, len - 2))
|
||||||
return String.Empty;
|
: String.Empty;
|
||||||
|
|
||||||
var reason = appData.SubArray (2, appDataLen - 2);
|
|
||||||
return Encoding.UTF8.GetString (reason);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -168,7 +168,7 @@ namespace WebSocketSharp
|
|||||||
internal static string CheckIfStarted (this ServerState state)
|
internal static string CheckIfStarted (this ServerState state)
|
||||||
{
|
{
|
||||||
return state != ServerState.START
|
return state != ServerState.START
|
||||||
? "Not started, on shutdown or stopped."
|
? "Any of not started, on shutdown or stopped."
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,6 +396,22 @@ namespace WebSocketSharp
|
|||||||
return value > 0 && value < 65536;
|
return value > 0 && value < 65536;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool IsReserved (this ushort code)
|
||||||
|
{
|
||||||
|
return code == (ushort) CloseStatusCode.UNDEFINED ||
|
||||||
|
code == (ushort) CloseStatusCode.NO_STATUS_CODE ||
|
||||||
|
code == (ushort) CloseStatusCode.ABNORMAL ||
|
||||||
|
code == (ushort) CloseStatusCode.TLS_HANDSHAKE_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool IsReserved (this CloseStatusCode code)
|
||||||
|
{
|
||||||
|
return code == CloseStatusCode.UNDEFINED ||
|
||||||
|
code == CloseStatusCode.NO_STATUS_CODE ||
|
||||||
|
code == CloseStatusCode.ABNORMAL ||
|
||||||
|
code == CloseStatusCode.TLS_HANDSHAKE_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
internal static bool IsText (this string value)
|
internal static bool IsText (this string value)
|
||||||
{
|
{
|
||||||
int len = value.Length;
|
int len = value.Length;
|
||||||
|
@ -29,8 +29,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace WebSocketSharp {
|
namespace WebSocketSharp
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains the event data associated with a <see cref="WebSocket.OnMessage"/> event.
|
/// Contains the event data associated with a <see cref="WebSocket.OnMessage"/> event.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -51,16 +51,16 @@ namespace WebSocketSharp {
|
|||||||
|
|
||||||
#region Internal Constructors
|
#region Internal Constructors
|
||||||
|
|
||||||
internal MessageEventArgs(Opcode opcode, byte[] rawData)
|
internal MessageEventArgs (Opcode opcode, byte[] rawData)
|
||||||
{
|
{
|
||||||
if ((ulong)rawData.LongLength > PayloadData.MaxLength)
|
if ((ulong) rawData.LongLength > PayloadData.MaxLength)
|
||||||
throw new WebSocketException(CloseStatusCode.TOO_BIG);
|
throw new WebSocketException (CloseStatusCode.TOO_BIG);
|
||||||
|
|
||||||
_opcode = opcode;
|
_opcode = opcode;
|
||||||
_rawData = rawData;
|
_rawData = rawData;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal MessageEventArgs(Opcode opcode, PayloadData data)
|
internal MessageEventArgs (Opcode opcode, PayloadData data)
|
||||||
{
|
{
|
||||||
_opcode = opcode;
|
_opcode = opcode;
|
||||||
_rawData = data.ApplicationData;
|
_rawData = data.ApplicationData;
|
||||||
@ -82,8 +82,8 @@ namespace WebSocketSharp {
|
|||||||
_data = _rawData.LongLength == 0
|
_data = _rawData.LongLength == 0
|
||||||
? String.Empty
|
? String.Empty
|
||||||
: _opcode == Opcode.TEXT
|
: _opcode == Opcode.TEXT
|
||||||
? Encoding.UTF8.GetString(_rawData)
|
? Encoding.UTF8.GetString (_rawData)
|
||||||
: _opcode.ToString();
|
: _opcode.ToString ();
|
||||||
|
|
||||||
return _data;
|
return _data;
|
||||||
}
|
}
|
||||||
@ -95,7 +95,7 @@ namespace WebSocketSharp {
|
|||||||
/// <value>
|
/// <value>
|
||||||
/// An array of <see cref="byte"/> that contains the received data.
|
/// An array of <see cref="byte"/> that contains the received data.
|
||||||
/// </value>
|
/// </value>
|
||||||
public byte[] RawData {
|
public byte [] RawData {
|
||||||
get {
|
get {
|
||||||
return _rawData;
|
return _rawData;
|
||||||
}
|
}
|
||||||
@ -105,7 +105,7 @@ namespace WebSocketSharp {
|
|||||||
/// Gets the type of the received data.
|
/// Gets the type of the received data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
/// <value>
|
||||||
/// One of the <see cref="Opcode"/> values that indicates the type of the received data.
|
/// One of the <see cref="Opcode"/> values, indicates the type of the received data.
|
||||||
/// </value>
|
/// </value>
|
||||||
public Opcode Type {
|
public Opcode Type {
|
||||||
get {
|
get {
|
||||||
|
@ -33,11 +33,11 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace WebSocketSharp {
|
namespace WebSocketSharp
|
||||||
|
{
|
||||||
internal class PayloadData : IEnumerable<byte>
|
internal class PayloadData : IEnumerable<byte>
|
||||||
{
|
{
|
||||||
#region Public Fields
|
#region Public Const Fields
|
||||||
|
|
||||||
public const ulong MaxLength = long.MaxValue;
|
public const ulong MaxLength = long.MaxValue;
|
||||||
|
|
||||||
@ -45,35 +45,35 @@ namespace WebSocketSharp {
|
|||||||
|
|
||||||
#region Public Constructors
|
#region Public Constructors
|
||||||
|
|
||||||
public PayloadData()
|
public PayloadData ()
|
||||||
: this(new byte[]{})
|
: this (new byte []{})
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public PayloadData(byte[] appData)
|
public PayloadData (byte [] appData)
|
||||||
: this(new byte[]{}, appData)
|
: this (new byte []{}, appData)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public PayloadData(string appData)
|
public PayloadData (string appData)
|
||||||
: this(Encoding.UTF8.GetBytes(appData))
|
: this (Encoding.UTF8.GetBytes (appData))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public PayloadData(byte[] appData, bool masked)
|
public PayloadData (byte [] appData, bool masked)
|
||||||
: this(new byte[]{}, appData, masked)
|
: this (new byte []{}, appData, masked)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public PayloadData(byte[] extData, byte[] appData)
|
public PayloadData (byte [] extData, byte [] appData)
|
||||||
: this(extData, appData, false)
|
: this (extData, appData, false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public PayloadData(byte[] extData, byte[] appData, bool masked)
|
public PayloadData (byte [] extData, byte [] appData, bool masked)
|
||||||
{
|
{
|
||||||
if ((ulong)extData.LongLength + (ulong)appData.LongLength > MaxLength)
|
if ((ulong) extData.LongLength + (ulong) appData.LongLength > MaxLength)
|
||||||
throw new ArgumentOutOfRangeException(
|
throw new ArgumentOutOfRangeException (
|
||||||
"The length of 'extData' plus 'appData' must be less than MaxLength.");
|
"The length of 'extData' plus 'appData' must be less than MaxLength.");
|
||||||
|
|
||||||
ExtensionData = extData;
|
ExtensionData = extData;
|
||||||
@ -87,17 +87,9 @@ namespace WebSocketSharp {
|
|||||||
|
|
||||||
internal bool ContainsReservedCloseStatusCode {
|
internal bool ContainsReservedCloseStatusCode {
|
||||||
get {
|
get {
|
||||||
if (Length >= 2)
|
return ApplicationData.Length > 1
|
||||||
{
|
? ApplicationData.SubArray (0, 2).To<ushort> (ByteOrder.BIG).IsReserved ()
|
||||||
var code = ToByteArray().SubArray(0, 2).To<ushort>(ByteOrder.BIG);
|
: false;
|
||||||
if (code == (ushort)CloseStatusCode.UNDEFINED ||
|
|
||||||
code == (ushort)CloseStatusCode.NO_STATUS_CODE ||
|
|
||||||
code == (ushort)CloseStatusCode.ABNORMAL ||
|
|
||||||
code == (ushort)CloseStatusCode.TLS_HANDSHAKE_FAILURE)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,32 +97,32 @@ namespace WebSocketSharp {
|
|||||||
get; private set;
|
get; private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ulong Length {
|
|
||||||
get {
|
|
||||||
return (ulong)(ExtensionData.LongLength + ApplicationData.LongLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Public Properties
|
#region Public Properties
|
||||||
|
|
||||||
public byte[] ExtensionData {
|
public byte [] ExtensionData {
|
||||||
get; private set;
|
get; private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] ApplicationData {
|
public byte [] ApplicationData {
|
||||||
get; private set;
|
get; private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ulong Length {
|
||||||
|
get {
|
||||||
|
return (ulong) (ExtensionData.LongLength + ApplicationData.LongLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
||||||
private static void mask(byte[] src, byte[] key)
|
private static void mask (byte [] src, byte [] key)
|
||||||
{
|
{
|
||||||
for (long i = 0; i < src.LongLength; i++)
|
for (long i = 0; i < src.LongLength; i++)
|
||||||
src[i] = (byte)(src[i] ^ key[i % 4]);
|
src [i] = (byte) (src [i] ^ key [i % 4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -141,7 +133,7 @@ namespace WebSocketSharp {
|
|||||||
|
|
||||||
#region Public Methods
|
#region Public Methods
|
||||||
|
|
||||||
public IEnumerator<byte> GetEnumerator()
|
public IEnumerator<byte> GetEnumerator ()
|
||||||
{
|
{
|
||||||
foreach (byte b in ExtensionData)
|
foreach (byte b in ExtensionData)
|
||||||
yield return b;
|
yield return b;
|
||||||
@ -150,36 +142,36 @@ namespace WebSocketSharp {
|
|||||||
yield return b;
|
yield return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Mask(byte[] maskingKey)
|
public void Mask (byte [] maskingKey)
|
||||||
{
|
{
|
||||||
if (ExtensionData.LongLength > 0)
|
if (ExtensionData.LongLength > 0)
|
||||||
mask(ExtensionData, maskingKey);
|
mask (ExtensionData, maskingKey);
|
||||||
|
|
||||||
if (ApplicationData.LongLength > 0)
|
if (ApplicationData.LongLength > 0)
|
||||||
mask(ApplicationData, maskingKey);
|
mask (ApplicationData, maskingKey);
|
||||||
|
|
||||||
IsMasked = !IsMasked;
|
IsMasked = !IsMasked;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] ToByteArray()
|
public byte [] ToByteArray ()
|
||||||
{
|
{
|
||||||
return ExtensionData.LongLength > 0
|
return ExtensionData.LongLength > 0
|
||||||
? this.ToArray()
|
? this.ToArray ()
|
||||||
: ApplicationData;
|
: ApplicationData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString ()
|
||||||
{
|
{
|
||||||
return BitConverter.ToString(ToByteArray());
|
return BitConverter.ToString (ToByteArray ());
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Explicitly Implemented Interface Members
|
#region Explicitly Implemented Interface Members
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
IEnumerator IEnumerable.GetEnumerator ()
|
||||||
{
|
{
|
||||||
return GetEnumerator();
|
return GetEnumerator ();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -321,7 +321,7 @@ namespace WebSocketSharp.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
_listening = false;
|
_listening = false;
|
||||||
_serviceHosts.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG));
|
_serviceHosts.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG), true);
|
||||||
_listener.Abort ();
|
_listener.Abort ();
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
@ -617,7 +617,7 @@ namespace WebSocketSharp.Server
|
|||||||
_state = ServerState.SHUTDOWN;
|
_state = ServerState.SHUTDOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
_serviceHosts.Stop ();
|
_serviceHosts.Stop (new byte []{}, true);
|
||||||
stopListener ();
|
stopListener ();
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
@ -651,7 +651,7 @@ namespace WebSocketSharp.Server
|
|||||||
_state = ServerState.SHUTDOWN;
|
_state = ServerState.SHUTDOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
_serviceHosts.Stop (data);
|
_serviceHosts.Stop (data, !code.IsReserved ());
|
||||||
stopListener ();
|
stopListener ();
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
@ -685,7 +685,7 @@ namespace WebSocketSharp.Server
|
|||||||
_state = ServerState.SHUTDOWN;
|
_state = ServerState.SHUTDOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
_serviceHosts.Stop (data);
|
_serviceHosts.Stop (data, !code.IsReserved ());
|
||||||
stopListener ();
|
stopListener ();
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
|
@ -201,7 +201,7 @@ namespace WebSocketSharp.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
StopListener ();
|
StopListener ();
|
||||||
_serviceHosts.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG));
|
_serviceHosts.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG), true);
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
}
|
}
|
||||||
@ -313,7 +313,7 @@ namespace WebSocketSharp.Server
|
|||||||
base.Start ();
|
base.Start ();
|
||||||
if (!IsListening)
|
if (!IsListening)
|
||||||
{
|
{
|
||||||
_serviceHosts.Stop ();
|
_serviceHosts.Stop (new byte []{}, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,7 +339,7 @@ namespace WebSocketSharp.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
base.Stop ();
|
base.Stop ();
|
||||||
_serviceHosts.Stop ();
|
_serviceHosts.Stop (new byte []{}, true);
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
}
|
}
|
||||||
@ -373,7 +373,7 @@ namespace WebSocketSharp.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
base.Stop ();
|
base.Stop ();
|
||||||
_serviceHosts.Stop (data);
|
_serviceHosts.Stop (data, !code.IsReserved ());
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
}
|
}
|
||||||
@ -407,7 +407,7 @@ namespace WebSocketSharp.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
base.Stop ();
|
base.Stop ();
|
||||||
_serviceHosts.Stop (data);
|
_serviceHosts.Stop (data, !code.IsReserved ());
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
}
|
}
|
||||||
|
@ -294,7 +294,7 @@ namespace WebSocketSharp.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
StopListener ();
|
StopListener ();
|
||||||
_sessions.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG));
|
_sessions.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG), true);
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
}
|
}
|
||||||
@ -346,7 +346,7 @@ namespace WebSocketSharp.Server
|
|||||||
base.Start ();
|
base.Start ();
|
||||||
if (!IsListening)
|
if (!IsListening)
|
||||||
{
|
{
|
||||||
_sessions.Stop ();
|
_sessions.Stop (new byte []{}, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,7 +372,7 @@ namespace WebSocketSharp.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
base.Stop ();
|
base.Stop ();
|
||||||
_sessions.Stop ();
|
_sessions.Stop (new byte []{}, true);
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
}
|
}
|
||||||
@ -406,7 +406,7 @@ namespace WebSocketSharp.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
base.Stop ();
|
base.Stop ();
|
||||||
_sessions.Stop (data);
|
_sessions.Stop (data, !code.IsReserved ());
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
}
|
}
|
||||||
@ -440,7 +440,7 @@ namespace WebSocketSharp.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
base.Stop ();
|
base.Stop ();
|
||||||
_sessions.Stop (data);
|
_sessions.Stop (data, !code.IsReserved ());
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
}
|
}
|
||||||
|
@ -195,7 +195,7 @@ namespace WebSocketSharp.Server
|
|||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
||||||
private Dictionary<string, Dictionary<string, bool>> broadping (byte [] data)
|
private Dictionary<string, Dictionary<string, bool>> broadping (byte [] frameAsBytes, int timeOut)
|
||||||
{
|
{
|
||||||
var result = new Dictionary<string, Dictionary<string, bool>> ();
|
var result = new Dictionary<string, Dictionary<string, bool>> ();
|
||||||
foreach (var host in ServiceHosts)
|
foreach (var host in ServiceHosts)
|
||||||
@ -203,7 +203,7 @@ namespace WebSocketSharp.Server
|
|||||||
if (_state != ServerState.START)
|
if (_state != ServerState.START)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
result.Add (host.ServicePath, host.Sessions.BroadpingInternally (data));
|
result.Add (host.ServicePath, host.Sessions.BroadpingInternally (frameAsBytes, timeOut));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -250,7 +250,7 @@ namespace WebSocketSharp.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (host.Sessions.State == ServerState.START)
|
if (host.Sessions.State == ServerState.START)
|
||||||
host.Sessions.Stop (((ushort) CloseStatusCode.AWAY).ToByteArray (ByteOrder.BIG));
|
host.Sessions.Stop (((ushort) CloseStatusCode.AWAY).ToByteArray (ByteOrder.BIG), true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -266,28 +266,23 @@ namespace WebSocketSharp.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Stop ()
|
internal void Stop (byte [] data, bool send)
|
||||||
{
|
{
|
||||||
lock (_sync)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
_state = ServerState.SHUTDOWN;
|
_state = ServerState.SHUTDOWN;
|
||||||
|
|
||||||
|
var payload = new PayloadData (data);
|
||||||
|
var args = new CloseEventArgs (payload);
|
||||||
|
var frameAsBytes = send
|
||||||
|
? WsFrame.CreateCloseFrame (Mask.UNMASK, payload).ToByteArray ()
|
||||||
|
: null;
|
||||||
|
|
||||||
foreach (var host in _serviceHosts.Values)
|
foreach (var host in _serviceHosts.Values)
|
||||||
host.Sessions.Stop ();
|
host.Sessions.Stop (args, frameAsBytes);
|
||||||
|
|
||||||
_serviceHosts.Clear ();
|
_serviceHosts.Clear ();
|
||||||
_state = ServerState.STOP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void Stop (byte [] data)
|
|
||||||
{
|
|
||||||
lock (_sync)
|
|
||||||
{
|
|
||||||
_state = ServerState.SHUTDOWN;
|
|
||||||
foreach (var host in _serviceHosts.Values)
|
|
||||||
host.Sessions.Stop (data);
|
|
||||||
|
|
||||||
_serviceHosts.Clear ();
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -430,7 +425,7 @@ namespace WebSocketSharp.Server
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return broadping (new byte [] {});
|
return broadping (WsFrame.CreatePingFrame (Mask.UNMASK).ToByteArray (), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -459,7 +454,7 @@ namespace WebSocketSharp.Server
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return broadping (data);
|
return broadping (WsFrame.CreatePingFrame (Mask.UNMASK, data).ToByteArray (), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -489,7 +484,7 @@ namespace WebSocketSharp.Server
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return host.Sessions.BroadpingInternally (new byte [] {});
|
return host.Sessions.BroadpingInternally ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -527,7 +522,8 @@ namespace WebSocketSharp.Server
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return host.Sessions.BroadpingInternally (data);
|
return host.Sessions.BroadpingInternally (
|
||||||
|
WsFrame.CreatePingFrame (Mask.UNMASK, data).ToByteArray (), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -106,7 +106,7 @@ namespace WebSocketSharp.Server
|
|||||||
/// </value>
|
/// </value>
|
||||||
public IEnumerable<string> ActiveIDs {
|
public IEnumerable<string> ActiveIDs {
|
||||||
get {
|
get {
|
||||||
return from result in BroadpingInternally (new byte [] {})
|
return from result in BroadpingInternally ()
|
||||||
where result.Value
|
where result.Value
|
||||||
select result.Key;
|
select result.Key;
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ namespace WebSocketSharp.Server
|
|||||||
/// </value>
|
/// </value>
|
||||||
public IEnumerable<string> InactiveIDs {
|
public IEnumerable<string> InactiveIDs {
|
||||||
get {
|
get {
|
||||||
return from result in BroadpingInternally (new byte [] {})
|
return from result in BroadpingInternally ()
|
||||||
where !result.Value
|
where !result.Value
|
||||||
select result.Key;
|
select result.Key;
|
||||||
}
|
}
|
||||||
@ -282,7 +282,12 @@ namespace WebSocketSharp.Server
|
|||||||
services.Current.SendAsync (data, completed);
|
services.Current.SendAsync (data, completed);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Dictionary<string, bool> BroadpingInternally (byte [] data)
|
internal Dictionary<string, bool> BroadpingInternally ()
|
||||||
|
{
|
||||||
|
return BroadpingInternally (WsFrame.CreatePingFrame (Mask.UNMASK).ToByteArray (), 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Dictionary<string, bool> BroadpingInternally (byte [] frameAsBytes, int timeOut)
|
||||||
{
|
{
|
||||||
var result = new Dictionary<string, bool> ();
|
var result = new Dictionary<string, bool> ();
|
||||||
foreach (var session in ServiceInstances)
|
foreach (var session in ServiceInstances)
|
||||||
@ -290,7 +295,7 @@ namespace WebSocketSharp.Server
|
|||||||
if (_state != ServerState.START)
|
if (_state != ServerState.START)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
result.Add (session.ID, session.Context.WebSocket.Ping (data));
|
result.Add (session.ID, session.Context.WebSocket.Ping (frameAsBytes, timeOut));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -310,21 +315,18 @@ namespace WebSocketSharp.Server
|
|||||||
_state = ServerState.START;
|
_state = ServerState.START;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Stop ()
|
internal void Stop (byte [] data, bool send)
|
||||||
{
|
{
|
||||||
lock (_sync)
|
var payload = new PayloadData (data);
|
||||||
{
|
var args = new CloseEventArgs (payload);
|
||||||
_state = ServerState.SHUTDOWN;
|
var frameAsBytes = send
|
||||||
|
? WsFrame.CreateCloseFrame (Mask.UNMASK, payload).ToByteArray ()
|
||||||
|
: null;
|
||||||
|
|
||||||
_sweepTimer.Enabled = false;
|
Stop (args, frameAsBytes);
|
||||||
foreach (var session in _sessions.Values.ToList ())
|
|
||||||
session.Context.WebSocket.Close ();
|
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Stop (byte [] data)
|
internal void Stop (CloseEventArgs args, byte [] frameAsBytes)
|
||||||
{
|
{
|
||||||
lock (_sync)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
@ -332,7 +334,7 @@ namespace WebSocketSharp.Server
|
|||||||
|
|
||||||
_sweepTimer.Enabled = false;
|
_sweepTimer.Enabled = false;
|
||||||
foreach (var session in _sessions.Values.ToList ())
|
foreach (var session in _sessions.Values.ToList ())
|
||||||
session.Context.WebSocket.Close (data);
|
session.Context.WebSocket.Close (args, frameAsBytes, 1000);
|
||||||
|
|
||||||
_state = ServerState.STOP;
|
_state = ServerState.STOP;
|
||||||
}
|
}
|
||||||
@ -402,7 +404,7 @@ namespace WebSocketSharp.Server
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BroadpingInternally (new byte [] {});
|
return BroadpingInternally ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -428,7 +430,7 @@ namespace WebSocketSharp.Server
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BroadpingInternally (data);
|
return BroadpingInternally (WsFrame.CreatePingFrame (Mask.UNMASK, data).ToByteArray (), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -80,7 +80,6 @@ namespace WebSocketSharp
|
|||||||
private string _extensions;
|
private string _extensions;
|
||||||
private AutoResetEvent _exitReceiving;
|
private AutoResetEvent _exitReceiving;
|
||||||
private object _forClose;
|
private object _forClose;
|
||||||
private object _forFrame;
|
|
||||||
private object _forSend;
|
private object _forSend;
|
||||||
private volatile Logger _logger;
|
private volatile Logger _logger;
|
||||||
private string _origin;
|
private string _origin;
|
||||||
@ -104,7 +103,6 @@ namespace WebSocketSharp
|
|||||||
_cookies = new CookieCollection ();
|
_cookies = new CookieCollection ();
|
||||||
_extensions = String.Empty;
|
_extensions = String.Empty;
|
||||||
_forClose = new object ();
|
_forClose = new object ();
|
||||||
_forFrame = new object ();
|
|
||||||
_forSend = new object ();
|
_forSend = new object ();
|
||||||
_logger = new Logger ();
|
_logger = new Logger ();
|
||||||
_origin = String.Empty;
|
_origin = String.Empty;
|
||||||
@ -319,9 +317,7 @@ namespace WebSocketSharp
|
|||||||
/// </value>
|
/// </value>
|
||||||
public bool IsAlive {
|
public bool IsAlive {
|
||||||
get {
|
get {
|
||||||
return _readyState == WebSocketState.OPEN
|
return Ping ();
|
||||||
? Ping (new byte [] {})
|
|
||||||
: false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,23 +527,13 @@ namespace WebSocketSharp
|
|||||||
return send (createHandshakeResponse ());
|
return send (createHandshakeResponse ());
|
||||||
}
|
}
|
||||||
|
|
||||||
// As server
|
private void close (CloseStatusCode code, string reason, bool wait)
|
||||||
private void close (HttpStatusCode code)
|
|
||||||
{
|
{
|
||||||
send (createHandshakeResponse (code));
|
close (new PayloadData (((ushort) code).Append (reason)), !code.IsReserved (), wait);
|
||||||
try {
|
|
||||||
closeServerResources ();
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
}
|
|
||||||
|
|
||||||
_readyState = WebSocketState.CLOSED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void close (PayloadData data, bool received)
|
private void close (PayloadData payload, bool send, bool wait)
|
||||||
{
|
{
|
||||||
var sent = false;
|
|
||||||
CloseEventArgs args = null;
|
|
||||||
lock (_forClose)
|
lock (_forClose)
|
||||||
{
|
{
|
||||||
if (_readyState == WebSocketState.CLOSING || _readyState == WebSocketState.CLOSED)
|
if (_readyState == WebSocketState.CLOSING || _readyState == WebSocketState.CLOSED)
|
||||||
@ -555,60 +541,53 @@ namespace WebSocketSharp
|
|||||||
|
|
||||||
_logger.Trace ("Start closing handshake.");
|
_logger.Trace ("Start closing handshake.");
|
||||||
|
|
||||||
var current = _readyState;
|
|
||||||
_readyState = WebSocketState.CLOSING;
|
_readyState = WebSocketState.CLOSING;
|
||||||
if (current == WebSocketState.CONNECTING && !_client)
|
|
||||||
{
|
|
||||||
close (HttpStatusCode.BadRequest);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
args = new CloseEventArgs (data);
|
|
||||||
if (current == WebSocketState.OPEN && !data.ContainsReservedCloseStatusCode)
|
|
||||||
sent = send (createControlFrame (Opcode.CLOSE, data, _client));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
received = received || (sent && _exitReceiving != null && _exitReceiving.WaitOne (5 * 1000));
|
var args = new CloseEventArgs (payload);
|
||||||
var released = closeResources ();
|
args.WasClean = _client
|
||||||
args.WasClean = sent && received && released;
|
? close (
|
||||||
_logger.Debug (String.Format (
|
send ? WsFrame.CreateCloseFrame (Mask.MASK, payload).ToByteArray () : null,
|
||||||
"Was clean?: {0}\nsent: {1} received: {2} released: {3}", args.WasClean, sent, received, released));
|
wait ? 5000 : 0,
|
||||||
|
closeClientResources)
|
||||||
|
: close (
|
||||||
|
send ? WsFrame.CreateCloseFrame (Mask.UNMASK, payload).ToByteArray () : null,
|
||||||
|
wait ? 1000 : 0,
|
||||||
|
closeServerResources);
|
||||||
|
|
||||||
_readyState = WebSocketState.CLOSED;
|
_readyState = WebSocketState.CLOSED;
|
||||||
_logger.Trace ("End closing handshake.");
|
|
||||||
|
|
||||||
|
_logger.Trace ("End closing handshake.");
|
||||||
OnClose.Emit (this, args);
|
OnClose.Emit (this, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void close (CloseStatusCode code, string reason, bool received)
|
private bool close (byte [] frameAsBytes, int timeOut, Func<bool> release)
|
||||||
{
|
{
|
||||||
var data = ((ushort) code).Append (reason);
|
var sent = frameAsBytes != null && _stream.Write (frameAsBytes);
|
||||||
close (new PayloadData (data), received);
|
var received = timeOut == 0 || (sent && _exitReceiving.WaitOne (timeOut));
|
||||||
|
var released = release ();
|
||||||
|
var result = sent && received && released;
|
||||||
|
_logger.Debug (String.Format (
|
||||||
|
"Was clean?: {0}\nsent: {1} received: {2} released: {3}", result, sent, received, released));
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// As client
|
// As client
|
||||||
private void closeClientResources ()
|
private bool closeClientResources ()
|
||||||
{
|
|
||||||
if (_stream != null)
|
|
||||||
{
|
|
||||||
_stream.Dispose ();
|
|
||||||
_stream = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_tcpClient != null)
|
|
||||||
{
|
|
||||||
_tcpClient.Close ();
|
|
||||||
_tcpClient = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool closeResources ()
|
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (_client)
|
if (_stream != null)
|
||||||
closeClientResources ();
|
{
|
||||||
else
|
_stream.Dispose ();
|
||||||
closeServerResources ();
|
_stream = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_tcpClient != null)
|
||||||
|
{
|
||||||
|
_tcpClient.Close ();
|
||||||
|
_tcpClient = null;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -621,13 +600,23 @@ namespace WebSocketSharp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// As server
|
// As server
|
||||||
private void closeServerResources ()
|
private bool closeServerResources ()
|
||||||
{
|
{
|
||||||
if (_closeContext != null)
|
try {
|
||||||
_closeContext ();
|
if (_closeContext != null)
|
||||||
|
_closeContext ();
|
||||||
|
|
||||||
_stream = null;
|
_stream = null;
|
||||||
_context = null;
|
_context = null;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
_logger.Fatal (ex.ToString ());
|
||||||
|
error ("An exception has occured.");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool concatenateFragments (Stream dest)
|
private bool concatenateFragments (Stream dest)
|
||||||
@ -697,23 +686,6 @@ namespace WebSocketSharp
|
|||||||
return Convert.ToBase64String (src);
|
return Convert.ToBase64String (src);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static WsFrame createControlFrame (Opcode opcode, PayloadData payloadData, bool client)
|
|
||||||
{
|
|
||||||
var mask = client ? Mask.MASK : Mask.UNMASK;
|
|
||||||
var frame = new WsFrame (Fin.FINAL, opcode, mask, payloadData);
|
|
||||||
|
|
||||||
return frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static WsFrame createFrame (
|
|
||||||
Fin fin, Opcode opcode, PayloadData payloadData, bool compressed, bool client)
|
|
||||||
{
|
|
||||||
var mask = client ? Mask.MASK : Mask.UNMASK;
|
|
||||||
var frame = new WsFrame (fin, opcode, mask, payloadData, compressed);
|
|
||||||
|
|
||||||
return frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
// As client
|
// As client
|
||||||
private HandshakeRequest createHandshakeRequest ()
|
private HandshakeRequest createHandshakeRequest ()
|
||||||
{
|
{
|
||||||
@ -851,23 +823,19 @@ namespace WebSocketSharp
|
|||||||
OnOpen.Emit (this, EventArgs.Empty);
|
OnOpen.Emit (this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pong (PayloadData data)
|
|
||||||
{
|
|
||||||
var frame = createControlFrame (Opcode.PONG, data, _client);
|
|
||||||
send (frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool processAbnormalFrame ()
|
private bool processAbnormalFrame ()
|
||||||
{
|
{
|
||||||
var code = CloseStatusCode.ABNORMAL;
|
var code = CloseStatusCode.ABNORMAL;
|
||||||
close (code, code.GetMessage (), true);
|
close (code, code.GetMessage (), false);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool processCloseFrame (WsFrame frame)
|
private bool processCloseFrame (WsFrame frame)
|
||||||
{
|
{
|
||||||
close (frame.PayloadData, true);
|
var payload = frame.PayloadData;
|
||||||
|
close (payload, !payload.ContainsReservedCloseStatusCode, false);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -937,22 +905,23 @@ namespace WebSocketSharp
|
|||||||
|
|
||||||
private bool processIncorrectFrame ()
|
private bool processIncorrectFrame ()
|
||||||
{
|
{
|
||||||
close (CloseStatusCode.INCORRECT_DATA, null, true);
|
close (CloseStatusCode.INCORRECT_DATA, null, false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool processPingFrame (WsFrame frame)
|
private bool processPingFrame (WsFrame frame)
|
||||||
{
|
{
|
||||||
_logger.Trace ("Return Pong.");
|
if (send (WsFrame.CreatePongFrame (
|
||||||
pong (frame.PayloadData);
|
_client ? Mask.MASK : Mask.UNMASK, frame.PayloadData).ToByteArray ()))
|
||||||
|
_logger.Trace ("Returned Pong.");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool processPongFrame ()
|
private bool processPongFrame ()
|
||||||
{
|
{
|
||||||
_logger.Trace ("Receive Pong.");
|
|
||||||
_receivePong.Set ();
|
_receivePong.Set ();
|
||||||
|
_logger.Trace ("Received Pong.");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1012,11 +981,25 @@ namespace WebSocketSharp
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool send (byte [] frameAsBytes)
|
||||||
|
{
|
||||||
|
if (_readyState != WebSocketState.OPEN)
|
||||||
|
{
|
||||||
|
var msg = "A WebSocket connection isn't established or has been closed.";
|
||||||
|
_logger.Error (msg);
|
||||||
|
error (msg);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _stream.Write (frameAsBytes);
|
||||||
|
}
|
||||||
|
|
||||||
// As client
|
// As client
|
||||||
private void send (HandshakeRequest request)
|
private void send (HandshakeRequest request)
|
||||||
{
|
{
|
||||||
_logger.Debug (String.Format ("A WebSocket connection request to {0}:\n{1}",
|
_logger.Debug (String.Format (
|
||||||
_uri, request));
|
"A WebSocket connection request to {0}:\n{1}", _uri, request));
|
||||||
_stream.WriteHandshake (request);
|
_stream.WriteHandshake (request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1029,23 +1012,16 @@ namespace WebSocketSharp
|
|||||||
|
|
||||||
private bool send (WsFrame frame)
|
private bool send (WsFrame frame)
|
||||||
{
|
{
|
||||||
lock (_forFrame)
|
if (_readyState != WebSocketState.OPEN)
|
||||||
{
|
{
|
||||||
var ready = _stream != null &&
|
var msg = "A WebSocket connection isn't established or has been closed.";
|
||||||
(_readyState == WebSocketState.OPEN ||
|
_logger.Error (msg);
|
||||||
(_readyState == WebSocketState.CLOSING && frame.IsClose));
|
error (msg);
|
||||||
|
|
||||||
if (!ready)
|
return false;
|
||||||
{
|
|
||||||
var msg = "A WebSocket connection isn't established or has been closed.";
|
|
||||||
_logger.Error (msg);
|
|
||||||
error (msg);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _stream.WriteFrame (frame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return _stream.WriteFrame (frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void send (Opcode opcode, Stream stream)
|
private void send (Opcode opcode, Stream stream)
|
||||||
@ -1091,8 +1067,8 @@ namespace WebSocketSharp
|
|||||||
|
|
||||||
private bool send (Fin fin, Opcode opcode, byte [] data, bool compressed)
|
private bool send (Fin fin, Opcode opcode, byte [] data, bool compressed)
|
||||||
{
|
{
|
||||||
var frame = createFrame (fin, opcode, new PayloadData (data), compressed, _client);
|
return send (
|
||||||
return send (frame);
|
WsFrame.CreateFrame (fin, opcode, _client ? Mask.MASK : Mask.UNMASK, data, compressed));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendAsync (Opcode opcode, Stream stream, Action completed)
|
private void sendAsync (Opcode opcode, Stream stream, Action completed)
|
||||||
@ -1201,12 +1177,12 @@ namespace WebSocketSharp
|
|||||||
catch (WebSocketException ex) {
|
catch (WebSocketException ex) {
|
||||||
_logger.Fatal (ex.ToString ());
|
_logger.Fatal (ex.ToString ());
|
||||||
error ("An exception has occured.");
|
error ("An exception has occured.");
|
||||||
close (ex.Code, ex.Message, true);
|
close (ex.Code, ex.Message, false);
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
_logger.Fatal (ex.ToString ());
|
_logger.Fatal (ex.ToString ());
|
||||||
error ("An exception has occured.");
|
error ("An exception has occured.");
|
||||||
close (CloseStatusCode.ABNORMAL, null, true);
|
close (CloseStatusCode.ABNORMAL, null, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1263,27 +1239,39 @@ namespace WebSocketSharp
|
|||||||
|
|
||||||
#region Internal Methods
|
#region Internal Methods
|
||||||
|
|
||||||
// As server
|
|
||||||
internal void Close (byte [] data)
|
|
||||||
{
|
|
||||||
close (new PayloadData (data), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// As server
|
// As server
|
||||||
internal void Close (HttpStatusCode code)
|
internal void Close (HttpStatusCode code)
|
||||||
{
|
{
|
||||||
_readyState = WebSocketState.CLOSING;
|
_readyState = WebSocketState.CLOSING;
|
||||||
close (code);
|
|
||||||
|
send (createHandshakeResponse (code));
|
||||||
|
closeServerResources ();
|
||||||
|
|
||||||
|
_readyState = WebSocketState.CLOSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool Ping (byte [] data)
|
// As server
|
||||||
|
internal void Close (CloseEventArgs args, byte [] frameAsBytes, int waitTimeOut)
|
||||||
{
|
{
|
||||||
var frame = createControlFrame (Opcode.PING, new PayloadData (data), _client);
|
lock (_forClose)
|
||||||
var timeOut = _client ? 5000 : 1000;
|
{
|
||||||
|
if (_readyState == WebSocketState.CLOSING || _readyState == WebSocketState.CLOSED)
|
||||||
|
return;
|
||||||
|
|
||||||
return send (frame)
|
_readyState = WebSocketState.CLOSING;
|
||||||
? _receivePong.WaitOne (timeOut)
|
}
|
||||||
: false;
|
|
||||||
|
args.WasClean = close (frameAsBytes, waitTimeOut, closeServerResources);
|
||||||
|
|
||||||
|
_readyState = WebSocketState.CLOSED;
|
||||||
|
|
||||||
|
OnClose.Emit (this, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool Ping (byte [] frameAsBytes, int timeOut)
|
||||||
|
{
|
||||||
|
return send (frameAsBytes) &&
|
||||||
|
_receivePong.WaitOne (timeOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -1295,7 +1283,7 @@ namespace WebSocketSharp
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Close ()
|
public void Close ()
|
||||||
{
|
{
|
||||||
close (new PayloadData (), false);
|
close (new PayloadData (), _readyState == WebSocketState.OPEN, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1320,7 +1308,8 @@ namespace WebSocketSharp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
close (new PayloadData (code.ToByteArray (ByteOrder.BIG)), false);
|
var send = _readyState == WebSocketState.OPEN && !code.IsReserved ();
|
||||||
|
close (new PayloadData (code.ToByteArray (ByteOrder.BIG)), send, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1332,7 +1321,8 @@ namespace WebSocketSharp
|
|||||||
/// </param>
|
/// </param>
|
||||||
public void Close (CloseStatusCode code)
|
public void Close (CloseStatusCode code)
|
||||||
{
|
{
|
||||||
close (new PayloadData (((ushort) code).ToByteArray (ByteOrder.BIG)), false);
|
var send = _readyState == WebSocketState.OPEN && !code.IsReserved ();
|
||||||
|
close (new PayloadData (((ushort) code).ToByteArray (ByteOrder.BIG)), send, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1364,7 +1354,8 @@ namespace WebSocketSharp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
close (new PayloadData (data), false);
|
var send = _readyState == WebSocketState.OPEN && !code.IsReserved ();
|
||||||
|
close (new PayloadData (data), send, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1393,7 +1384,8 @@ namespace WebSocketSharp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
close (new PayloadData (data), false);
|
var send = _readyState == WebSocketState.OPEN && !code.IsReserved ();
|
||||||
|
close (new PayloadData (data), send, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1417,7 +1409,10 @@ namespace WebSocketSharp
|
|||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
_logger.Fatal (ex.ToString ());
|
_logger.Fatal (ex.ToString ());
|
||||||
error ("An exception has occured.");
|
error ("An exception has occured.");
|
||||||
Close (CloseStatusCode.ABNORMAL);
|
if (_client)
|
||||||
|
Close (CloseStatusCode.ABNORMAL);
|
||||||
|
else
|
||||||
|
Close (HttpStatusCode.BadRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1441,7 +1436,9 @@ namespace WebSocketSharp
|
|||||||
/// </returns>
|
/// </returns>
|
||||||
public bool Ping ()
|
public bool Ping ()
|
||||||
{
|
{
|
||||||
return Ping (new byte [] {});
|
return _client
|
||||||
|
? Ping (WsFrame.CreatePingFrame (Mask.MASK).ToByteArray (), 5000)
|
||||||
|
: Ping (WsFrame.CreatePingFrame (Mask.UNMASK).ToByteArray (), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1457,7 +1454,7 @@ namespace WebSocketSharp
|
|||||||
public bool Ping (string message)
|
public bool Ping (string message)
|
||||||
{
|
{
|
||||||
if (message == null || message.Length == 0)
|
if (message == null || message.Length == 0)
|
||||||
return Ping (new byte [] {});
|
return Ping ();
|
||||||
|
|
||||||
var data = Encoding.UTF8.GetBytes (message);
|
var data = Encoding.UTF8.GetBytes (message);
|
||||||
var msg = data.CheckIfValidPingData ();
|
var msg = data.CheckIfValidPingData ();
|
||||||
@ -1469,7 +1466,9 @@ namespace WebSocketSharp
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ping (data);
|
return _client
|
||||||
|
? Ping (WsFrame.CreatePingFrame (Mask.MASK, data).ToByteArray (), 5000)
|
||||||
|
: Ping (WsFrame.CreatePingFrame (Mask.UNMASK, data).ToByteArray (), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -32,13 +32,13 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace WebSocketSharp {
|
namespace WebSocketSharp
|
||||||
|
{
|
||||||
internal class WsFrame : IEnumerable<byte>
|
internal class WsFrame : IEnumerable<byte>
|
||||||
{
|
{
|
||||||
#region Private Constructors
|
#region Private Constructors
|
||||||
|
|
||||||
private WsFrame()
|
private WsFrame ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,26 +46,26 @@ namespace WebSocketSharp {
|
|||||||
|
|
||||||
#region Public Constructors
|
#region Public Constructors
|
||||||
|
|
||||||
public WsFrame(Opcode opcode, PayloadData payloadData)
|
public WsFrame (Opcode opcode, PayloadData payload)
|
||||||
: this(opcode, Mask.MASK, payloadData)
|
: this (opcode, Mask.MASK, payload)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public WsFrame(Opcode opcode, Mask mask, PayloadData payloadData)
|
public WsFrame (Opcode opcode, Mask mask, PayloadData payload)
|
||||||
: this(Fin.FINAL, opcode, mask, payloadData)
|
: this (Fin.FINAL, opcode, mask, payload)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public WsFrame(Fin fin, Opcode opcode, Mask mask, PayloadData payloadData)
|
public WsFrame (Fin fin, Opcode opcode, Mask mask, PayloadData payload)
|
||||||
: this(fin, opcode, mask, payloadData, false)
|
: this (fin, opcode, mask, payload, false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public WsFrame(
|
public WsFrame (
|
||||||
Fin fin, Opcode opcode, Mask mask, PayloadData payloadData, bool compressed)
|
Fin fin, Opcode opcode, Mask mask, PayloadData payload, bool compressed)
|
||||||
{
|
{
|
||||||
Fin = fin;
|
Fin = fin;
|
||||||
Rsv1 = isData(opcode) && compressed ? Rsv.ON : Rsv.OFF;
|
Rsv1 = isData (opcode) && compressed ? Rsv.ON : Rsv.OFF;
|
||||||
Rsv2 = Rsv.OFF;
|
Rsv2 = Rsv.OFF;
|
||||||
Rsv3 = Rsv.OFF;
|
Rsv3 = Rsv.OFF;
|
||||||
Opcode = opcode;
|
Opcode = opcode;
|
||||||
@ -73,38 +73,38 @@ namespace WebSocketSharp {
|
|||||||
|
|
||||||
/* PayloadLen */
|
/* PayloadLen */
|
||||||
|
|
||||||
ulong dataLen = payloadData.Length;
|
var dataLen = payload.Length;
|
||||||
var payloadLen = dataLen < 126
|
var payloadLen = dataLen < 126
|
||||||
? (byte)dataLen
|
? (byte) dataLen
|
||||||
: dataLen < 0x010000
|
: dataLen < 0x010000
|
||||||
? (byte)126
|
? (byte) 126
|
||||||
: (byte)127;
|
: (byte) 127;
|
||||||
|
|
||||||
PayloadLen = payloadLen;
|
PayloadLen = payloadLen;
|
||||||
|
|
||||||
/* ExtPayloadLen */
|
/* ExtPayloadLen */
|
||||||
|
|
||||||
ExtPayloadLen = payloadLen < 126
|
ExtPayloadLen = payloadLen < 126
|
||||||
? new byte[]{}
|
? new byte []{}
|
||||||
: payloadLen == 126
|
: payloadLen == 126
|
||||||
? ((ushort)dataLen).ToByteArray(ByteOrder.BIG)
|
? ((ushort) dataLen).ToByteArray (ByteOrder.BIG)
|
||||||
: dataLen.ToByteArray(ByteOrder.BIG);
|
: dataLen.ToByteArray (ByteOrder.BIG);
|
||||||
|
|
||||||
/* MaskingKey */
|
/* MaskingKey */
|
||||||
|
|
||||||
var masking = mask == Mask.MASK;
|
var masking = mask == Mask.MASK;
|
||||||
var maskingKey = masking
|
var maskingKey = masking
|
||||||
? createMaskingKey()
|
? createMaskingKey ()
|
||||||
: new byte[]{};
|
: new byte []{};
|
||||||
|
|
||||||
MaskingKey = maskingKey;
|
MaskingKey = maskingKey;
|
||||||
|
|
||||||
/* PayloadData */
|
/* PayloadData */
|
||||||
|
|
||||||
if (masking)
|
if (masking)
|
||||||
payloadData.Mask(maskingKey);
|
payload.Mask (maskingKey);
|
||||||
|
|
||||||
PayloadData = payloadData;
|
PayloadData = payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -194,7 +194,7 @@ namespace WebSocketSharp {
|
|||||||
|
|
||||||
internal ulong Length {
|
internal ulong Length {
|
||||||
get {
|
get {
|
||||||
return 2 + (ulong)(ExtPayloadLen.Length + MaskingKey.Length) + PayloadData.Length;
|
return 2 + (ulong) (ExtPayloadLen.Length + MaskingKey.Length) + PayloadData.Length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,9 +216,9 @@ namespace WebSocketSharp {
|
|||||||
|
|
||||||
public byte PayloadLen { get; private set; }
|
public byte PayloadLen { get; private set; }
|
||||||
|
|
||||||
public byte[] ExtPayloadLen { get; private set; }
|
public byte [] ExtPayloadLen { get; private set; }
|
||||||
|
|
||||||
public byte[] MaskingKey { get; private set; }
|
public byte [] MaskingKey { get; private set; }
|
||||||
|
|
||||||
public PayloadData PayloadData { get; private set; }
|
public PayloadData PayloadData { get; private set; }
|
||||||
|
|
||||||
@ -226,26 +226,20 @@ namespace WebSocketSharp {
|
|||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
||||||
private static WsFrame createCloseFrame(CloseStatusCode code, string reason, Mask mask)
|
private static byte [] createMaskingKey ()
|
||||||
{
|
{
|
||||||
var data = ((ushort)code).Append(reason);
|
var key = new byte [4];
|
||||||
return new WsFrame(Fin.FINAL, Opcode.CLOSE, mask, new PayloadData(data));
|
var rand = new Random ();
|
||||||
}
|
rand.NextBytes (key);
|
||||||
|
|
||||||
private static byte[] createMaskingKey()
|
|
||||||
{
|
|
||||||
var key = new byte[4];
|
|
||||||
var rand = new Random();
|
|
||||||
rand.NextBytes(key);
|
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void dump(WsFrame frame)
|
private static void dump (WsFrame frame)
|
||||||
{
|
{
|
||||||
var len = frame.Length;
|
var len = frame.Length;
|
||||||
var count = (long)(len / 4);
|
var count = (long) (len / 4);
|
||||||
var remainder = (int)(len % 4);
|
var remainder = (int) (len % 4);
|
||||||
|
|
||||||
int countDigit;
|
int countDigit;
|
||||||
string countFmt;
|
string countFmt;
|
||||||
@ -270,120 +264,121 @@ namespace WebSocketSharp {
|
|||||||
countFmt = "{0,16:X}";
|
countFmt = "{0,16:X}";
|
||||||
}
|
}
|
||||||
|
|
||||||
var spFmt = String.Format("{{0,{0}}}", countDigit);
|
var spFmt = String.Format ("{{0,{0}}}", countDigit);
|
||||||
var headerFmt = String.Format(@"
|
var headerFmt = String.Format (@"
|
||||||
{0} 01234567 89ABCDEF 01234567 89ABCDEF
|
{0} 01234567 89ABCDEF 01234567 89ABCDEF
|
||||||
{0}+--------+--------+--------+--------+", spFmt);
|
{0}+--------+--------+--------+--------+", spFmt);
|
||||||
var footerFmt = String.Format(" {0}+--------+--------+--------+--------+", spFmt);
|
var footerFmt = String.Format (" {0}+--------+--------+--------+--------+", spFmt);
|
||||||
|
|
||||||
Func<Action<string, string, string, string>> linePrinter = () =>
|
Func<Action<string, string, string, string>> linePrinter = () =>
|
||||||
{
|
{
|
||||||
long lineCount = 0;
|
long lineCount = 0;
|
||||||
var lineFmt = String.Format(" {0}|{{1,8}} {{2,8}} {{3,8}} {{4,8}}|", countFmt);
|
var lineFmt = String.Format (" {0}|{{1,8}} {{2,8}} {{3,8}} {{4,8}}|", countFmt);
|
||||||
return (arg1, arg2, arg3, arg4) =>
|
return (arg1, arg2, arg3, arg4) =>
|
||||||
{
|
{
|
||||||
Console.WriteLine(lineFmt, ++lineCount, arg1, arg2, arg3, arg4);
|
Console.WriteLine (lineFmt, ++lineCount, arg1, arg2, arg3, arg4);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
var printLine = linePrinter();
|
var printLine = linePrinter ();
|
||||||
|
|
||||||
Console.WriteLine(headerFmt, String.Empty);
|
Console.WriteLine (headerFmt, String.Empty);
|
||||||
|
|
||||||
var buffer = frame.ToByteArray();
|
var buffer = frame.ToByteArray ();
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = 0; i <= count; i++)
|
for (i = 0; i <= count; i++)
|
||||||
{
|
{
|
||||||
j = i * 4;
|
j = i * 4;
|
||||||
if (i < count)
|
if (i < count)
|
||||||
printLine(
|
printLine (
|
||||||
Convert.ToString(buffer[j], 2).PadLeft(8, '0'),
|
Convert.ToString (buffer [j], 2).PadLeft (8, '0'),
|
||||||
Convert.ToString(buffer[j + 1], 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 + 2], 2).PadLeft (8, '0'),
|
||||||
Convert.ToString(buffer[j + 3], 2).PadLeft(8, '0'));
|
Convert.ToString (buffer [j + 3], 2).PadLeft (8, '0'));
|
||||||
else if (remainder > 0)
|
else if (remainder > 0)
|
||||||
printLine(
|
printLine (
|
||||||
Convert.ToString(buffer[j], 2).PadLeft(8, '0'),
|
Convert.ToString (buffer [j], 2).PadLeft (8, '0'),
|
||||||
remainder >= 2 ? Convert.ToString(buffer[j + 1], 2).PadLeft(8, '0') : String.Empty,
|
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,
|
remainder == 3 ? Convert.ToString (buffer [j + 2], 2).PadLeft (8, '0') : String.Empty,
|
||||||
String.Empty);
|
String.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine(footerFmt, String.Empty);
|
Console.WriteLine (footerFmt, String.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool isBinary(Opcode opcode)
|
private static bool isBinary (Opcode opcode)
|
||||||
{
|
{
|
||||||
return opcode == Opcode.BINARY;
|
return opcode == Opcode.BINARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool isClose(Opcode opcode)
|
private static bool isClose (Opcode opcode)
|
||||||
{
|
{
|
||||||
return opcode == Opcode.CLOSE;
|
return opcode == Opcode.CLOSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool isContinuation(Opcode opcode)
|
private static bool isContinuation (Opcode opcode)
|
||||||
{
|
{
|
||||||
return opcode == Opcode.CONT;
|
return opcode == Opcode.CONT;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool isControl(Opcode opcode)
|
private static bool isControl (Opcode opcode)
|
||||||
{
|
{
|
||||||
return opcode == Opcode.CLOSE || opcode == Opcode.PING || opcode == Opcode.PONG;
|
return opcode == Opcode.CLOSE || opcode == Opcode.PING || opcode == Opcode.PONG;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool isData(Opcode opcode)
|
private static bool isData (Opcode opcode)
|
||||||
{
|
{
|
||||||
return opcode == Opcode.TEXT || opcode == Opcode.BINARY;
|
return opcode == Opcode.TEXT || opcode == Opcode.BINARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool isFinal(Fin fin)
|
private static bool isFinal (Fin fin)
|
||||||
{
|
{
|
||||||
return fin == Fin.FINAL;
|
return fin == Fin.FINAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool isMasked(Mask mask)
|
private static bool isMasked (Mask mask)
|
||||||
{
|
{
|
||||||
return mask == Mask.MASK;
|
return mask == Mask.MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool isPing(Opcode opcode)
|
private static bool isPing (Opcode opcode)
|
||||||
{
|
{
|
||||||
return opcode == Opcode.PING;
|
return opcode == Opcode.PING;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool isPong(Opcode opcode)
|
private static bool isPong (Opcode opcode)
|
||||||
{
|
{
|
||||||
return opcode == Opcode.PONG;
|
return opcode == Opcode.PONG;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool isText(Opcode opcode)
|
private static bool isText (Opcode opcode)
|
||||||
{
|
{
|
||||||
return opcode == Opcode.TEXT;
|
return opcode == Opcode.TEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static WsFrame parse(byte[] header, Stream stream, bool unmask)
|
private static WsFrame parse (byte [] header, Stream stream, bool unmask)
|
||||||
{
|
{
|
||||||
/* Header */
|
/* Header */
|
||||||
|
|
||||||
// FIN
|
// FIN
|
||||||
var fin = (header[0] & 0x80) == 0x80 ? Fin.FINAL : Fin.MORE;
|
var fin = (header [0] & 0x80) == 0x80 ? Fin.FINAL : Fin.MORE;
|
||||||
// RSV1
|
// RSV1
|
||||||
var rsv1 = (header[0] & 0x40) == 0x40 ? Rsv.ON : Rsv.OFF;
|
var rsv1 = (header [0] & 0x40) == 0x40 ? Rsv.ON : Rsv.OFF;
|
||||||
// RSV2
|
// RSV2
|
||||||
var rsv2 = (header[0] & 0x20) == 0x20 ? Rsv.ON : Rsv.OFF;
|
var rsv2 = (header [0] & 0x20) == 0x20 ? Rsv.ON : Rsv.OFF;
|
||||||
// RSV3
|
// RSV3
|
||||||
var rsv3 = (header[0] & 0x10) == 0x10 ? Rsv.ON : Rsv.OFF;
|
var rsv3 = (header [0] & 0x10) == 0x10 ? Rsv.ON : Rsv.OFF;
|
||||||
// Opcode
|
// Opcode
|
||||||
var opcode = (Opcode)(header[0] & 0x0f);
|
var opcode = (Opcode) (header [0] & 0x0f);
|
||||||
// MASK
|
// MASK
|
||||||
var mask = (header[1] & 0x80) == 0x80 ? Mask.MASK : Mask.UNMASK;
|
var mask = (header [1] & 0x80) == 0x80 ? Mask.MASK : Mask.UNMASK;
|
||||||
// Payload len
|
// Payload len
|
||||||
var payloadLen = (byte)(header[1] & 0x7f);
|
var payloadLen = (byte) (header [1] & 0x7f);
|
||||||
|
|
||||||
if (isControl(opcode) && payloadLen > 125)
|
if (isControl (opcode) && payloadLen > 125)
|
||||||
return createCloseFrame(CloseStatusCode.INCONSISTENT_DATA,
|
return CreateCloseFrame (
|
||||||
"The payload length of a control frame must be 125 bytes or less.",
|
Mask.UNMASK,
|
||||||
Mask.UNMASK);
|
CloseStatusCode.INCONSISTENT_DATA,
|
||||||
|
"The payload length of a control frame must be 125 bytes or less.");
|
||||||
|
|
||||||
var frame = new WsFrame {
|
var frame = new WsFrame {
|
||||||
Fin = fin,
|
Fin = fin,
|
||||||
@ -404,27 +399,29 @@ namespace WebSocketSharp {
|
|||||||
: 8;
|
: 8;
|
||||||
|
|
||||||
var extPayloadLen = extLen > 0
|
var extPayloadLen = extLen > 0
|
||||||
? stream.ReadBytesInternal(extLen)
|
? stream.ReadBytesInternal (extLen)
|
||||||
: new byte[]{};
|
: new byte []{};
|
||||||
|
|
||||||
if (extLen > 0 && extPayloadLen.Length != extLen)
|
if (extLen > 0 && extPayloadLen.Length != extLen)
|
||||||
return createCloseFrame(CloseStatusCode.ABNORMAL,
|
return CreateCloseFrame (
|
||||||
"'Extended Payload Length' of a frame cannot be read from the data stream.",
|
Mask.UNMASK,
|
||||||
Mask.UNMASK);
|
CloseStatusCode.ABNORMAL,
|
||||||
|
"'Extended Payload Length' of a frame cannot be read from the data stream.");
|
||||||
|
|
||||||
frame.ExtPayloadLen = extPayloadLen;
|
frame.ExtPayloadLen = extPayloadLen;
|
||||||
|
|
||||||
/* Masking Key */
|
/* Masking Key */
|
||||||
|
|
||||||
var masked = mask == Mask.MASK ? true : false;
|
var masked = mask == Mask.MASK;
|
||||||
var maskingKey = masked
|
var maskingKey = masked
|
||||||
? stream.ReadBytesInternal(4)
|
? stream.ReadBytesInternal (4)
|
||||||
: new byte[]{};
|
: new byte []{};
|
||||||
|
|
||||||
if (masked && maskingKey.Length != 4)
|
if (masked && maskingKey.Length != 4)
|
||||||
return createCloseFrame(CloseStatusCode.ABNORMAL,
|
return CreateCloseFrame (
|
||||||
"'Masking Key' of a frame cannot be read from the data stream.",
|
Mask.UNMASK,
|
||||||
Mask.UNMASK);
|
CloseStatusCode.ABNORMAL,
|
||||||
|
"'Masking Key' of a frame cannot be read from the data stream.");
|
||||||
|
|
||||||
frame.MaskingKey = maskingKey;
|
frame.MaskingKey = maskingKey;
|
||||||
|
|
||||||
@ -433,64 +430,65 @@ namespace WebSocketSharp {
|
|||||||
ulong dataLen = payloadLen < 126
|
ulong dataLen = payloadLen < 126
|
||||||
? payloadLen
|
? payloadLen
|
||||||
: payloadLen == 126
|
: payloadLen == 126
|
||||||
? extPayloadLen.To<ushort>(ByteOrder.BIG)
|
? extPayloadLen.To<ushort> (ByteOrder.BIG)
|
||||||
: extPayloadLen.To<ulong>(ByteOrder.BIG);
|
: extPayloadLen.To<ulong> (ByteOrder.BIG);
|
||||||
|
|
||||||
byte[] data = null;
|
byte [] data = null;
|
||||||
if (dataLen > 0)
|
if (dataLen > 0)
|
||||||
{
|
{
|
||||||
if (payloadLen > 126 && dataLen > PayloadData.MaxLength)
|
if (payloadLen > 126 && dataLen > PayloadData.MaxLength)
|
||||||
{
|
{
|
||||||
var code = CloseStatusCode.TOO_BIG;
|
var code = CloseStatusCode.TOO_BIG;
|
||||||
return createCloseFrame(code, code.GetMessage(), Mask.UNMASK);
|
return CreateCloseFrame (Mask.UNMASK, code, code.GetMessage ());
|
||||||
}
|
}
|
||||||
|
|
||||||
data = dataLen > 1024
|
data = dataLen > 1024
|
||||||
? stream.ReadBytesInternal((long)dataLen, 1024)
|
? stream.ReadBytesInternal ((long) dataLen, 1024)
|
||||||
: stream.ReadBytesInternal((int)dataLen);
|
: stream.ReadBytesInternal ((int) dataLen);
|
||||||
|
|
||||||
if (data.LongLength != (long)dataLen)
|
if (data.LongLength != (long) dataLen)
|
||||||
return createCloseFrame(CloseStatusCode.ABNORMAL,
|
return CreateCloseFrame (
|
||||||
"'Payload Data' of a frame cannot be read from the data stream.",
|
Mask.UNMASK,
|
||||||
Mask.UNMASK);
|
CloseStatusCode.ABNORMAL,
|
||||||
|
"'Payload Data' of a frame cannot be read from the data stream.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
data = new byte[]{};
|
data = new byte []{};
|
||||||
}
|
}
|
||||||
|
|
||||||
var payloadData = new PayloadData(data, masked);
|
var payload = new PayloadData (data, masked);
|
||||||
if (masked && unmask)
|
if (masked && unmask)
|
||||||
{
|
{
|
||||||
payloadData.Mask(maskingKey);
|
payload.Mask (maskingKey);
|
||||||
frame.Mask = Mask.UNMASK;
|
frame.Mask = Mask.UNMASK;
|
||||||
frame.MaskingKey = new byte[]{};
|
frame.MaskingKey = new byte []{};
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.PayloadData = payloadData;
|
frame.PayloadData = payload;
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void print(WsFrame frame)
|
private static void print (WsFrame frame)
|
||||||
{
|
{
|
||||||
var len = frame.ExtPayloadLen.Length;
|
var len = frame.ExtPayloadLen.Length;
|
||||||
var extPayloadLen = len == 2
|
var extPayloadLen = len == 2
|
||||||
? frame.ExtPayloadLen.To<ushort>(ByteOrder.BIG).ToString()
|
? frame.ExtPayloadLen.To<ushort> (ByteOrder.BIG).ToString ()
|
||||||
: len == 8
|
: len == 8
|
||||||
? frame.ExtPayloadLen.To<ulong>(ByteOrder.BIG).ToString()
|
? frame.ExtPayloadLen.To<ulong> (ByteOrder.BIG).ToString ()
|
||||||
: String.Empty;
|
: String.Empty;
|
||||||
|
|
||||||
var masked = frame.IsMasked;
|
var masked = frame.IsMasked;
|
||||||
var maskingKey = masked
|
var maskingKey = masked
|
||||||
? BitConverter.ToString(frame.MaskingKey)
|
? BitConverter.ToString (frame.MaskingKey)
|
||||||
: String.Empty;
|
: String.Empty;
|
||||||
|
|
||||||
var opcode = frame.Opcode;
|
var opcode = frame.Opcode;
|
||||||
var payloadData = frame.PayloadData.Length == 0
|
var payloadData = frame.PayloadData.Length == 0
|
||||||
? String.Empty
|
? String.Empty
|
||||||
: masked || frame.IsFragmented || frame.IsBinary || frame.IsClose
|
: masked || frame.IsFragmented || frame.IsBinary || frame.IsClose
|
||||||
? BitConverter.ToString(frame.PayloadData.ToByteArray())
|
? BitConverter.ToString (frame.PayloadData.ToByteArray ())
|
||||||
: Encoding.UTF8.GetString(frame.PayloadData.ToByteArray());
|
: Encoding.UTF8.GetString (frame.PayloadData.ToByteArray ());
|
||||||
|
|
||||||
var format = @"
|
var format = @"
|
||||||
FIN: {0}
|
FIN: {0}
|
||||||
@ -504,168 +502,210 @@ namespace WebSocketSharp {
|
|||||||
Masking Key: {8}
|
Masking Key: {8}
|
||||||
Payload Data: {9}";
|
Payload Data: {9}";
|
||||||
|
|
||||||
Console.WriteLine(
|
Console.WriteLine (
|
||||||
format, frame.Fin, frame.Rsv1, frame.Rsv2, frame.Rsv3, opcode, frame.Mask, frame.PayloadLen, extPayloadLen, maskingKey, payloadData);
|
format, frame.Fin, frame.Rsv1, frame.Rsv2, frame.Rsv3, opcode, frame.Mask, frame.PayloadLen, extPayloadLen, maskingKey, payloadData);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
#region Public Methods
|
#region Public Methods
|
||||||
|
|
||||||
public IEnumerator<byte> GetEnumerator()
|
public static WsFrame CreateCloseFrame (Mask mask, byte [] data)
|
||||||
{
|
{
|
||||||
foreach (byte b in ToByteArray())
|
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 ()
|
||||||
|
{
|
||||||
|
foreach (byte b in ToByteArray ())
|
||||||
yield return b;
|
yield return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WsFrame Parse(byte[] src)
|
public static WsFrame Parse (byte [] src)
|
||||||
{
|
{
|
||||||
return Parse(src, true);
|
return Parse (src, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WsFrame Parse(Stream stream)
|
public static WsFrame Parse (Stream stream)
|
||||||
{
|
{
|
||||||
return Parse(stream, true);
|
return Parse (stream, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WsFrame Parse(byte[] src, bool unmask)
|
public static WsFrame Parse (byte [] src, bool unmask)
|
||||||
{
|
{
|
||||||
using (MemoryStream ms = new MemoryStream(src))
|
using (var stream = new MemoryStream (src))
|
||||||
{
|
{
|
||||||
return Parse(ms, unmask);
|
return Parse (stream, unmask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WsFrame Parse(Stream stream, bool unmask)
|
public static WsFrame Parse (Stream stream, bool unmask)
|
||||||
{
|
{
|
||||||
return Parse(stream, unmask, null);
|
return Parse (stream, unmask, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WsFrame Parse(Stream stream, bool unmask, Action<Exception> error)
|
public static WsFrame Parse (Stream stream, bool unmask, Action<Exception> error)
|
||||||
{
|
{
|
||||||
WsFrame frame = null;
|
WsFrame frame = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var header = stream.ReadBytesInternal(2);
|
var header = stream.ReadBytesInternal (2);
|
||||||
frame = header.Length == 2
|
frame = header.Length == 2
|
||||||
? parse(header, stream, unmask)
|
? parse (header, stream, unmask)
|
||||||
: createCloseFrame(CloseStatusCode.ABNORMAL,
|
: CreateCloseFrame (
|
||||||
"'Header' of a frame cannot be read from the data stream.",
|
Mask.UNMASK,
|
||||||
Mask.UNMASK);
|
CloseStatusCode.ABNORMAL,
|
||||||
|
"'Header' of a frame cannot be read from the data stream.");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (error != null)
|
if (error != null)
|
||||||
error(ex);
|
error (ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ParseAsync(Stream stream, Action<WsFrame> completed)
|
public static void ParseAsync (Stream stream, Action<WsFrame> completed)
|
||||||
{
|
{
|
||||||
ParseAsync(stream, true, completed, null);
|
ParseAsync (stream, true, completed, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ParseAsync(Stream stream, Action<WsFrame> completed, Action<Exception> error)
|
public static void ParseAsync (Stream stream, Action<WsFrame> completed, Action<Exception> error)
|
||||||
{
|
{
|
||||||
ParseAsync(stream, true, completed, error);
|
ParseAsync (stream, true, completed, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ParseAsync(
|
public static void ParseAsync (
|
||||||
Stream stream, bool unmask, Action<WsFrame> completed, Action<Exception> error)
|
Stream stream, bool unmask, Action<WsFrame> completed, Action<Exception> error)
|
||||||
{
|
{
|
||||||
var header = new byte[2];
|
var header = new byte [2];
|
||||||
AsyncCallback callback = ar =>
|
AsyncCallback callback = ar =>
|
||||||
{
|
{
|
||||||
WsFrame frame = null;
|
WsFrame frame = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var readLen = stream.EndRead(ar);
|
var readLen = stream.EndRead (ar);
|
||||||
if (readLen == 1)
|
if (readLen == 1)
|
||||||
{
|
{
|
||||||
var tmp = stream.ReadByte();
|
var tmp = stream.ReadByte ();
|
||||||
if (tmp > -1)
|
if (tmp > -1)
|
||||||
{
|
{
|
||||||
header[1] = (byte)tmp;
|
header [1] = (byte) tmp;
|
||||||
readLen++;
|
readLen++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
frame = readLen == 2
|
frame = readLen == 2
|
||||||
? parse(header, stream, unmask)
|
? parse (header, stream, unmask)
|
||||||
: createCloseFrame(CloseStatusCode.ABNORMAL,
|
: CreateCloseFrame (
|
||||||
"'Header' of a frame cannot be read from the data stream.",
|
Mask.UNMASK,
|
||||||
Mask.UNMASK);
|
CloseStatusCode.ABNORMAL,
|
||||||
|
"'Header' of a frame cannot be read from the data stream.");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (error != null)
|
if (error != null)
|
||||||
error(ex);
|
error (ex);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (completed != null)
|
if (completed != null)
|
||||||
completed(frame);
|
completed (frame);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
stream.BeginRead(header, 0, 2, callback, null);
|
stream.BeginRead (header, 0, 2, callback, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Print(bool dumped)
|
public void Print (bool dumped)
|
||||||
{
|
{
|
||||||
if (dumped)
|
if (dumped)
|
||||||
dump(this);
|
dump (this);
|
||||||
else
|
else
|
||||||
print(this);
|
print (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] ToByteArray()
|
public byte [] ToByteArray()
|
||||||
{
|
{
|
||||||
using (var buffer = new MemoryStream())
|
using (var buffer = new MemoryStream ())
|
||||||
{
|
{
|
||||||
int header = (int)Fin;
|
int header = (int) Fin;
|
||||||
header = (header << 1) + (int)Rsv1;
|
header = (header << 1) + (int) Rsv1;
|
||||||
header = (header << 1) + (int)Rsv2;
|
header = (header << 1) + (int) Rsv2;
|
||||||
header = (header << 1) + (int)Rsv3;
|
header = (header << 1) + (int) Rsv3;
|
||||||
header = (header << 4) + (int)Opcode;
|
header = (header << 4) + (int) Opcode;
|
||||||
header = (header << 1) + (int)Mask;
|
header = (header << 1) + (int) Mask;
|
||||||
header = (header << 7) + (int)PayloadLen;
|
header = (header << 7) + (int) PayloadLen;
|
||||||
buffer.Write(((ushort)header).ToByteArray(ByteOrder.BIG), 0, 2);
|
buffer.Write (((ushort) header).ToByteArray (ByteOrder.BIG), 0, 2);
|
||||||
|
|
||||||
if (PayloadLen > 125)
|
if (PayloadLen > 125)
|
||||||
buffer.Write(ExtPayloadLen, 0, ExtPayloadLen.Length);
|
buffer.Write (ExtPayloadLen, 0, ExtPayloadLen.Length);
|
||||||
|
|
||||||
if (Mask == Mask.MASK)
|
if (Mask == Mask.MASK)
|
||||||
buffer.Write(MaskingKey, 0, MaskingKey.Length);
|
buffer.Write (MaskingKey, 0, MaskingKey.Length);
|
||||||
|
|
||||||
if (PayloadLen > 0)
|
if (PayloadLen > 0)
|
||||||
{
|
{
|
||||||
var payload = PayloadData.ToByteArray();
|
var payload = PayloadData.ToByteArray ();
|
||||||
if (PayloadLen < 127)
|
if (PayloadLen < 127)
|
||||||
buffer.Write(payload, 0, payload.Length);
|
buffer.Write (payload, 0, payload.Length);
|
||||||
else
|
else
|
||||||
buffer.WriteBytes(payload);
|
buffer.WriteBytes (payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.Close();
|
buffer.Close ();
|
||||||
return buffer.ToArray();
|
return buffer.ToArray ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString ()
|
||||||
{
|
{
|
||||||
return BitConverter.ToString(ToByteArray());
|
return BitConverter.ToString (ToByteArray ());
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Explicitly Implemented Interface Members
|
#region Explicitly Implemented Interface Members
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
IEnumerator IEnumerable.GetEnumerator ()
|
||||||
{
|
{
|
||||||
return GetEnumerator();
|
return GetEnumerator ();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -98,24 +98,6 @@ namespace WebSocketSharp
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Private Methods
|
|
||||||
|
|
||||||
private bool write (byte [] data)
|
|
||||||
{
|
|
||||||
lock (_forWrite)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
_innerStream.Write (data, 0, data.Length);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Internal Methods
|
#region Internal Methods
|
||||||
|
|
||||||
internal static WsStream CreateClientStream (
|
internal static WsStream CreateClientStream (
|
||||||
@ -160,6 +142,20 @@ namespace WebSocketSharp
|
|||||||
return new WsStream (conn.Stream, conn.IsSecure);
|
return new WsStream (conn.Stream, conn.IsSecure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal bool Write (byte [] data)
|
||||||
|
{
|
||||||
|
lock (_forWrite)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
_innerStream.Write (data, 0, data.Length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Public Methods
|
#region Public Methods
|
||||||
@ -222,12 +218,12 @@ namespace WebSocketSharp
|
|||||||
|
|
||||||
public bool WriteFrame (WsFrame frame)
|
public bool WriteFrame (WsFrame frame)
|
||||||
{
|
{
|
||||||
return write (frame.ToByteArray ());
|
return Write (frame.ToByteArray ());
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool WriteHandshake (HandshakeBase handshake)
|
public bool WriteHandshake (HandshakeBase handshake)
|
||||||
{
|
{
|
||||||
return write (handshake.ToByteArray ());
|
return Write (handshake.ToByteArray ());
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
Loading…
Reference in New Issue
Block a user