Modified closing and ping

This commit is contained in:
sta 2013-10-01 14:52:39 +09:00
parent f103cd2faf
commit 2b57a58da2
12 changed files with 491 additions and 454 deletions

View File

@ -41,7 +41,7 @@ namespace WebSocketSharp
/// </remarks>
public class CloseEventArgs : MessageEventArgs
{
#region Fields
#region Private Fields
private bool _clean;
private ushort _code;
@ -49,19 +49,19 @@ namespace WebSocketSharp
#endregion
#region Constructors
#region Internal Constructors
internal CloseEventArgs (PayloadData data)
: base (Opcode.CLOSE, data)
internal CloseEventArgs (PayloadData payload)
: base (Opcode.CLOSE, payload)
{
_code = getCodeFrom (data);
_reason = getReasonFrom (data);
_code = getCodeFrom (RawData);
_reason = getReasonFrom (RawData);
_clean = false;
}
#endregion
#region Properties
#region Public Properties
/// <summary>
/// Gets the status code for closure.
@ -107,23 +107,19 @@ namespace WebSocketSharp
#region Private Methods
private static ushort getCodeFrom (PayloadData data)
private static ushort getCodeFrom (byte [] data)
{
var appData = data.ApplicationData;
return appData.Length >= 2
? appData.SubArray (0, 2).To<ushort> (ByteOrder.BIG)
: (ushort) CloseStatusCode.NO_STATUS_CODE;
return data.Length > 1
? data.SubArray (0, 2).To<ushort> (ByteOrder.BIG)
: (ushort) 0;
}
private static string getReasonFrom (PayloadData data)
private static string getReasonFrom (byte [] data)
{
var appData = data.ApplicationData;
var appDataLen = appData.Length;
if (appDataLen <= 2)
return String.Empty;
var reason = appData.SubArray (2, appDataLen - 2);
return Encoding.UTF8.GetString (reason);
var len = data.Length;
return len > 2
? Encoding.UTF8.GetString (data.SubArray (2, len - 2))
: String.Empty;
}
#endregion

View File

@ -168,7 +168,7 @@ namespace WebSocketSharp
internal static string CheckIfStarted (this ServerState state)
{
return state != ServerState.START
? "Not started, on shutdown or stopped."
? "Any of not started, on shutdown or stopped."
: null;
}
@ -396,6 +396,22 @@ namespace WebSocketSharp
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)
{
int len = value.Length;

View File

@ -29,8 +29,8 @@
using System;
using System.Text;
namespace WebSocketSharp {
namespace WebSocketSharp
{
/// <summary>
/// Contains the event data associated with a <see cref="WebSocket.OnMessage"/> event.
/// </summary>
@ -105,7 +105,7 @@ namespace WebSocketSharp {
/// Gets the type of the received data.
/// </summary>
/// <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>
public Opcode Type {
get {

View File

@ -33,11 +33,11 @@ using System.IO;
using System.Linq;
using System.Text;
namespace WebSocketSharp {
namespace WebSocketSharp
{
internal class PayloadData : IEnumerable<byte>
{
#region Public Fields
#region Public Const Fields
public const ulong MaxLength = long.MaxValue;
@ -87,17 +87,9 @@ namespace WebSocketSharp {
internal bool ContainsReservedCloseStatusCode {
get {
if (Length >= 2)
{
var code = ToByteArray().SubArray(0, 2).To<ushort>(ByteOrder.BIG);
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;
return ApplicationData.Length > 1
? ApplicationData.SubArray (0, 2).To<ushort> (ByteOrder.BIG).IsReserved ()
: false;
}
}
@ -105,12 +97,6 @@ namespace WebSocketSharp {
get; private set;
}
internal ulong Length {
get {
return (ulong)(ExtensionData.LongLength + ApplicationData.LongLength);
}
}
#endregion
#region Public Properties
@ -123,6 +109,12 @@ namespace WebSocketSharp {
get; private set;
}
public ulong Length {
get {
return (ulong) (ExtensionData.LongLength + ApplicationData.LongLength);
}
}
#endregion
#region Private Methods

View File

@ -321,7 +321,7 @@ namespace WebSocketSharp.Server
}
_listening = false;
_serviceHosts.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG));
_serviceHosts.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG), true);
_listener.Abort ();
_state = ServerState.STOP;
@ -617,7 +617,7 @@ namespace WebSocketSharp.Server
_state = ServerState.SHUTDOWN;
}
_serviceHosts.Stop ();
_serviceHosts.Stop (new byte []{}, true);
stopListener ();
_state = ServerState.STOP;
@ -651,7 +651,7 @@ namespace WebSocketSharp.Server
_state = ServerState.SHUTDOWN;
}
_serviceHosts.Stop (data);
_serviceHosts.Stop (data, !code.IsReserved ());
stopListener ();
_state = ServerState.STOP;
@ -685,7 +685,7 @@ namespace WebSocketSharp.Server
_state = ServerState.SHUTDOWN;
}
_serviceHosts.Stop (data);
_serviceHosts.Stop (data, !code.IsReserved ());
stopListener ();
_state = ServerState.STOP;

View File

@ -201,7 +201,7 @@ namespace WebSocketSharp.Server
}
StopListener ();
_serviceHosts.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG));
_serviceHosts.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG), true);
_state = ServerState.STOP;
}
@ -313,7 +313,7 @@ namespace WebSocketSharp.Server
base.Start ();
if (!IsListening)
{
_serviceHosts.Stop ();
_serviceHosts.Stop (new byte []{}, false);
return;
}
@ -339,7 +339,7 @@ namespace WebSocketSharp.Server
}
base.Stop ();
_serviceHosts.Stop ();
_serviceHosts.Stop (new byte []{}, true);
_state = ServerState.STOP;
}
@ -373,7 +373,7 @@ namespace WebSocketSharp.Server
}
base.Stop ();
_serviceHosts.Stop (data);
_serviceHosts.Stop (data, !code.IsReserved ());
_state = ServerState.STOP;
}
@ -407,7 +407,7 @@ namespace WebSocketSharp.Server
}
base.Stop ();
_serviceHosts.Stop (data);
_serviceHosts.Stop (data, !code.IsReserved ());
_state = ServerState.STOP;
}

