Modified closing handshake
This commit is contained in:
parent
4375a5c2a3
commit
68d1a7b9ba
@ -29,15 +29,15 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace WebSocketSharp {
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the event data associated with a <see cref="WebSocket.OnClose"/> event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The <see cref="WebSocket.OnClose"/> event occurs when the WebSocket receives a close control frame or
|
||||
/// the <c>WebSocket.Close</c> method is called. If you want to get the reason for closure, you should access
|
||||
/// the <see cref="CloseEventArgs.Code"/> or <see cref="CloseEventArgs.Reason"/> properties.
|
||||
/// A <see cref="WebSocket.OnClose"/> event occurs when the WebSocket connection has been closed.
|
||||
/// If you want to get the reason for closure, you use the <see cref="CloseEventArgs.Code"/> or
|
||||
/// <see cref="CloseEventArgs.Reason"/> property.
|
||||
/// </remarks>
|
||||
public class CloseEventArgs : MessageEventArgs
|
||||
{
|
||||
@ -51,12 +51,12 @@ namespace WebSocketSharp {
|
||||
|
||||
#region Constructors
|
||||
|
||||
internal CloseEventArgs(PayloadData data)
|
||||
: base(Opcode.CLOSE, data)
|
||||
internal CloseEventArgs (PayloadData data)
|
||||
: base (Opcode.CLOSE, data)
|
||||
{
|
||||
_code = getCodeFrom(data);
|
||||
_reason = getReasonFrom(data);
|
||||
_clean = false;
|
||||
_code = getCodeFrom (data);
|
||||
_reason = getReasonFrom (data);
|
||||
_clean = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -67,7 +67,7 @@ namespace WebSocketSharp {
|
||||
/// Gets the status code for closure.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ushort"/> that contains a status code for closure.
|
||||
/// A <see cref="ushort"/> that contains a status code for closure if any.
|
||||
/// </value>
|
||||
public ushort Code {
|
||||
get {
|
||||
@ -79,7 +79,7 @@ namespace WebSocketSharp {
|
||||
/// Gets the reason for closure.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string"/> that contains a reason for closure.
|
||||
/// A <see cref="string"/> that contains the reason for closure if any.
|
||||
/// </value>
|
||||
public string Reason {
|
||||
get {
|
||||
@ -88,10 +88,10 @@ namespace WebSocketSharp {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the WebSocket connection closed cleanly.
|
||||
/// Indicates whether the WebSocket connection has been closed cleanly.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if the WebSocket connection closed cleanly; otherwise, <c>false</c>.
|
||||
/// <c>true</c> if the WebSocket connection has been closed cleanly; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool WasClean {
|
||||
get {
|
||||
@ -107,23 +107,23 @@ namespace WebSocketSharp {
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private static ushort getCodeFrom(PayloadData data)
|
||||
private static ushort getCodeFrom (PayloadData data)
|
||||
{
|
||||
var appData = data.ApplicationData;
|
||||
return appData.Length >= 2
|
||||
? appData.SubArray(0, 2).To<ushort>(ByteOrder.BIG)
|
||||
: (ushort)CloseStatusCode.NO_STATUS_CODE;
|
||||
? appData.SubArray (0, 2).To<ushort> (ByteOrder.BIG)
|
||||
: (ushort) CloseStatusCode.NO_STATUS_CODE;
|
||||
}
|
||||
|
||||
private static string getReasonFrom(PayloadData data)
|
||||
private static string getReasonFrom (PayloadData data)
|
||||
{
|
||||
var appData = data.ApplicationData;
|
||||
var appDataLen = appData.Length;
|
||||
if (appDataLen <= 2)
|
||||
return String.Empty;
|
||||
|
||||
var buffer = appData.SubArray(2, appDataLen - 2);
|
||||
return Encoding.UTF8.GetString(buffer);
|
||||
var reason = appData.SubArray (2, appDataLen - 2);
|
||||
return Encoding.UTF8.GetString (reason);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -473,7 +473,7 @@ namespace WebSocketSharp {
|
||||
#region Public Events
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the <see cref="WebSocket"/> receives a Close frame or the Close method is called.
|
||||
/// Occurs when the WebSocket connection has been closed.
|
||||
/// </summary>
|
||||
public event EventHandler<CloseEventArgs> OnClose;
|
||||
|
||||
@ -497,136 +497,109 @@ namespace WebSocketSharp {
|
||||
#region Private Methods
|
||||
|
||||
// As server
|
||||
private bool acceptHandshake()
|
||||
private bool acceptHandshake ()
|
||||
{
|
||||
if (!processRequestHandshake())
|
||||
return false;
|
||||
|
||||
sendResponseHandshake();
|
||||
return true;
|
||||
return processRequestHandshake ()
|
||||
? send (createResponseHandshake ())
|
||||
: false;
|
||||
}
|
||||
|
||||
private void close(CloseEventArgs eventArgs)
|
||||
private void close (CloseEventArgs eventArgs)
|
||||
{
|
||||
if (!Thread.CurrentThread.IsBackground && _exitReceiving != null)
|
||||
_exitReceiving.WaitOne(5 * 1000);
|
||||
if (!_exitReceiving.WaitOne (5 * 1000))
|
||||
eventArgs.WasClean = false;
|
||||
|
||||
if (!closeResources())
|
||||
if (!closeResources ())
|
||||
eventArgs.WasClean = false;
|
||||
|
||||
OnClose.Emit(this, eventArgs);
|
||||
_readyState = WsState.CLOSED;
|
||||
OnClose.Emit (this, eventArgs);
|
||||
}
|
||||
|
||||
private void close(PayloadData data)
|
||||
private void close (PayloadData data)
|
||||
{
|
||||
_logger.Debug("Is this thread background?: " + Thread.CurrentThread.IsBackground);
|
||||
lock(_forClose)
|
||||
_logger.Debug ("Is this thread background?: " + Thread.CurrentThread.IsBackground);
|
||||
CloseEventArgs args = null;
|
||||
lock (_forClose)
|
||||
{
|
||||
// Whether the closing handshake has been started already?
|
||||
if (_readyState == WsState.CLOSING || _readyState == WsState.CLOSED)
|
||||
return;
|
||||
|
||||
// Whether the closing handshake on server is started before the connection has been established?
|
||||
if (_readyState == WsState.CONNECTING && !_client)
|
||||
{
|
||||
sendResponseHandshake(HttpStatusCode.BadRequest);
|
||||
close(new CloseEventArgs(data));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var state = _readyState;
|
||||
_readyState = WsState.CLOSING;
|
||||
args = new CloseEventArgs (data);
|
||||
if (state == WsState.CONNECTING)
|
||||
{
|
||||
if (!_client)
|
||||
args.WasClean = send (createResponseHandshake (HttpStatusCode.BadRequest));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!data.ContainsReservedCloseStatusCode)
|
||||
args.WasClean = send (createControlFrame (Opcode.CLOSE, data, _client));
|
||||
}
|
||||
}
|
||||
|
||||
// Whether a payload data contains the close status code which must not be set for send?
|
||||
if (data.ContainsReservedCloseStatusCode)
|
||||
{
|
||||
close(new CloseEventArgs(data));
|
||||
return;
|
||||
}
|
||||
|
||||
closeHandshake(data);
|
||||
_logger.Trace("Exit close method.");
|
||||
close (args);
|
||||
_logger.Trace ("Exit close method.");
|
||||
}
|
||||
|
||||
private void close(HttpStatusCode code)
|
||||
private void close (ushort code, string reason)
|
||||
{
|
||||
if (_readyState != WsState.CONNECTING || _client)
|
||||
return;
|
||||
|
||||
sendResponseHandshake(code);
|
||||
closeResources();
|
||||
}
|
||||
|
||||
private void close(ushort code, string reason)
|
||||
{
|
||||
var data = code.Append(reason);
|
||||
var data = code.Append (reason);
|
||||
if (data.Length > 125)
|
||||
{
|
||||
var msg = "The payload length of a Close frame must be 125 bytes or less.";
|
||||
_logger.Error(msg);
|
||||
error(msg);
|
||||
_logger.Error (msg);
|
||||
error (msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
close(new PayloadData(data));
|
||||
}
|
||||
|
||||
private void closeHandshake(PayloadData data)
|
||||
{
|
||||
var args = new CloseEventArgs(data);
|
||||
var frame = createControlFrame(Opcode.CLOSE, data, _client);
|
||||
if (send(frame))
|
||||
args.WasClean = true;
|
||||
|
||||
close(args);
|
||||
}
|
||||
|
||||
private bool closeResources()
|
||||
{
|
||||
_readyState = WsState.CLOSED;
|
||||
|
||||
try
|
||||
{
|
||||
if (_client)
|
||||
closeResourcesAsClient();
|
||||
else
|
||||
closeResourcesAsServer();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Fatal(ex.Message);
|
||||
error("An exception has occured.");
|
||||
|
||||
return false;
|
||||
}
|
||||
close (new PayloadData (data));
|
||||
}
|
||||
|
||||
// As client
|
||||
private void closeResourcesAsClient()
|
||||
private void closeClientResources ()
|
||||
{
|
||||
if (_stream != null)
|
||||
{
|
||||
_stream.Dispose();
|
||||
_stream.Dispose ();
|
||||
_stream = null;
|
||||
}
|
||||
|
||||
if (_tcpClient != null)
|
||||
{
|
||||
_tcpClient.Close();
|
||||
_tcpClient.Close ();
|
||||
_tcpClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
private bool closeResources ()
|
||||
{
|
||||
try {
|
||||
if (_client)
|
||||
closeClientResources ();
|
||||
else
|
||||
closeServerResources ();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.Fatal (ex.Message);
|
||||
error ("An exception has occured.");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// As server
|
||||
private void closeResourcesAsServer()
|
||||
private void closeServerResources ()
|
||||
{
|
||||
if (_context != null && _closeContext != null)
|
||||
{
|
||||
_closeContext();
|
||||
_closeContext ();
|
||||
_stream = null;
|
||||
_context = null;
|
||||
}
|
||||
@ -1080,34 +1053,31 @@ namespace WebSocketSharp {
|
||||
}
|
||||
|
||||
// As server
|
||||
private bool processRequestHandshake()
|
||||
private bool processRequestHandshake ()
|
||||
{
|
||||
var req = RequestHandshake.Parse(_context);
|
||||
_logger.Debug("Request handshake from client:\n" + req.ToString());
|
||||
if (!isValidRequesHandshake())
|
||||
var req = RequestHandshake.Parse (_context);
|
||||
_logger.Debug ("Request handshake from client:\n" + req.ToString ());
|
||||
if (!isValidRequesHandshake ())
|
||||
{
|
||||
var msg = "Invalid WebSocket connection request.";
|
||||
_logger.Error(msg);
|
||||
error(msg);
|
||||
close(HttpStatusCode.BadRequest);
|
||||
_logger.Error (msg);
|
||||
error (msg);
|
||||
Close (HttpStatusCode.BadRequest);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_base64key = _context.SecWebSocketKey;
|
||||
processRequestProtocols(_context.Headers["Sec-WebSocket-Protocol"]);
|
||||
processRequestExtensions(_context.Headers["Sec-WebSocket-Extensions"]);
|
||||
|
||||
var protocols = _context.Headers ["Sec-WebSocket-Protocol"];
|
||||
if (!protocols.IsNullOrEmpty ())
|
||||
_protocols = protocols;
|
||||
|
||||
processRequestExtensions (_context.Headers ["Sec-WebSocket-Extensions"]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// As server
|
||||
private void processRequestProtocols(string protocols)
|
||||
{
|
||||
if (!protocols.IsNullOrEmpty())
|
||||
_protocols = protocols;
|
||||
}
|
||||
|
||||
// As client
|
||||
private void processResponseCookies(CookieCollection cookies)
|
||||
{
|
||||
@ -1190,13 +1160,13 @@ namespace WebSocketSharp {
|
||||
}
|
||||
|
||||
// As server
|
||||
private void send(ResponseHandshake response)
|
||||
private bool send (ResponseHandshake response)
|
||||
{
|
||||
_logger.Debug("Response handshake to client:\n" + response.ToString());
|
||||
_stream.WriteHandshake(response);
|
||||
_logger.Debug ("Response handshake to client:\n" + response.ToString ());
|
||||
return _stream.WriteHandshake (response);
|
||||
}
|
||||
|
||||
private bool send(WsFrame frame)
|
||||
private bool send (WsFrame frame)
|
||||
{
|
||||
lock (_forFrame)
|
||||
{
|
||||
@ -1211,13 +1181,13 @@ namespace WebSocketSharp {
|
||||
if (!ready)
|
||||
{
|
||||
var msg = "The WebSocket connection isn't established or has been closed.";
|
||||
_logger.Error(msg);
|
||||
error(msg);
|
||||
_logger.Error (msg);
|
||||
error (msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return _stream.WriteFrame(frame);
|
||||
return _stream.WriteFrame (frame);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1346,24 +1316,10 @@ namespace WebSocketSharp {
|
||||
}
|
||||
|
||||
// As client
|
||||
private ResponseHandshake sendRequestHandshake(RequestHandshake request)
|
||||
private ResponseHandshake sendRequestHandshake (RequestHandshake request)
|
||||
{
|
||||
send(request);
|
||||
return receiveResponseHandshake();
|
||||
}
|
||||
|
||||
// As server
|
||||
private void sendResponseHandshake()
|
||||
{
|
||||
var res = createResponseHandshake();
|
||||
send(res);
|
||||
}
|
||||
|
||||
// As server
|
||||
private void sendResponseHandshake(HttpStatusCode code)
|
||||
{
|
||||
var res = createResponseHandshake(code);
|
||||
send(res);
|
||||
send (request);
|
||||
return receiveResponseHandshake ();
|
||||
}
|
||||
|
||||
// As client
|
||||
@ -1375,35 +1331,32 @@ namespace WebSocketSharp {
|
||||
_stream = WsStream.CreateClientStream(_tcpClient, _secure, host, _certValidationCallback);
|
||||
}
|
||||
|
||||
private void startReceiving()
|
||||
private void startReceiving ()
|
||||
{
|
||||
_exitReceiving = new AutoResetEvent(false);
|
||||
_receivePong = new AutoResetEvent(false);
|
||||
_exitReceiving = new AutoResetEvent (false);
|
||||
_receivePong = new AutoResetEvent (false);
|
||||
|
||||
Action<WsFrame> completed = null;
|
||||
completed = (frame) =>
|
||||
completed = frame =>
|
||||
{
|
||||
try
|
||||
{
|
||||
processFrame(frame);
|
||||
try {
|
||||
processFrame (frame);
|
||||
if (_readyState == WsState.OPEN)
|
||||
_stream.ReadFrameAsync(completed);
|
||||
_stream.ReadFrameAsync (completed);
|
||||
else
|
||||
_exitReceiving.Set();
|
||||
_exitReceiving.Set ();
|
||||
}
|
||||
catch (WebSocketException ex)
|
||||
{
|
||||
_logger.Fatal(ex.Message);
|
||||
Close(ex.Code, ex.Message);
|
||||
catch (WebSocketException ex) {
|
||||
_logger.Fatal (ex.Message);
|
||||
Close (ex.Code, ex.Message);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Fatal(ex.Message);
|
||||
Close(CloseStatusCode.ABNORMAL, "An exception has occured.");
|
||||
catch (Exception ex) {
|
||||
_logger.Fatal (ex.Message);
|
||||
Close (CloseStatusCode.ABNORMAL, "An exception has occured.");
|
||||
}
|
||||
};
|
||||
|
||||
_stream.ReadFrameAsync(completed);
|
||||
_stream.ReadFrameAsync (completed);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -1411,9 +1364,12 @@ namespace WebSocketSharp {
|
||||
#region Internal Methods
|
||||
|
||||
// As server
|
||||
internal void Close(HttpStatusCode code)
|
||||
internal void Close (HttpStatusCode code)
|
||||
{
|
||||
close(code);
|
||||
_readyState = WsState.CLOSING;
|
||||
send (createResponseHandshake (code));
|
||||
closeResources ();
|
||||
_readyState = WsState.CLOSED;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -1423,9 +1379,9 @@ namespace WebSocketSharp {
|
||||
/// <summary>
|
||||
/// Closes the WebSocket connection and releases all associated resources.
|
||||
/// </summary>
|
||||
public void Close()
|
||||
public void Close ()
|
||||
{
|
||||
close(new PayloadData());
|
||||
close (new PayloadData ());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1439,9 +1395,9 @@ namespace WebSocketSharp {
|
||||
/// <param name="code">
|
||||
/// A <see cref="ushort"/> that indicates the status code for closure.
|
||||
/// </param>
|
||||
public void Close(ushort code)
|
||||
public void Close (ushort code)
|
||||
{
|
||||
Close(code, String.Empty);
|
||||
Close (code, String.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1451,9 +1407,9 @@ namespace WebSocketSharp {
|
||||
/// <param name="code">
|
||||
/// One of the <see cref="CloseStatusCode"/> values that indicates the status code for closure.
|
||||
/// </param>
|
||||
public void Close(CloseStatusCode code)
|
||||
public void Close (CloseStatusCode code)
|
||||
{
|
||||
close((ushort)code, String.Empty);
|
||||
close ((ushort) code, String.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1470,18 +1426,18 @@ namespace WebSocketSharp {
|
||||
/// <param name="reason">
|
||||
/// A <see cref="string"/> that contains the reason for closure.
|
||||
/// </param>
|
||||
public void Close(ushort code, string reason)
|
||||
public void Close (ushort code, string reason)
|
||||
{
|
||||
if (!code.IsCloseStatusCode())
|
||||
if (!code.IsCloseStatusCode ())
|
||||
{
|
||||
var msg = String.Format("Invalid close status code: {0}", code);
|
||||
_logger.Error(msg);
|
||||
error(msg);
|
||||
var msg = String.Format ("Invalid close status code: {0}", code);
|
||||
_logger.Error (msg);
|
||||
error (msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
close(code, reason);
|
||||
close (code, reason);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1494,9 +1450,9 @@ namespace WebSocketSharp {
|
||||
/// <param name="reason">
|
||||
/// A <see cref="string"/> that contains the reason for closure.
|
||||
/// </param>
|
||||
public void Close(CloseStatusCode code, string reason)
|
||||
public void Close (CloseStatusCode code, string reason)
|
||||
{
|
||||
close((ushort)code, reason);
|
||||
close ((ushort) code, reason);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
Loading…
Reference in New Issue
Block a user