From 2b57a58da2454679bc1f63ab4543c4dd3a710d93 Mon Sep 17 00:00:00 2001 From: sta Date: Tue, 1 Oct 2013 14:52:39 +0900 Subject: [PATCH] Modified closing and ping --- websocket-sharp/CloseEventArgs.cs | 36 +- websocket-sharp/Ext.cs | 18 +- websocket-sharp/MessageEventArgs.cs | 20 +- websocket-sharp/PayloadData.cs | 86 ++-- websocket-sharp/Server/HttpServer.cs | 8 +- websocket-sharp/Server/WebSocketServer.cs | 10 +- .../Server/WebSocketServiceHost.cs | 10 +- .../Server/WebSocketServiceHostManager.cs | 38 +- .../Server/WebSocketSessionManager.cs | 38 +- websocket-sharp/WebSocket.cs | 265 ++++++------ websocket-sharp/WsFrame.cs | 380 ++++++++++-------- websocket-sharp/WsStream.cs | 36 +- 12 files changed, 491 insertions(+), 454 deletions(-) diff --git a/websocket-sharp/CloseEventArgs.cs b/websocket-sharp/CloseEventArgs.cs index ee65563b..67cbdea5 100644 --- a/websocket-sharp/CloseEventArgs.cs +++ b/websocket-sharp/CloseEventArgs.cs @@ -41,7 +41,7 @@ namespace WebSocketSharp /// 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 /// /// 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 (ByteOrder.BIG) - : (ushort) CloseStatusCode.NO_STATUS_CODE; + return data.Length > 1 + ? data.SubArray (0, 2).To (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 diff --git a/websocket-sharp/Ext.cs b/websocket-sharp/Ext.cs index 7f6aa368..549ed78a 100644 --- a/websocket-sharp/Ext.cs +++ b/websocket-sharp/Ext.cs @@ -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; diff --git a/websocket-sharp/MessageEventArgs.cs b/websocket-sharp/MessageEventArgs.cs index 3dddf973..cf2cf8a1 100644 --- a/websocket-sharp/MessageEventArgs.cs +++ b/websocket-sharp/MessageEventArgs.cs @@ -29,8 +29,8 @@ using System; using System.Text; -namespace WebSocketSharp { - +namespace WebSocketSharp +{ /// /// Contains the event data associated with a event. /// @@ -51,16 +51,16 @@ namespace WebSocketSharp { #region Internal Constructors - internal MessageEventArgs(Opcode opcode, byte[] rawData) + internal MessageEventArgs (Opcode opcode, byte[] rawData) { - if ((ulong)rawData.LongLength > PayloadData.MaxLength) - throw new WebSocketException(CloseStatusCode.TOO_BIG); + if ((ulong) rawData.LongLength > PayloadData.MaxLength) + throw new WebSocketException (CloseStatusCode.TOO_BIG); _opcode = opcode; _rawData = rawData; } - internal MessageEventArgs(Opcode opcode, PayloadData data) + internal MessageEventArgs (Opcode opcode, PayloadData data) { _opcode = opcode; _rawData = data.ApplicationData; @@ -82,8 +82,8 @@ namespace WebSocketSharp { _data = _rawData.LongLength == 0 ? String.Empty : _opcode == Opcode.TEXT - ? Encoding.UTF8.GetString(_rawData) - : _opcode.ToString(); + ? Encoding.UTF8.GetString (_rawData) + : _opcode.ToString (); return _data; } @@ -95,7 +95,7 @@ namespace WebSocketSharp { /// /// An array of that contains the received data. /// - public byte[] RawData { + public byte [] RawData { get { return _rawData; } @@ -105,7 +105,7 @@ namespace WebSocketSharp { /// Gets the type of the received data. /// /// - /// One of the values that indicates the type of the received data. + /// One of the values, indicates the type of the received data. /// public Opcode Type { get { diff --git a/websocket-sharp/PayloadData.cs b/websocket-sharp/PayloadData.cs index 6be0cbac..2c4034b3 100644 --- a/websocket-sharp/PayloadData.cs +++ b/websocket-sharp/PayloadData.cs @@ -33,11 +33,11 @@ using System.IO; using System.Linq; using System.Text; -namespace WebSocketSharp { - +namespace WebSocketSharp +{ internal class PayloadData : IEnumerable { - #region Public Fields + #region Public Const Fields public const ulong MaxLength = long.MaxValue; @@ -45,35 +45,35 @@ namespace WebSocketSharp { #region Public Constructors - public PayloadData() - : this(new byte[]{}) + public PayloadData () + : this (new byte []{}) { } - public PayloadData(byte[] appData) - : this(new byte[]{}, appData) + public PayloadData (byte [] appData) + : this (new byte []{}, appData) { } - public PayloadData(string appData) - : this(Encoding.UTF8.GetBytes(appData)) + public PayloadData (string appData) + : this (Encoding.UTF8.GetBytes (appData)) { } - public PayloadData(byte[] appData, bool masked) - : this(new byte[]{}, appData, masked) + public PayloadData (byte [] appData, bool masked) + : this (new byte []{}, appData, masked) { } - public PayloadData(byte[] extData, byte[] appData) - : this(extData, appData, false) + public PayloadData (byte [] extData, byte [] appData) + : 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) - throw new ArgumentOutOfRangeException( + if ((ulong) extData.LongLength + (ulong) appData.LongLength > MaxLength) + throw new ArgumentOutOfRangeException ( "The length of 'extData' plus 'appData' must be less than MaxLength."); ExtensionData = extData; @@ -87,17 +87,9 @@ namespace WebSocketSharp { internal bool ContainsReservedCloseStatusCode { get { - if (Length >= 2) - { - var code = ToByteArray().SubArray(0, 2).To(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 (ByteOrder.BIG).IsReserved () + : false; } } @@ -105,32 +97,32 @@ namespace WebSocketSharp { get; private set; } - internal ulong Length { - get { - return (ulong)(ExtensionData.LongLength + ApplicationData.LongLength); - } - } - #endregion #region Public Properties - public byte[] ExtensionData { + public byte [] ExtensionData { get; private set; } - public byte[] ApplicationData { + public byte [] ApplicationData { get; private set; } + public ulong Length { + get { + return (ulong) (ExtensionData.LongLength + ApplicationData.LongLength); + } + } + #endregion #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++) - src[i] = (byte)(src[i] ^ key[i % 4]); + src [i] = (byte) (src [i] ^ key [i % 4]); } #endregion @@ -141,7 +133,7 @@ namespace WebSocketSharp { #region Public Methods - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator () { foreach (byte b in ExtensionData) yield return b; @@ -150,36 +142,36 @@ namespace WebSocketSharp { yield return b; } - public void Mask(byte[] maskingKey) + public void Mask (byte [] maskingKey) { if (ExtensionData.LongLength > 0) - mask(ExtensionData, maskingKey); + mask (ExtensionData, maskingKey); if (ApplicationData.LongLength > 0) - mask(ApplicationData, maskingKey); + mask (ApplicationData, maskingKey); IsMasked = !IsMasked; } - public byte[] ToByteArray() + public byte [] ToByteArray () { return ExtensionData.LongLength > 0 - ? this.ToArray() + ? this.ToArray () : ApplicationData; } - public override string ToString() + public override string ToString () { - return BitConverter.ToString(ToByteArray()); + return BitConverter.ToString (ToByteArray ()); } #endregion #region Explicitly Implemented Interface Members - IEnumerator IEnumerable.GetEnumerator() + IEnumerator IEnumerable.GetEnumerator () { - return GetEnumerator(); + return GetEnumerator (); } #endregion diff --git a/websocket-sharp/Server/HttpServer.cs b/websocket-sharp/Server/HttpServer.cs index 69d9fbc2..8a747b37 100644 --- a/websocket-sharp/Server/HttpServer.cs +++ b/websocket-sharp/Server/HttpServer.cs @@ -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; diff --git a/websocket-sharp/Server/WebSocketServer.cs b/websocket-sharp/Server/WebSocketServer.cs index e024e12f..10f94763 100644 --- a/websocket-sharp/Server/WebSocketServer.cs +++ b/websocket-sharp/Server/WebSocketServer.cs @@ -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; } diff --git a/websocket-sharp/Server/WebSocketServiceHost.cs b/websocket-sharp/Server/WebSocketServiceHost.cs index 1a6fb525..b0d1d3eb 100644 --- a/websocket-sharp/Server/WebSocketServiceHost.cs +++ b/websocket-sharp/Server/WebSocketServiceHost.cs @@ -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; } diff --git a/websocket-sharp/Server/WebSocketServiceHostManager.cs b/websocket-sharp/Server/WebSocketServiceHostManager.cs index e6c76357..110b3970 100644 --- a/websocket-sharp/Server/WebSocketServiceHostManager.cs +++ b/websocket-sharp/Server/WebSocketServiceHostManager.cs @@ -195,7 +195,7 @@ namespace WebSocketSharp.Server #region Private Methods - private Dictionary> broadping (byte [] data) + private Dictionary> broadping (byte [] frameAsBytes, int timeOut) { var result = new Dictionary> (); 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); } /// @@ -459,7 +454,7 @@ namespace WebSocketSharp.Server return null; } - return broadping (data); + return broadping (WsFrame.CreatePingFrame (Mask.UNMASK, data).ToByteArray (), 1000); } /// @@ -489,7 +484,7 @@ namespace WebSocketSharp.Server return null; } - return host.Sessions.BroadpingInternally (new byte [] {}); + return host.Sessions.BroadpingInternally (); } /// @@ -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); } /// diff --git a/websocket-sharp/Server/WebSocketSessionManager.cs b/websocket-sharp/Server/WebSocketSessionManager.cs index de9c1ce3..437e2bf1 100644 --- a/websocket-sharp/Server/WebSocketSessionManager.cs +++ b/websocket-sharp/Server/WebSocketSessionManager.cs @@ -106,7 +106,7 @@ namespace WebSocketSharp.Server /// public IEnumerable 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 /// public IEnumerable 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 BroadpingInternally (byte [] data) + internal Dictionary BroadpingInternally () + { + return BroadpingInternally (WsFrame.CreatePingFrame (Mask.UNMASK).ToByteArray (), 1000); + } + + internal Dictionary BroadpingInternally (byte [] frameAsBytes, int timeOut) { var result = new Dictionary (); 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,21 +315,18 @@ namespace WebSocketSharp.Server _state = ServerState.START; } - 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; - _sweepTimer.Enabled = false; - foreach (var session in _sessions.Values.ToList ()) - session.Context.WebSocket.Close (); - - _state = ServerState.STOP; - } + Stop (args, frameAsBytes); } - internal void Stop (byte [] data) + internal void Stop (CloseEventArgs args, byte [] frameAsBytes) { lock (_sync) { @@ -332,7 +334,7 @@ namespace WebSocketSharp.Server _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 (); } /// @@ -428,7 +430,7 @@ namespace WebSocketSharp.Server return null; } - return BroadpingInternally (data); + return BroadpingInternally (WsFrame.CreatePingFrame (Mask.UNMASK, data).ToByteArray (), 1000); } /// diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs index dff82f82..e84533c3 100644 --- a/websocket-sharp/WebSocket.cs +++ b/websocket-sharp/WebSocket.cs @@ -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 /// 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 { - } - - _readyState = WebSocketState.CLOSED; + close (new PayloadData (((ushort) code).Append (reason)), !code.IsReserved (), wait); } - 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,60 +541,53 @@ 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 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 () - { - if (_stream != null) - { - _stream.Dispose (); - _stream = null; - } - - if (_tcpClient != null) - { - _tcpClient.Close (); - _tcpClient = null; - } - } - - private bool closeResources () + private bool closeClientResources () { try { - if (_client) - closeClientResources (); - else - closeServerResources (); + if (_stream != null) + { + _stream.Dispose (); + _stream = null; + } + + if (_tcpClient != null) + { + _tcpClient.Close (); + _tcpClient = null; + } return true; } @@ -621,13 +600,23 @@ namespace WebSocketSharp } // As server - private void closeServerResources () + private bool closeServerResources () { - if (_closeContext != null) - _closeContext (); + try { + if (_closeContext != null) + _closeContext (); - _stream = null; - _context = null; + _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,23 +1012,16 @@ namespace WebSocketSharp private bool send (WsFrame frame) { - lock (_forFrame) + if (_readyState != WebSocketState.OPEN) { - var ready = _stream != null && - (_readyState == WebSocketState.OPEN || - (_readyState == WebSocketState.CLOSING && frame.IsClose)); + var msg = "A WebSocket connection isn't established or has been closed."; + _logger.Error (msg); + error (msg); - if (!ready) - { - var msg = "A WebSocket connection isn't established or has been closed."; - _logger.Error (msg); - error (msg); - - return false; - } - - return _stream.WriteFrame (frame); + return false; } + + 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 /// public void Close () { - close (new PayloadData (), false); + close (new PayloadData (), _readyState == WebSocketState.OPEN, true); } /// @@ -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); } /// @@ -1332,7 +1321,8 @@ namespace WebSocketSharp /// 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); } /// @@ -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); } /// @@ -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); } /// @@ -1417,7 +1409,10 @@ namespace WebSocketSharp catch (Exception ex) { _logger.Fatal (ex.ToString ()); error ("An exception has occured."); - Close (CloseStatusCode.ABNORMAL); + if (_client) + Close (CloseStatusCode.ABNORMAL); + else + Close (HttpStatusCode.BadRequest); } } @@ -1441,7 +1436,9 @@ namespace WebSocketSharp /// public bool Ping () { - return Ping (new byte [] {}); + return _client + ? Ping (WsFrame.CreatePingFrame (Mask.MASK).ToByteArray (), 5000) + : Ping (WsFrame.CreatePingFrame (Mask.UNMASK).ToByteArray (), 1000); } /// @@ -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); } /// diff --git a/websocket-sharp/WsFrame.cs b/websocket-sharp/WsFrame.cs index 350fc631..8d9e937f 100644 --- a/websocket-sharp/WsFrame.cs +++ b/websocket-sharp/WsFrame.cs @@ -32,13 +32,13 @@ using System.Collections; using System.Collections.Generic; using System.Text; -namespace WebSocketSharp { - +namespace WebSocketSharp +{ internal class WsFrame : IEnumerable { #region Private Constructors - private WsFrame() + private WsFrame () { } @@ -46,26 +46,26 @@ 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) + public WsFrame ( + Fin fin, Opcode opcode, Mask mask, PayloadData payload, bool compressed) { Fin = fin; - Rsv1 = isData(opcode) && compressed ? Rsv.ON : Rsv.OFF; + Rsv1 = isData (opcode) && compressed ? Rsv.ON : Rsv.OFF; Rsv2 = Rsv.OFF; Rsv3 = Rsv.OFF; Opcode = opcode; @@ -73,38 +73,38 @@ namespace WebSocketSharp { /* PayloadLen */ - ulong dataLen = payloadData.Length; + var dataLen = payload.Length; var payloadLen = dataLen < 126 - ? (byte)dataLen + ? (byte) dataLen : dataLen < 0x010000 - ? (byte)126 - : (byte)127; + ? (byte) 126 + : (byte) 127; PayloadLen = payloadLen; /* ExtPayloadLen */ ExtPayloadLen = payloadLen < 126 - ? new byte[]{} + ? new byte []{} : payloadLen == 126 - ? ((ushort)dataLen).ToByteArray(ByteOrder.BIG) - : dataLen.ToByteArray(ByteOrder.BIG); + ? ((ushort) dataLen).ToByteArray (ByteOrder.BIG) + : dataLen.ToByteArray (ByteOrder.BIG); /* MaskingKey */ var masking = mask == Mask.MASK; var maskingKey = masking - ? createMaskingKey() - : new byte[]{}; + ? createMaskingKey () + : new byte []{}; MaskingKey = maskingKey; /* PayloadData */ if (masking) - payloadData.Mask(maskingKey); + payload.Mask (maskingKey); - PayloadData = payloadData; + PayloadData = payload; } #endregion @@ -194,7 +194,7 @@ namespace WebSocketSharp { internal ulong Length { 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[] 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; } @@ -226,26 +226,20 @@ namespace WebSocketSharp { #region Private Methods - private static WsFrame createCloseFrame(CloseStatusCode code, string reason, Mask mask) + private static byte [] createMaskingKey () { - 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]; - var rand = new Random(); - rand.NextBytes(key); + var key = new byte [4]; + var rand = new Random (); + rand.NextBytes (key); return key; } - private static void dump(WsFrame frame) + private static void dump (WsFrame frame) { var len = frame.Length; - var count = (long)(len / 4); - var remainder = (int)(len % 4); + var count = (long) (len / 4); + var remainder = (int) (len % 4); int countDigit; string countFmt; @@ -270,120 +264,121 @@ namespace WebSocketSharp { countFmt = "{0,16:X}"; } - var spFmt = String.Format("{{0,{0}}}", countDigit); - var headerFmt = String.Format(@" + var spFmt = String.Format ("{{0,{0}}}", countDigit); + var headerFmt = String.Format (@" {0} 01234567 89ABCDEF 01234567 89ABCDEF {0}+--------+--------+--------+--------+", spFmt); - var footerFmt = String.Format(" {0}+--------+--------+--------+--------+", spFmt); + var footerFmt = String.Format (" {0}+--------+--------+--------+--------+", spFmt); Func> linePrinter = () => { 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) => { - 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; for (i = 0; i <= count; i++) { j = i * 4; if (i < count) - printLine( - Convert.ToString(buffer[j], 2).PadLeft(8, '0'), - Convert.ToString(buffer[j + 1], 2).PadLeft(8, '0'), - Convert.ToString(buffer[j + 2], 2).PadLeft(8, '0'), - Convert.ToString(buffer[j + 3], 2).PadLeft(8, '0')); + printLine ( + Convert.ToString (buffer [j], 2).PadLeft (8, '0'), + Convert.ToString (buffer [j + 1], 2).PadLeft (8, '0'), + Convert.ToString (buffer [j + 2], 2).PadLeft (8, '0'), + Convert.ToString (buffer [j + 3], 2).PadLeft (8, '0')); else if (remainder > 0) - printLine( - Convert.ToString(buffer[j], 2).PadLeft(8, '0'), - remainder >= 2 ? Convert.ToString(buffer[j + 1], 2).PadLeft(8, '0') : String.Empty, - remainder == 3 ? Convert.ToString(buffer[j + 2], 2).PadLeft(8, '0') : String.Empty, + printLine ( + Convert.ToString (buffer [j], 2).PadLeft (8, '0'), + remainder >= 2 ? Convert.ToString (buffer [j + 1], 2).PadLeft (8, '0') : String.Empty, + remainder == 3 ? Convert.ToString (buffer [j + 2], 2).PadLeft (8, '0') : String.Empty, 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; } - private static bool isClose(Opcode opcode) + private static bool isClose (Opcode opcode) { return opcode == Opcode.CLOSE; } - private static bool isContinuation(Opcode opcode) + private static bool isContinuation (Opcode opcode) { 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; } - private static bool isData(Opcode opcode) + private static bool isData (Opcode opcode) { return opcode == Opcode.TEXT || opcode == Opcode.BINARY; } - private static bool isFinal(Fin fin) + private static bool isFinal (Fin fin) { return fin == Fin.FINAL; } - private static bool isMasked(Mask mask) + private static bool isMasked (Mask mask) { return mask == Mask.MASK; } - private static bool isPing(Opcode opcode) + private static bool isPing (Opcode opcode) { return opcode == Opcode.PING; } - private static bool isPong(Opcode opcode) + private static bool isPong (Opcode opcode) { return opcode == Opcode.PONG; } - private static bool isText(Opcode opcode) + private static bool isText (Opcode opcode) { 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 */ // FIN - var fin = (header[0] & 0x80) == 0x80 ? Fin.FINAL : Fin.MORE; + var fin = (header [0] & 0x80) == 0x80 ? Fin.FINAL : Fin.MORE; // RSV1 - var rsv1 = (header[0] & 0x40) == 0x40 ? Rsv.ON : Rsv.OFF; + var rsv1 = (header [0] & 0x40) == 0x40 ? Rsv.ON : Rsv.OFF; // RSV2 - var rsv2 = (header[0] & 0x20) == 0x20 ? Rsv.ON : Rsv.OFF; + var rsv2 = (header [0] & 0x20) == 0x20 ? Rsv.ON : Rsv.OFF; // RSV3 - var rsv3 = (header[0] & 0x10) == 0x10 ? Rsv.ON : Rsv.OFF; + var rsv3 = (header [0] & 0x10) == 0x10 ? Rsv.ON : Rsv.OFF; // Opcode - var opcode = (Opcode)(header[0] & 0x0f); + var opcode = (Opcode) (header [0] & 0x0f); // MASK - var mask = (header[1] & 0x80) == 0x80 ? Mask.MASK : Mask.UNMASK; + var mask = (header [1] & 0x80) == 0x80 ? Mask.MASK : Mask.UNMASK; // Payload len - var payloadLen = (byte)(header[1] & 0x7f); + 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); + if (isControl (opcode) && payloadLen > 125) + return CreateCloseFrame ( + Mask.UNMASK, + CloseStatusCode.INCONSISTENT_DATA, + "The payload length of a control frame must be 125 bytes or less."); var frame = new WsFrame { Fin = fin, @@ -404,27 +399,29 @@ namespace WebSocketSharp { : 8; var extPayloadLen = extLen > 0 - ? stream.ReadBytesInternal(extLen) - : new byte[]{}; + ? stream.ReadBytesInternal (extLen) + : 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[]{}; + ? 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; @@ -433,64 +430,65 @@ namespace WebSocketSharp { ulong dataLen = payloadLen < 126 ? payloadLen : payloadLen == 126 - ? extPayloadLen.To(ByteOrder.BIG) - : extPayloadLen.To(ByteOrder.BIG); + ? extPayloadLen.To (ByteOrder.BIG) + : extPayloadLen.To (ByteOrder.BIG); - byte[] data = null; + byte [] data = null; if (dataLen > 0) { 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 - ? stream.ReadBytesInternal((long)dataLen, 1024) - : stream.ReadBytesInternal((int)dataLen); + ? stream.ReadBytesInternal ((long) dataLen, 1024) + : 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); + if (data.LongLength != (long) dataLen) + return CreateCloseFrame ( + Mask.UNMASK, + CloseStatusCode.ABNORMAL, + "'Payload Data' of a frame cannot be read from the data stream."); } else { - data = new byte[]{}; + 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.MaskingKey = new byte []{}; } - frame.PayloadData = payloadData; + frame.PayloadData = payload; return frame; } - private static void print(WsFrame frame) + private static void print (WsFrame frame) { var len = frame.ExtPayloadLen.Length; var extPayloadLen = len == 2 - ? frame.ExtPayloadLen.To(ByteOrder.BIG).ToString() + ? frame.ExtPayloadLen.To (ByteOrder.BIG).ToString () : len == 8 - ? frame.ExtPayloadLen.To(ByteOrder.BIG).ToString() + ? frame.ExtPayloadLen.To (ByteOrder.BIG).ToString () : String.Empty; var masked = frame.IsMasked; var maskingKey = masked - ? BitConverter.ToString(frame.MaskingKey) + ? BitConverter.ToString (frame.MaskingKey) : String.Empty; var opcode = frame.Opcode; var payloadData = frame.PayloadData.Length == 0 ? String.Empty : masked || frame.IsFragmented || frame.IsBinary || frame.IsClose - ? BitConverter.ToString(frame.PayloadData.ToByteArray()) - : Encoding.UTF8.GetString(frame.PayloadData.ToByteArray()); + ? BitConverter.ToString (frame.PayloadData.ToByteArray ()) + : Encoding.UTF8.GetString (frame.PayloadData.ToByteArray ()); var format = @" FIN: {0} @@ -504,168 +502,210 @@ namespace WebSocketSharp { Masking Key: {8} Payload Data: {9}"; - Console.WriteLine( + Console.WriteLine ( format, frame.Fin, frame.Rsv1, frame.Rsv2, frame.Rsv3, opcode, frame.Mask, frame.PayloadLen, extPayloadLen, maskingKey, payloadData); } #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 IEnumerator 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 GetEnumerator () + { + foreach (byte b in ToByteArray ()) 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 error) + public static WsFrame Parse (Stream stream, bool unmask, Action error) { WsFrame frame = null; try { - var header = stream.ReadBytesInternal(2); + 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); + ? parse (header, stream, unmask) + : CreateCloseFrame ( + Mask.UNMASK, + CloseStatusCode.ABNORMAL, + "'Header' of a frame cannot be read from the data stream."); } catch (Exception ex) { if (error != null) - error(ex); + error (ex); } return frame; } - public static void ParseAsync(Stream stream, Action completed) + public static void ParseAsync (Stream stream, Action completed) { - ParseAsync(stream, true, completed, null); + ParseAsync (stream, true, completed, null); } - public static void ParseAsync(Stream stream, Action completed, Action error) + public static void ParseAsync (Stream stream, Action completed, Action error) { - ParseAsync(stream, true, completed, error); + ParseAsync (stream, true, completed, error); } - public static void ParseAsync( + public static void ParseAsync ( Stream stream, bool unmask, Action completed, Action error) { - var header = new byte[2]; + var header = new byte [2]; AsyncCallback callback = ar => { WsFrame frame = null; try { - var readLen = stream.EndRead(ar); + var readLen = stream.EndRead (ar); if (readLen == 1) { - var tmp = stream.ReadByte(); + var tmp = stream.ReadByte (); if (tmp > -1) { - header[1] = (byte)tmp; + header [1] = (byte) tmp; readLen++; } } frame = readLen == 2 - ? parse(header, stream, unmask) - : createCloseFrame(CloseStatusCode.ABNORMAL, - "'Header' of a frame cannot be read from the data stream.", - Mask.UNMASK); + ? parse (header, stream, unmask) + : CreateCloseFrame ( + Mask.UNMASK, + CloseStatusCode.ABNORMAL, + "'Header' of a frame cannot be read from the data stream."); } catch (Exception ex) { if (error != null) - error(ex); + error (ex); } finally { 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) - dump(this); + dump (this); 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; - header = (header << 1) + (int)Rsv1; - header = (header << 1) + (int)Rsv2; - header = (header << 1) + (int)Rsv3; - header = (header << 4) + (int)Opcode; - header = (header << 1) + (int)Mask; - header = (header << 7) + (int)PayloadLen; - buffer.Write(((ushort)header).ToByteArray(ByteOrder.BIG), 0, 2); + int header = (int) Fin; + header = (header << 1) + (int) Rsv1; + header = (header << 1) + (int) Rsv2; + header = (header << 1) + (int) Rsv3; + header = (header << 4) + (int) Opcode; + header = (header << 1) + (int) Mask; + header = (header << 7) + (int) PayloadLen; + buffer.Write (((ushort) header).ToByteArray (ByteOrder.BIG), 0, 2); if (PayloadLen > 125) - buffer.Write(ExtPayloadLen, 0, ExtPayloadLen.Length); + buffer.Write (ExtPayloadLen, 0, ExtPayloadLen.Length); if (Mask == Mask.MASK) - buffer.Write(MaskingKey, 0, MaskingKey.Length); + buffer.Write (MaskingKey, 0, MaskingKey.Length); if (PayloadLen > 0) { - var payload = PayloadData.ToByteArray(); + var payload = PayloadData.ToByteArray (); if (PayloadLen < 127) - buffer.Write(payload, 0, payload.Length); + buffer.Write (payload, 0, payload.Length); else - buffer.WriteBytes(payload); + buffer.WriteBytes (payload); } - buffer.Close(); - return buffer.ToArray(); + buffer.Close (); + return buffer.ToArray (); } } - public override string ToString() + public override string ToString () { - return BitConverter.ToString(ToByteArray()); + return BitConverter.ToString (ToByteArray ()); } #endregion #region Explicitly Implemented Interface Members - IEnumerator IEnumerable.GetEnumerator() + IEnumerator IEnumerable.GetEnumerator () { - return GetEnumerator(); + return GetEnumerator (); } #endregion diff --git a/websocket-sharp/WsStream.cs b/websocket-sharp/WsStream.cs index c2fdde4c..091972c7 100644 --- a/websocket-sharp/WsStream.cs +++ b/websocket-sharp/WsStream.cs @@ -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