View File

@ -294,7 +294,7 @@ namespace WebSocketSharp.Server
}
StopListener ();
_sessions.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG));
_sessions.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG), true);
_state = ServerState.STOP;
}
@ -346,7 +346,7 @@ namespace WebSocketSharp.Server
base.Start ();
if (!IsListening)
{
_sessions.Stop ();
_sessions.Stop (new byte []{}, false);
return;
}
@ -372,7 +372,7 @@ namespace WebSocketSharp.Server
}
base.Stop ();
_sessions.Stop ();
_sessions.Stop (new byte []{}, true);
_state = ServerState.STOP;
}
@ -406,7 +406,7 @@ namespace WebSocketSharp.Server
}
base.Stop ();
_sessions.Stop (data);
_sessions.Stop (data, !code.IsReserved ());
_state = ServerState.STOP;
}
@ -440,7 +440,7 @@ namespace WebSocketSharp.Server
}
base.Stop ();
_sessions.Stop (data);
_sessions.Stop (data, !code.IsReserved ());
_state = ServerState.STOP;
}

View File

@ -195,7 +195,7 @@ namespace WebSocketSharp.Server
#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>> ();
foreach (var host in ServiceHosts)
@ -203,7 +203,7 @@ namespace WebSocketSharp.Server
if (_state != ServerState.START)
break;
result.Add (host.ServicePath, host.Sessions.BroadpingInternally (data));
result.Add (host.ServicePath, host.Sessions.BroadpingInternally (frameAsBytes, timeOut));
}
return result;
@ -250,7 +250,7 @@ namespace WebSocketSharp.Server
}
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;
}
@ -266,28 +266,23 @@ namespace WebSocketSharp.Server
}
}
internal void Stop ()
internal void Stop (byte [] data, bool send)
{
lock (_sync)
{
_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)
host.Sessions.Stop ();
host.Sessions.Stop (args, frameAsBytes);
_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;
}
}
@ -430,7 +425,7 @@ namespace WebSocketSharp.Server
return null;
}
return broadping (new byte [] {});
return broadping (WsFrame.CreatePingFrame (Mask.UNMASK).ToByteArray (), 1000);
}
/// <summary>
@ -459,7 +454,7 @@ namespace WebSocketSharp.Server
return null;
}
return broadping (data);
return broadping (WsFrame.CreatePingFrame (Mask.UNMASK, data).ToByteArray (), 1000);
}
/// <summary>
@ -489,7 +484,7 @@ namespace WebSocketSharp.Server
return null;
}
return host.Sessions.BroadpingInternally (new byte [] {});
return host.Sessions.BroadpingInternally ();
}
/// <summary>
@ -527,7 +522,8 @@ namespace WebSocketSharp.Server
return null;
}
return host.Sessions.BroadpingInternally (data);
return host.Sessions.BroadpingInternally (
WsFrame.CreatePingFrame (Mask.UNMASK, data).ToByteArray (), 1000);
}
/// <summary>

