Modified closing
This commit is contained in:
		| @@ -180,12 +180,10 @@ namespace WebSocketSharp | |||||||
|  |  | ||||||
|     internal static byte [] Append (this ushort code, string reason) |     internal static byte [] Append (this ushort code, string reason) | ||||||
|     { |     { | ||||||
|       using (var buffer = new MemoryStream ()) |       using (var buffer = new MemoryStream ()) { | ||||||
|       { |  | ||||||
|         var tmp = code.ToByteArrayInternally (ByteOrder.BIG); |         var tmp = code.ToByteArrayInternally (ByteOrder.BIG); | ||||||
|         buffer.Write (tmp, 0, 2); |         buffer.Write (tmp, 0, 2); | ||||||
|         if (reason != null && reason.Length > 0) |         if (reason != null && reason.Length > 0) { | ||||||
|         { |  | ||||||
|           tmp = Encoding.UTF8.GetBytes (reason); |           tmp = Encoding.UTF8.GetBytes (reason); | ||||||
|           buffer.Write (tmp, 0, tmp.Length); |           buffer.Write (tmp, 0, tmp.Length); | ||||||
|         } |         } | ||||||
| @@ -195,6 +193,13 @@ namespace WebSocketSharp | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     internal static string CheckIfCanClose (this WebSocketState state) | ||||||
|  |     { | ||||||
|  |       return state == WebSocketState.CLOSING || state == WebSocketState.CLOSED | ||||||
|  |              ? "While closing the WebSocket connection, or already closed." | ||||||
|  |              : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     internal static string CheckIfCanRead (this Stream stream) |     internal static string CheckIfCanRead (this Stream stream) | ||||||
|     { |     { | ||||||
|       return stream == null |       return stream == null | ||||||
| @@ -1149,8 +1154,8 @@ namespace WebSocketSharp | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Determines whether the specified <see cref="ushort"/> is in the allowable range of |     /// Determines whether the specified <see cref="ushort"/> is in the allowable | ||||||
|     /// the WebSocket close status code. |     /// range of the WebSocket close status code. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     /// <remarks> |     /// <remarks> | ||||||
|     /// Not allowable ranges are the followings. |     /// Not allowable ranges are the followings. | ||||||
| @@ -1162,14 +1167,15 @@ namespace WebSocketSharp | |||||||
|     ///     </item> |     ///     </item> | ||||||
|     ///     <item> |     ///     <item> | ||||||
|     ///       <term> |     ///       <term> | ||||||
|     ///       Numbers which are greater than 4999 are out of the reserved close status code ranges. |     ///       Numbers which are greater than 4999 are out of the reserved close | ||||||
|  |     ///       status code ranges. | ||||||
|     ///       </term> |     ///       </term> | ||||||
|     ///     </item> |     ///     </item> | ||||||
|     ///   </list> |     ///   </list> | ||||||
|     /// </remarks> |     /// </remarks> | ||||||
|     /// <returns> |     /// <returns> | ||||||
|     /// <c>true</c> if <paramref name="value"/> is in the allowable range of the WebSocket close status code; |     /// <c>true</c> if <paramref name="value"/> is in the allowable range of the | ||||||
|     /// otherwise, <c>false</c>. |     /// WebSocket close status code; otherwise, <c>false</c>. | ||||||
|     /// </returns> |     /// </returns> | ||||||
|     /// <param name="value"> |     /// <param name="value"> | ||||||
|     /// A <see cref="ushort"/> to test. |     /// A <see cref="ushort"/> to test. | ||||||
|   | |||||||
| @@ -557,34 +557,49 @@ namespace WebSocketSharp | |||||||
|  |  | ||||||
|     private void close (CloseStatusCode code, string reason, bool wait) |     private void close (CloseStatusCode code, string reason, bool wait) | ||||||
|     { |     { | ||||||
|       close (new PayloadData (((ushort) code).Append (reason)), !code.IsReserved (), wait); |       close ( | ||||||
|  |         new PayloadData (((ushort) code).Append (reason)), | ||||||
|  |         !code.IsReserved (), | ||||||
|  |         wait); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void close (PayloadData payload, bool send, bool wait) |     private void close (PayloadData payload, bool send, bool wait) | ||||||
|     { |     { | ||||||
|       lock (_forClose) |       lock (_forClose) { | ||||||
|       { |         var msg = _readyState.CheckIfCanClose (); | ||||||
|         if (_readyState == WebSocketState.CLOSING || _readyState == WebSocketState.CLOSED) |         if (msg != null) { | ||||||
|  |           _logger.Info (String.Format ("{0}\nstate: {1}", msg, _readyState)); | ||||||
|  |  | ||||||
|           return; |           return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         _readyState = WebSocketState.CLOSING; |         _readyState = WebSocketState.CLOSING; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       _logger.Trace ("Start closing handshake."); |       _logger.Trace ("Start closing handshake."); | ||||||
|  |  | ||||||
|  |       try { | ||||||
|         var args = new CloseEventArgs (payload); |         var args = new CloseEventArgs (payload); | ||||||
|       args.WasClean = _client |         args.WasClean = | ||||||
|  |           _client | ||||||
|           ? close ( |           ? close ( | ||||||
|                         send ? WsFrame.CreateCloseFrame (Mask.MASK, payload).ToByteArray () : null, |               send ? WsFrame.CreateCloseFrame (Mask.MASK, payload).ToByteArray () | ||||||
|  |                    : null, | ||||||
|               wait ? 5000 : 0, |               wait ? 5000 : 0, | ||||||
|               closeClientResources) |               closeClientResources) | ||||||
|           : close ( |           : close ( | ||||||
|                         send ? WsFrame.CreateCloseFrame (Mask.UNMASK, payload).ToByteArray () : null, |               send ? WsFrame.CreateCloseFrame (Mask.UNMASK, payload).ToByteArray () | ||||||
|  |                    : null, | ||||||
|               wait ? 1000 : 0, |               wait ? 1000 : 0, | ||||||
|               closeServerResources); |               closeServerResources); | ||||||
|  |  | ||||||
|         _readyState = WebSocketState.CLOSED; |         _readyState = WebSocketState.CLOSED; | ||||||
|         OnClose.Emit (this, args); |         OnClose.Emit (this, args); | ||||||
|  |       } | ||||||
|  |       catch (Exception ex) { | ||||||
|  |         _logger.Fatal (ex.ToString ()); | ||||||
|  |         error ("An exception has occurred while closing."); | ||||||
|  |       } | ||||||
|  |  | ||||||
|       _logger.Trace ("End closing handshake."); |       _logger.Trace ("End closing handshake."); | ||||||
|     } |     } | ||||||
| @@ -592,11 +607,17 @@ namespace WebSocketSharp | |||||||
|     private bool close (byte [] frameAsBytes, int timeOut, Func<bool> release) |     private bool close (byte [] frameAsBytes, int timeOut, Func<bool> release) | ||||||
|     { |     { | ||||||
|       var sent = frameAsBytes != null && _stream.Write (frameAsBytes); |       var sent = frameAsBytes != null && _stream.Write (frameAsBytes); | ||||||
|       var received = timeOut == 0 || (sent && _exitReceiving.WaitOne (timeOut)); |       var received = timeOut == 0 || | ||||||
|  |                      (sent && _exitReceiving != null && _exitReceiving.WaitOne (timeOut)); | ||||||
|       var released = release (); |       var released = release (); | ||||||
|       var result = sent && received && released; |       var result = sent && received && released; | ||||||
|       _logger.Debug (String.Format ( |       _logger.Debug ( | ||||||
|         "Was clean?: {0}\nsent: {1} received: {2} released: {3}", result, sent, received, released)); |         String.Format ( | ||||||
|  |           "Was clean?: {0}\nsent: {1} received: {2} released: {3}", | ||||||
|  |           result, | ||||||
|  |           sent, | ||||||
|  |           received, | ||||||
|  |           released)); | ||||||
|  |  | ||||||
|       return result; |       return result; | ||||||
|     } |     } | ||||||
| @@ -605,14 +626,12 @@ namespace WebSocketSharp | |||||||
|     private bool closeClientResources () |     private bool closeClientResources () | ||||||
|     { |     { | ||||||
|       try { |       try { | ||||||
|         if (_stream != null) |         if (_stream != null) { | ||||||
|         { |  | ||||||
|           _stream.Dispose (); |           _stream.Dispose (); | ||||||
|           _stream = null; |           _stream = null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (_tcpClient != null) |         if (_tcpClient != null) { | ||||||
|         { |  | ||||||
|           _tcpClient.Close (); |           _tcpClient.Close (); | ||||||
|           _tcpClient = null; |           _tcpClient = null; | ||||||
|         } |         } | ||||||
| @@ -621,11 +640,11 @@ namespace WebSocketSharp | |||||||
|       } |       } | ||||||
|       catch (Exception ex) { |       catch (Exception ex) { | ||||||
|         _logger.Fatal (ex.ToString ()); |         _logger.Fatal (ex.ToString ()); | ||||||
|         error ("An exception has occurred."); |         error ("An exception has occurred while releasing resources."); | ||||||
|  |       } | ||||||
|  |  | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // As server |     // As server | ||||||
|     private bool closeServerResources () |     private bool closeServerResources () | ||||||
| @@ -641,11 +660,11 @@ namespace WebSocketSharp | |||||||
|       } |       } | ||||||
|       catch (Exception ex) { |       catch (Exception ex) { | ||||||
|         _logger.Fatal (ex.ToString ()); |         _logger.Fatal (ex.ToString ()); | ||||||
|         error ("An exception has occurred."); |         error ("An exception has occurred while releasing resources."); | ||||||
|  |       } | ||||||
|  |  | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private bool concatenateFragmentsInto (Stream dest) |     private bool concatenateFragmentsInto (Stream dest) | ||||||
|     { |     { | ||||||
| @@ -886,21 +905,18 @@ namespace WebSocketSharp | |||||||
|     { |     { | ||||||
|       var code = CloseStatusCode.ABNORMAL; |       var code = CloseStatusCode.ABNORMAL; | ||||||
|       var msg = reason; |       var msg = reason; | ||||||
|       if (exception.GetType () == typeof (WebSocketException)) |       if (exception is WebSocketException) { | ||||||
|       { |  | ||||||
|         var wsex = (WebSocketException) exception; |         var wsex = (WebSocketException) exception; | ||||||
|         code = wsex.Code; |         code = wsex.Code; | ||||||
|         reason = wsex.Message; |         reason = wsex.Message; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       if (code == CloseStatusCode.ABNORMAL || |       if (code == CloseStatusCode.ABNORMAL || | ||||||
|           code == CloseStatusCode.TLS_HANDSHAKE_FAILURE) |           code == CloseStatusCode.TLS_HANDSHAKE_FAILURE) { | ||||||
|       { |  | ||||||
|         _logger.Fatal (exception.ToString ()); |         _logger.Fatal (exception.ToString ()); | ||||||
|         reason = msg; |         reason = msg; | ||||||
|       } |       } | ||||||
|       else |       else { | ||||||
|       { |  | ||||||
|         _logger.Error (reason); |         _logger.Error (reason); | ||||||
|         msg = null; |         msg = null; | ||||||
|       } |       } | ||||||
| @@ -1365,22 +1381,29 @@ namespace WebSocketSharp | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // As server |     // As server | ||||||
|     internal void Close (CloseEventArgs args, byte [] frameAsBytes, int waitTimeOut) |     internal void Close ( | ||||||
|  |       CloseEventArgs args, byte [] frameAsBytes, int waitTimeOut) | ||||||
|     { |     { | ||||||
|       lock (_forClose) |       lock (_forClose) { | ||||||
|       { |         var msg = _readyState.CheckIfCanClose (); | ||||||
|         if (_readyState == WebSocketState.CLOSING || _readyState == WebSocketState.CLOSED) |         if (msg != null) { | ||||||
|  |           _logger.Info (String.Format ("{0}\nstate: {1}", msg, _readyState)); | ||||||
|  |  | ||||||
|           return; |           return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         _readyState = WebSocketState.CLOSING; |         _readyState = WebSocketState.CLOSING; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       try { | ||||||
|         args.WasClean = close (frameAsBytes, waitTimeOut, closeServerResources); |         args.WasClean = close (frameAsBytes, waitTimeOut, closeServerResources); | ||||||
|  |  | ||||||
|         _readyState = WebSocketState.CLOSED; |         _readyState = WebSocketState.CLOSED; | ||||||
|  |  | ||||||
|         OnClose.Emit (this, args); |         OnClose.Emit (this, args); | ||||||
|       } |       } | ||||||
|  |       catch (Exception ex) { | ||||||
|  |         _logger.Fatal (ex.ToString ()); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // As server |     // As server | ||||||
|     internal void ConnectAsServer () |     internal void ConnectAsServer () | ||||||
| @@ -1480,11 +1503,20 @@ namespace WebSocketSharp | |||||||
|     #region Public Methods |     #region Public Methods | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Closes the WebSocket connection and releases all associated resources. |     /// Closes the WebSocket connection, and releases all associated resources. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public void Close () |     public void Close () | ||||||
|     { |     { | ||||||
|       close (new PayloadData (), _readyState == WebSocketState.OPEN, true); |       var msg = _readyState.CheckIfCanClose (); | ||||||
|  |       if (msg != null) { | ||||||
|  |         _logger.Error (String.Format ("{0}\nstate: {1}", msg, _readyState)); | ||||||
|  |         error (msg); | ||||||
|  |  | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       var send = _readyState == WebSocketState.OPEN; | ||||||
|  |       close (new PayloadData (), send, send); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
| @@ -1492,25 +1524,15 @@ namespace WebSocketSharp | |||||||
|     /// and releases all associated resources. |     /// and releases all associated resources. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     /// <remarks> |     /// <remarks> | ||||||
|     /// This method emits a <see cref="OnError"/> event if <paramref name="code"/> is not |     /// This method emits a <see cref="OnError"/> event if <paramref name="code"/> | ||||||
|     /// in the allowable range of the WebSocket close status code. |     /// isn't in the allowable range of the WebSocket close status code. | ||||||
|     /// </remarks> |     /// </remarks> | ||||||
|     /// <param name="code"> |     /// <param name="code"> | ||||||
|     /// A <see cref="ushort"/> that indicates the status code for closure. |     /// A <see cref="ushort"/> that indicates the status code for closure. | ||||||
|     /// </param> |     /// </param> | ||||||
|     public void Close (ushort code) |     public void Close (ushort code) | ||||||
|     { |     { | ||||||
|       var msg = code.CheckIfValidCloseStatusCode (); |       Close (code, null); | ||||||
|       if (msg != null) |  | ||||||
|       { |  | ||||||
|         _logger.Error (String.Format ("{0}\ncode: {1}", msg, code)); |  | ||||||
|         error (msg); |  | ||||||
|  |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       var send = _readyState == WebSocketState.OPEN && !code.IsReserved (); |  | ||||||
|       close (new PayloadData (code.ToByteArrayInternally (ByteOrder.BIG)), send, true); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
| @@ -1518,75 +1540,81 @@ namespace WebSocketSharp | |||||||
|     /// and releases all associated resources. |     /// and releases all associated resources. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     /// <param name="code"> |     /// <param name="code"> | ||||||
|     /// One of the <see cref="CloseStatusCode"/> values that indicate the status codes for closure. |     /// One of the <see cref="CloseStatusCode"/> values that indicate the status | ||||||
|  |     /// codes for closure. | ||||||
|     /// </param> |     /// </param> | ||||||
|     public void Close (CloseStatusCode code) |     public void Close (CloseStatusCode code) | ||||||
|     { |     { | ||||||
|       var send = _readyState == WebSocketState.OPEN && !code.IsReserved (); |       Close (code, null); | ||||||
|       close (new PayloadData (((ushort) code).ToByteArrayInternally (ByteOrder.BIG)), send, true); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Closes the WebSocket connection with the specified <see cref="ushort"/> and <see cref="string"/>, |     /// Closes the WebSocket connection with the specified <see cref="ushort"/> | ||||||
|     /// and releases all associated resources. |     /// and <see cref="string"/>, and releases all associated resources. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     /// <remarks> |     /// <remarks> | ||||||
|     /// This method emits a <see cref="OnError"/> event if <paramref name="code"/> is not |     /// This method emits a <see cref="OnError"/> event if <paramref name="code"/> | ||||||
|     /// in the allowable range of the WebSocket close status code |     /// isn't in the allowable range of the WebSocket close status code or the | ||||||
|     /// or the length of <paramref name="reason"/> is greater than 123 bytes. |     /// length of <paramref name="reason"/> is greater than 123 bytes. | ||||||
|     /// </remarks> |     /// </remarks> | ||||||
|     /// <param name="code"> |     /// <param name="code"> | ||||||
|     /// A <see cref="ushort"/> that indicates the status code for closure. |     /// A <see cref="ushort"/> that indicates the status code for closure. | ||||||
|     /// </param> |     /// </param> | ||||||
|     /// <param name="reason"> |     /// <param name="reason"> | ||||||
|     /// A <see cref="string"/> that contains the reason for closure. |     /// A <see cref="string"/> that represents the reason for closure. | ||||||
|     /// </param> |     /// </param> | ||||||
|     public void Close (ushort code, string reason) |     public void Close (ushort code, string reason) | ||||||
|     { |     { | ||||||
|       byte [] data = null; |       byte [] data = null; | ||||||
|       var msg = code.CheckIfValidCloseStatusCode () ?? |       var msg = _readyState.CheckIfCanClose () ?? | ||||||
|  |                 code.CheckIfValidCloseStatusCode () ?? | ||||||
|                 (data = code.Append (reason)).CheckIfValidCloseData (); |                 (data = code.Append (reason)).CheckIfValidCloseData (); | ||||||
|  |  | ||||||
|       if (msg != null) |       if (msg != null) { | ||||||
|       { |         _logger.Error ( | ||||||
|         _logger.Error (String.Format ("{0}\ncode: {1}\nreason: {2}", msg, code, reason)); |           String.Format ( | ||||||
|  |             "{0}\nstate: {1} code: {2} reason: {3}", msg, _readyState, code, reason)); | ||||||
|         error (msg); |         error (msg); | ||||||
|  |  | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       var send = _readyState == WebSocketState.OPEN && !code.IsReserved (); |       var send = _readyState == WebSocketState.OPEN && !code.IsReserved (); | ||||||
|       close (new PayloadData (data), send, true); |       close (new PayloadData (data), send, send); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Closes the WebSocket connection with the specified <see cref="CloseStatusCode"/> and |     /// Closes the WebSocket connection with the specified <see cref="CloseStatusCode"/> | ||||||
|     /// <see cref="string"/>, and releases all associated resources. |     /// and <see cref="string"/>, and releases all associated resources. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     /// <remarks> |     /// <remarks> | ||||||
|     /// This method emits a <see cref="OnError"/> event if the length of <paramref name="reason"/> |     /// This method emits a <see cref="OnError"/> event if the length of | ||||||
|     /// is greater than 123 bytes. |     /// <paramref name="reason"/> is greater than 123 bytes. | ||||||
|     /// </remarks> |     /// </remarks> | ||||||
|     /// <param name="code"> |     /// <param name="code"> | ||||||
|     /// One of the <see cref="CloseStatusCode"/> values that indicate the status codes for closure. |     /// One of the <see cref="CloseStatusCode"/> values that indicate the status | ||||||
|  |     /// codes for closure. | ||||||
|     /// </param> |     /// </param> | ||||||
|     /// <param name="reason"> |     /// <param name="reason"> | ||||||
|     /// A <see cref="string"/> that contains the reason for closure. |     /// A <see cref="string"/> that represents the reason for closure. | ||||||
|     /// </param> |     /// </param> | ||||||
|     public void Close (CloseStatusCode code, string reason) |     public void Close (CloseStatusCode code, string reason) | ||||||
|     { |     { | ||||||
|       var data = ((ushort) code).Append (reason); |       byte [] data = null; | ||||||
|       var msg = data.CheckIfValidCloseData (); |       var msg = _readyState.CheckIfCanClose () ?? | ||||||
|       if (msg != null) |                 (data = ((ushort) code).Append (reason)).CheckIfValidCloseData (); | ||||||
|       { |  | ||||||
|         _logger.Error (String.Format ("{0}\nreason: {1}", msg, reason)); |       if (msg != null) { | ||||||
|  |         _logger.Error ( | ||||||
|  |           String.Format ( | ||||||
|  |             "{0}\nstate: {1} reason: {2}", msg, _readyState, reason)); | ||||||
|         error (msg); |         error (msg); | ||||||
|  |  | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       var send = _readyState == WebSocketState.OPEN && !code.IsReserved (); |       var send = _readyState == WebSocketState.OPEN && !code.IsReserved (); | ||||||
|       close (new PayloadData (data), send, true); |       close (new PayloadData (data), send, send); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
| @@ -1642,14 +1670,15 @@ namespace WebSocketSharp | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Closes the WebSocket connection and releases all associated resources. |     /// Closes the WebSocket connection, and releases all associated resources. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     /// <remarks> |     /// <remarks> | ||||||
|     /// This method closes the WebSocket connection with the <see cref="CloseStatusCode.AWAY"/>. |     /// This method closes the WebSocket connection with the | ||||||
|  |     /// <see cref="CloseStatusCode.AWAY"/>. | ||||||
|     /// </remarks> |     /// </remarks> | ||||||
|     public void Dispose () |     public void Dispose () | ||||||
|     { |     { | ||||||
|       Close (CloseStatusCode.AWAY); |       Close (CloseStatusCode.AWAY, null); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user