View File

@ -106,7 +106,7 @@ namespace WebSocketSharp.Server
/// </value>
public IEnumerable<string> ActiveIDs {
get {
return from result in BroadpingInternally (new byte [] {})
return from result in BroadpingInternally ()
where result.Value
select result.Key;
}
@ -150,7 +150,7 @@ namespace WebSocketSharp.Server
/// </value>
public IEnumerable<string> InactiveIDs {
get {
return from result in BroadpingInternally (new byte [] {})
return from result in BroadpingInternally ()
where !result.Value
select result.Key;
}
@ -282,7 +282,12 @@ namespace WebSocketSharp.Server
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> ();
foreach (var session in ServiceInstances)
@ -290,7 +295,7 @@ namespace WebSocketSharp.Server
if (_state != ServerState.START)
break;
result.Add (session.ID, session.Context.WebSocket.Ping (data));
result.Add (session.ID, session.Context.WebSocket.Ping (frameAsBytes, timeOut));
}
return result;
@ -310,7 +315,18 @@ namespace WebSocketSharp.Server
_state = ServerState.START;
}
internal void Stop ()
internal void Stop (byte [] data, bool send)
{
var payload = new PayloadData (data);
var args = new CloseEventArgs (payload);
var frameAsBytes = send
? WsFrame.CreateCloseFrame (Mask.UNMASK, payload).ToByteArray ()
: null;
Stop (args, frameAsBytes);
}
internal void Stop (CloseEventArgs args, byte [] frameAsBytes)
{
lock (_sync)
{
@ -318,21 +334,7 @@ namespace WebSocketSharp.Server
_sweepTimer.Enabled = false;
foreach (var session in _sessions.Values.ToList ())
session.Context.WebSocket.Close ();
_state = ServerState.STOP;
}
}
internal void Stop (byte [] data)
{
lock (_sync)
{
_state = ServerState.SHUTDOWN;
_sweepTimer.Enabled = false;
foreach (var session in _sessions.Values.ToList ())
session.Context.WebSocket.Close (data);
session.Context.WebSocket.Close (args, frameAsBytes, 1000);
_state = ServerState.STOP;
}
@ -402,7 +404,7 @@ namespace WebSocketSharp.Server
return null;
}
return BroadpingInternally (new byte [] {});
return BroadpingInternally ();
}
/// <summary>
@ -428,7 +430,7 @@ namespace WebSocketSharp.Server
return null;
}
return BroadpingInternally (data);
return BroadpingInternally (WsFrame.CreatePingFrame (Mask.UNMASK, data).ToByteArray (), 1000);
}
/// <summary>

View File

@ -80,7 +80,6 @@ namespace WebSocketSharp
private string _extensions;
private AutoResetEvent _exitReceiving;
private object _forClose;
private object _forFrame;
private object _forSend;
private volatile Logger _logger;
private string _origin;
@ -104,7 +103,6 @@ namespace WebSocketSharp
_cookies = new CookieCollection ();
_extensions = String.Empty;
_forClose = new object ();
_forFrame = new object ();
_forSend = new object ();
_logger = new Logger ();
_origin = String.Empty;
@ -319,9 +317,7 @@ namespace WebSocketSharp
/// </value>
public bool IsAlive {
get {
return _readyState == WebSocketState.OPEN
? Ping (new byte [] {})
: false;
return Ping ();
}
}
@ -531,23 +527,13 @@ namespace WebSocketSharp
return send (createHandshakeResponse ());
}
// As server
private void close (HttpStatusCode code)
private void close (CloseStatusCode code, string reason, bool wait)
{
send (createHandshakeResponse (code));
try {
closeServerResources ();
}
catch {
close (new PayloadData (((ushort) code).Append (reason)), !code.IsReserved (), wait);
}
_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)
{
if (_readyState == WebSocketState.CLOSING || _readyState == WebSocketState.CLOSED)
@ -555,40 +541,42 @@ namespace WebSocketSharp
_logger.Trace ("Start closing handshake.");
var current = _readyState;
_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 released = closeResources ();
args.WasClean = sent && received && released;
_logger.Debug (String.Format (
"Was clean?: {0}\nsent: {1} received: {2} released: {3}", args.WasClean, sent, received, released));
var args = new CloseEventArgs (payload);
args.WasClean = _client
? close (
send ? WsFrame.CreateCloseFrame (Mask.MASK, payload).ToByteArray () : null,
wait ? 5000 : 0,
closeClientResources)
: close (
send ? WsFrame.CreateCloseFrame (Mask.UNMASK, payload).ToByteArray () : null,
wait ? 1000 : 0,
closeServerResources);
_readyState = WebSocketState.CLOSED;
_logger.Trace ("End closing handshake.");
_logger.Trace ("End closing handshake.");
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);
close (new PayloadData (data), received);
var sent = frameAsBytes != null && _stream.Write (frameAsBytes);
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
private void closeClientResources ()
private bool closeClientResources ()
{
try {
if (_stream != null)
{
_stream.Dispose ();
@ -600,15 +588,6 @@ namespace WebSocketSharp
_tcpClient.Close ();
_tcpClient = null;
}
}
private bool closeResources ()
{
try {
if (_client)
closeClientResources ();
else
closeServerResources ();
return true;
}
@ -621,13 +600,23 @@ namespace WebSocketSharp
}
// As server
private void closeServerResources ()
private bool closeServerResources ()
{
try {
if (_closeContext != null)
_closeContext ();
_stream = null;
_context = null;
return true;
}
catch (Exception ex) {
_logger.Fatal (ex.ToString ());
error ("An exception has occured.");
return false;
}
}
private bool concatenateFragments (Stream dest)
@ -697,23 +686,6 @@ namespace WebSocketSharp
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
private HandshakeRequest createHandshakeRequest ()
{
@ -851,23 +823,19 @@ namespace WebSocketSharp
OnOpen.Emit (this, EventArgs.Empty);
}
private void pong (PayloadData data)
{
var frame = createControlFrame (Opcode.PONG, data, _client);
send (frame);
}
private bool processAbnormalFrame ()
{
var code = CloseStatusCode.ABNORMAL;
close (code, code.GetMessage (), true);
close (code, code.GetMessage (), false);
return false;
}
private bool processCloseFrame (WsFrame frame)
{
close (frame.PayloadData, true);
var payload = frame.PayloadData;
close (payload, !payload.ContainsReservedCloseStatusCode, false);
return false;
}
@ -937,22 +905,23 @@ namespace WebSocketSharp
private bool processIncorrectFrame ()
{
close (CloseStatusCode.INCORRECT_DATA, null, true);
close (CloseStatusCode.INCORRECT_DATA, null, false);
return false;
}
private bool processPingFrame (WsFrame frame)
{
_logger.Trace ("Return Pong.");
pong (frame.PayloadData);
if (send (WsFrame.CreatePongFrame (
_client ? Mask.MASK : Mask.UNMASK, frame.PayloadData).ToByteArray ()))
_logger.Trace ("Returned Pong.");
return true;
}
private bool processPongFrame ()
{
_logger.Trace ("Receive Pong.");
_receivePong.Set ();
_logger.Trace ("Received Pong.");
return true;
}
@ -1012,11 +981,25 @@ namespace WebSocketSharp
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
private void send (HandshakeRequest request)
{
_logger.Debug (String.Format ("A WebSocket connection request to {0}:\n{1}",
_uri, request));
_logger.Debug (String.Format (
"A WebSocket connection request to {0}:\n{1}", _uri, request));
_stream.WriteHandshake (request);
}
@ -1029,13 +1012,7 @@ namespace WebSocketSharp
private bool send (WsFrame frame)
{
lock (_forFrame)
{
var ready = _stream != null &&
(_readyState == WebSocketState.OPEN ||
(_readyState == WebSocketState.CLOSING && frame.IsClose));
if (!ready)
if (_readyState != WebSocketState.OPEN)
{
var msg = "A WebSocket connection isn't established or has been closed.";
_logger.Error (msg);
@ -1046,7 +1023,6 @@ namespace WebSocketSharp
return _stream.WriteFrame (frame);
}
}
private void send (Opcode opcode, Stream stream)
{
@ -1091,8 +1067,8 @@ namespace WebSocketSharp
private bool send (Fin fin, Opcode opcode, byte [] data, bool compressed)
{
var frame = createFrame (fin, opcode, new PayloadData (data), compressed, _client);
return send (frame);
return send (
WsFrame.CreateFrame (fin, opcode, _client ? Mask.MASK : Mask.UNMASK, data, compressed));
}
private void sendAsync (Opcode opcode, Stream stream, Action completed)
@ -1201,12 +1177,12 @@ namespace WebSocketSharp
catch (WebSocketException ex) {
_logger.Fatal (ex.ToString ());
error ("An exception has occured.");
close (ex.Code, ex.Message, true);
close (ex.Code, ex.Message, false);
}
catch (Exception ex) {
_logger.Fatal (ex.ToString ());
error ("An exception has occured.");
close (CloseStatusCode.ABNORMAL, null, true);
close (CloseStatusCode.ABNORMAL, null, false);
}
};
@ -1263,27 +1239,39 @@ namespace WebSocketSharp
#region Internal Methods
// As server
internal void Close (byte [] data)
{
close (new PayloadData (data), false);
}
// As server
internal void Close (HttpStatusCode code)
{
_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);
var timeOut = _client ? 5000 : 1000;
lock (_forClose)
{
if (_readyState == WebSocketState.CLOSING || _readyState == WebSocketState.CLOSED)
return;
return send (frame)
? _receivePong.WaitOne (timeOut)
: false;
_readyState = WebSocketState.CLOSING;
}
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
@ -1295,7 +1283,7 @@ namespace WebSocketSharp
/// </summary>
public void Close ()
{
close (new PayloadData (), false);
close (new PayloadData (), _readyState == WebSocketState.OPEN, true);
}
/// <summary>
@ -1320,7 +1308,8 @@ namespace WebSocketSharp
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>
@ -1332,7 +1321,8 @@ namespace WebSocketSharp
/// </param>
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>
@ -1364,7 +1354,8 @@ namespace WebSocketSharp
return;
}
close (new PayloadData (data), false);
var send = _readyState == WebSocketState.OPEN && !code.IsReserved ();
close (new PayloadData (data), send, true);
}
/// <summary>
@ -1393,7 +1384,8 @@ namespace WebSocketSharp
return;
}
close (new PayloadData (data), false);
var send = _readyState == WebSocketState.OPEN && !code.IsReserved ();
close (new PayloadData (data), send, true);
}
/// <summary>
@ -1417,7 +1409,10 @@ namespace WebSocketSharp
catch (Exception ex) {
_logger.Fatal (ex.ToString ());
error ("An exception has occured.");
if (_client)
Close (CloseStatusCode.ABNORMAL);
else
Close (HttpStatusCode.BadRequest);
}
}
@ -1441,7 +1436,9 @@ namespace WebSocketSharp
/// </returns>
public bool Ping ()
{
return Ping (new byte [] {});
return _client
? Ping (WsFrame.CreatePingFrame (Mask.MASK).ToByteArray (), 5000)
: Ping (WsFrame.CreatePingFrame (Mask.UNMASK).ToByteArray (), 1000);
}
/// <summary>
@ -1457,7 +1454,7 @@ namespace WebSocketSharp
public bool Ping (string message)
{
if (message == null || message.Length == 0)
return Ping (new byte [] {});
return Ping ();
var data = Encoding.UTF8.GetBytes (message);
var msg = data.CheckIfValidPingData ();
@ -1469,7 +1466,9 @@ namespace WebSocketSharp
return false;
}
return Ping (data);
return _client
? Ping (WsFrame.CreatePingFrame (Mask.MASK, data).ToByteArray (), 5000)
: Ping (WsFrame.CreatePingFrame (Mask.UNMASK, data).ToByteArray (), 1000);
}
/// <summary>

View File

@ -32,8 +32,8 @@ using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace WebSocketSharp {
namespace WebSocketSharp
{
internal class WsFrame : IEnumerable<byte>
{
#region Private Constructors
@ -46,23 +46,23 @@ namespace WebSocketSharp {
#region Public Constructors
public WsFrame(Opcode opcode, PayloadData payloadData)
: this(opcode, Mask.MASK, payloadData)
public WsFrame (Opcode opcode, PayloadData payload)
: this (opcode, Mask.MASK, payload)
{
}
public WsFrame(Opcode opcode, Mask mask, PayloadData payloadData)
: this(Fin.FINAL, opcode, mask, payloadData)
public WsFrame (Opcode opcode, Mask mask, PayloadData payload)
: this (Fin.FINAL, opcode, mask, payload)
{
}
public WsFrame(Fin fin, Opcode opcode, Mask mask, PayloadData payloadData)
: this(fin, opcode, mask, payloadData, false)
public WsFrame (Fin fin, Opcode opcode, Mask mask, PayloadData payload)
: this (fin, opcode, mask, payload, false)
{
}
public WsFrame (
Fin fin, Opcode opcode, Mask mask, PayloadData payloadData, bool compressed)
Fin fin, Opcode opcode, Mask mask, PayloadData payload, bool compressed)
{
Fin = fin;
Rsv1 = isData (opcode) && compressed ? Rsv.ON : Rsv.OFF;
@ -73,7 +73,7 @@ namespace WebSocketSharp {
/* PayloadLen */
ulong dataLen = payloadData.Length;
var dataLen = payload.Length;
var payloadLen = dataLen < 126
? (byte) dataLen
: dataLen < 0x010000
@ -102,9 +102,9 @@ namespace WebSocketSharp {
/* PayloadData */
if (masking)
payloadData.Mask(maskingKey);
payload.Mask (maskingKey);
PayloadData = payloadData;
PayloadData = payload;
}
#endregion
@ -226,12 +226,6 @@ namespace WebSocketSharp {
#region Private Methods
private static WsFrame createCloseFrame(CloseStatusCode code, string reason, Mask mask)
{
var data = ((ushort)code).Append(reason);
return new WsFrame(Fin.FINAL, Opcode.CLOSE, mask, new PayloadData(data));
}
private static byte [] createMaskingKey ()
{
var key = new byte [4];
@ -381,9 +375,10 @@ namespace WebSocketSharp {
var payloadLen = (byte) (header [1] & 0x7f);
if (isControl (opcode) && payloadLen > 125)
return createCloseFrame(CloseStatusCode.INCONSISTENT_DATA,
"The payload length of a control frame must be 125 bytes or less.",
Mask.UNMASK);
return CreateCloseFrame (
Mask.UNMASK,
CloseStatusCode.INCONSISTENT_DATA,
"The payload length of a control frame must be 125 bytes or less.");
var frame = new WsFrame {
Fin = fin,
@ -408,23 +403,25 @@ namespace WebSocketSharp {
: new byte []{};
if (extLen > 0 && extPayloadLen.Length != extLen)
return createCloseFrame(CloseStatusCode.ABNORMAL,
"'Extended Payload Length' of a frame cannot be read from the data stream.",
Mask.UNMASK);
return CreateCloseFrame (
Mask.UNMASK,
CloseStatusCode.ABNORMAL,
"'Extended Payload Length' of a frame cannot be read from the data stream.");
frame.ExtPayloadLen = extPayloadLen;
/* Masking Key */
var masked = mask == Mask.MASK ? true : false;
var masked = mask == Mask.MASK;
var maskingKey = masked
? stream.ReadBytesInternal (4)
: new byte []{};
if (masked && maskingKey.Length != 4)
return createCloseFrame(CloseStatusCode.ABNORMAL,
"'Masking Key' of a frame cannot be read from the data stream.",
Mask.UNMASK);
return CreateCloseFrame (
Mask.UNMASK,
CloseStatusCode.ABNORMAL,
"'Masking Key' of a frame cannot be read from the data stream.");
frame.MaskingKey = maskingKey;
@ -442,7 +439,7 @@ namespace WebSocketSharp {
if (payloadLen > 126 && dataLen > PayloadData.MaxLength)
{
var code = CloseStatusCode.TOO_BIG;
return createCloseFrame(code, code.GetMessage(), Mask.UNMASK);
return CreateCloseFrame (Mask.UNMASK, code, code.GetMessage ());
}
data = dataLen > 1024
@ -450,24 +447,25 @@ namespace WebSocketSharp {
: stream.ReadBytesInternal ((int) dataLen);
if (data.LongLength != (long) dataLen)
return createCloseFrame(CloseStatusCode.ABNORMAL,
"'Payload Data' of a frame cannot be read from the data stream.",
Mask.UNMASK);
return CreateCloseFrame (
Mask.UNMASK,
CloseStatusCode.ABNORMAL,
"'Payload Data' of a frame cannot be read from the data stream.");
}
else
{
data = new byte []{};
}
var payloadData = new PayloadData(data, masked);
var payload = new PayloadData (data, masked);
if (masked && unmask)
{
payloadData.Mask(maskingKey);
payload.Mask (maskingKey);
frame.Mask = Mask.UNMASK;
frame.MaskingKey = new byte []{};
}
frame.PayloadData = payloadData;
frame.PayloadData = payload;
return frame;
}
@ -510,8 +508,48 @@ namespace WebSocketSharp {
#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
public static WsFrame CreateCloseFrame (Mask mask, byte [] data)
{
return new WsFrame (Opcode.CLOSE, mask, new PayloadData (data));
}
public static WsFrame CreateCloseFrame (Mask mask, CloseStatusCode code, string reason)
{
return new WsFrame (Opcode.CLOSE, mask, new PayloadData (((ushort) code).Append (reason)));
}
public static WsFrame CreateFrame (
Fin fin, Opcode opcode, Mask mask, byte [] data, bool compressed)
{
return new WsFrame (fin, opcode, mask, new PayloadData (data), compressed);
}
public static WsFrame CreatePingFrame (Mask mask)
{
return new WsFrame (Opcode.PING, mask, new PayloadData ());
}
public static WsFrame CreatePingFrame (Mask mask, byte [] data)
{
return new WsFrame (Opcode.PING, mask, new PayloadData (data));
}
public IEnumerator<byte> GetEnumerator ()
{
foreach (byte b in ToByteArray ())
@ -530,9 +568,9 @@ namespace WebSocketSharp {
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);
}
}
@ -549,9 +587,10 @@ namespace WebSocketSharp {
var header = stream.ReadBytesInternal (2);
frame = header.Length == 2
? parse (header, stream, unmask)
: createCloseFrame(CloseStatusCode.ABNORMAL,
"'Header' of a frame cannot be read from the data stream.",
Mask.UNMASK);
: CreateCloseFrame (
Mask.UNMASK,
CloseStatusCode.ABNORMAL,
"'Header' of a frame cannot be read from the data stream.");
}
catch (Exception ex)
{
@ -594,9 +633,10 @@ namespace WebSocketSharp {
frame = readLen == 2
? parse (header, stream, unmask)
: createCloseFrame(CloseStatusCode.ABNORMAL,
"'Header' of a frame cannot be read from the data stream.",
Mask.UNMASK);
: CreateCloseFrame (
Mask.UNMASK,
CloseStatusCode.ABNORMAL,
"'Header' of a frame cannot be read from the data stream.");
}
catch (Exception ex)
{

View File

@ -98,24 +98,6 @@ namespace WebSocketSharp
#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
internal static WsStream CreateClientStream (
@ -160,6 +142,20 @@ namespace WebSocketSharp
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
#region Public Methods
@ -222,12 +218,12 @@ namespace WebSocketSharp
public bool WriteFrame (WsFrame frame)
{
return write (frame.ToByteArray ());
return Write (frame.ToByteArray ());
}
public bool WriteHandshake (HandshakeBase handshake)
{
return write (handshake.ToByteArray ());
return Write (handshake.ToByteArray ());
}
#endregion