Modified closing

This commit is contained in:
sta 2014-01-08 12:14:24 +09:00
parent 7147cde22c
commit e03f9eb631
2 changed files with 132 additions and 97 deletions

View File

@ -180,12 +180,10 @@ namespace WebSocketSharp
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);
buffer.Write (tmp, 0, 2);
if (reason != null && reason.Length > 0)
{
if (reason != null && reason.Length > 0) {
tmp = Encoding.UTF8.GetBytes (reason);
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)
{
return stream == null
@ -1149,8 +1154,8 @@ namespace WebSocketSharp
}
/// <summary>
/// Determines whether the specified <see cref="ushort"/> is in the allowable range of
/// the WebSocket close status code.
/// Determines whether the specified <see cref="ushort"/> is in the allowable
/// range of the WebSocket close status code.
/// </summary>
/// <remarks>
/// Not allowable ranges are the followings.
@ -1162,14 +1167,15 @@ namespace WebSocketSharp
/// </item>
/// <item>
/// <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>
/// </item>
/// </list>
/// </remarks>
/// <returns>
/// <c>true</c> if <paramref name="value"/> is in the allowable range of the WebSocket close status code;
/// otherwise, <c>false</c>.
/// <c>true</c> if <paramref name="value"/> is in the allowable range of the
/// WebSocket close status code; otherwise, <c>false</c>.
/// </returns>
/// <param name="value">
/// A <see cref="ushort"/> to test.

View File

@ -557,34 +557,49 @@ namespace WebSocketSharp
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)
{
lock (_forClose)
{
if (_readyState == WebSocketState.CLOSING || _readyState == WebSocketState.CLOSED)
lock (_forClose) {
var msg = _readyState.CheckIfCanClose ();
if (msg != null) {
_logger.Info (String.Format ("{0}\nstate: {1}", msg, _readyState));
return;
}
_readyState = WebSocketState.CLOSING;
}
_logger.Trace ("Start closing handshake.");
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);
try {
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;
OnClose.Emit (this, args);
_readyState = WebSocketState.CLOSED;
OnClose.Emit (this, args);
}
catch (Exception ex) {
_logger.Fatal (ex.ToString ());
error ("An exception has occurred while closing.");
}
_logger.Trace ("End closing handshake.");
}
@ -592,11 +607,17 @@ namespace WebSocketSharp
private bool close (byte [] frameAsBytes, int timeOut, Func<bool> release)
{
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 result = sent && received && released;
_logger.Debug (String.Format (
"Was clean?: {0}\nsent: {1} received: {2} released: {3}", result, sent, received, released));
_logger.Debug (
String.Format (
"Was clean?: {0}\nsent: {1} received: {2} released: {3}",
result,
sent,
received,
released));
return result;
}
@ -605,14 +626,12 @@ namespace WebSocketSharp
private bool closeClientResources ()
{
try {
if (_stream != null)
{
if (_stream != null) {
_stream.Dispose ();
_stream = null;
}
if (_tcpClient != null)
{
if (_tcpClient != null) {
_tcpClient.Close ();
_tcpClient = null;
}
@ -621,10 +640,10 @@ namespace WebSocketSharp
}
catch (Exception ex) {
_logger.Fatal (ex.ToString ());
error ("An exception has occurred.");
return false;
error ("An exception has occurred while releasing resources.");
}
return false;
}
// As server
@ -641,10 +660,10 @@ namespace WebSocketSharp
}
catch (Exception ex) {
_logger.Fatal (ex.ToString ());
error ("An exception has occurred.");
return false;
error ("An exception has occurred while releasing resources.");
}
return false;
}
private bool concatenateFragmentsInto (Stream dest)
@ -886,21 +905,18 @@ namespace WebSocketSharp
{
var code = CloseStatusCode.ABNORMAL;
var msg = reason;
if (exception.GetType () == typeof (WebSocketException))
{
if (exception is WebSocketException) {
var wsex = (WebSocketException) exception;
code = wsex.Code;
reason = wsex.Message;
}
if (code == CloseStatusCode.ABNORMAL ||
code == CloseStatusCode.TLS_HANDSHAKE_FAILURE)
{
code == CloseStatusCode.TLS_HANDSHAKE_FAILURE) {
_logger.Fatal (exception.ToString ());
reason = msg;
}
else
{
else {
_logger.Error (reason);
msg = null;
}
@ -1365,21 +1381,28 @@ namespace WebSocketSharp
}
// As server
internal void Close (CloseEventArgs args, byte [] frameAsBytes, int waitTimeOut)
internal void Close (
CloseEventArgs args, byte [] frameAsBytes, int waitTimeOut)
{
lock (_forClose)
{
if (_readyState == WebSocketState.CLOSING || _readyState == WebSocketState.CLOSED)
lock (_forClose) {
var msg = _readyState.CheckIfCanClose ();
if (msg != null) {
_logger.Info (String.Format ("{0}\nstate: {1}", msg, _readyState));
return;
}
_readyState = WebSocketState.CLOSING;
}
args.WasClean = close (frameAsBytes, waitTimeOut, closeServerResources);
_readyState = WebSocketState.CLOSED;
OnClose.Emit (this, args);
try {
args.WasClean = close (frameAsBytes, waitTimeOut, closeServerResources);
_readyState = WebSocketState.CLOSED;
OnClose.Emit (this, args);
}
catch (Exception ex) {
_logger.Fatal (ex.ToString ());
}
}
// As server
@ -1480,11 +1503,20 @@ namespace WebSocketSharp
#region Public Methods
/// <summary>
/// Closes the WebSocket connection and releases all associated resources.
/// Closes the WebSocket connection, and releases all associated resources.
/// </summary>
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>
@ -1492,25 +1524,15 @@ namespace WebSocketSharp
/// and releases all associated resources.
/// </summary>
/// <remarks>
/// This method emits a <see cref="OnError"/> event if <paramref name="code"/> is not
/// in the allowable range of the WebSocket close status code.
/// This method emits a <see cref="OnError"/> event if <paramref name="code"/>
/// isn't in the allowable range of the WebSocket close status code.
/// </remarks>
/// <param name="code">
/// A <see cref="ushort"/> that indicates the status code for closure.
/// </param>
public void Close (ushort code)
{
var msg = code.CheckIfValidCloseStatusCode ();
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);
Close (code, null);
}
/// <summary>
@ -1518,75 +1540,81 @@ namespace WebSocketSharp
/// and releases all associated resources.
/// </summary>
/// <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>
public void Close (CloseStatusCode code)
{
var send = _readyState == WebSocketState.OPEN && !code.IsReserved ();
close (new PayloadData (((ushort) code).ToByteArrayInternally (ByteOrder.BIG)), send, true);
Close (code, null);
}
/// <summary>
/// Closes the WebSocket connection with the specified <see cref="ushort"/> and <see cref="string"/>,
/// and releases all associated resources.
/// Closes the WebSocket connection with the specified <see cref="ushort"/>
/// and <see cref="string"/>, and releases all associated resources.
/// </summary>
/// <remarks>
/// This method emits a <see cref="OnError"/> event if <paramref name="code"/> is not
/// in the allowable range of the WebSocket close status code
/// or the length of <paramref name="reason"/> is greater than 123 bytes.
/// This method emits a <see cref="OnError"/> event if <paramref name="code"/>
/// isn't in the allowable range of the WebSocket close status code or the
/// length of <paramref name="reason"/> is greater than 123 bytes.
/// </remarks>
/// <param name="code">
/// A <see cref="ushort"/> that indicates the status code for closure.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that contains the reason for closure.
/// A <see cref="string"/> that represents the reason for closure.
/// </param>
public void Close (ushort code, string reason)
{
byte [] data = null;
var msg = code.CheckIfValidCloseStatusCode () ??
var msg = _readyState.CheckIfCanClose () ??
code.CheckIfValidCloseStatusCode () ??
(data = code.Append (reason)).CheckIfValidCloseData ();
if (msg != null)
{
_logger.Error (String.Format ("{0}\ncode: {1}\nreason: {2}", msg, code, reason));
if (msg != null) {
_logger.Error (
String.Format (
"{0}\nstate: {1} code: {2} reason: {3}", msg, _readyState, code, reason));
error (msg);
return;
}
var send = _readyState == WebSocketState.OPEN && !code.IsReserved ();
close (new PayloadData (data), send, true);
close (new PayloadData (data), send, send);
}
/// <summary>
/// Closes the WebSocket connection with the specified <see cref="CloseStatusCode"/> and
/// <see cref="string"/>, and releases all associated resources.
/// Closes the WebSocket connection with the specified <see cref="CloseStatusCode"/>
/// and <see cref="string"/>, and releases all associated resources.
/// </summary>
/// <remarks>
/// This method emits a <see cref="OnError"/> event if the length of <paramref name="reason"/>
/// is greater than 123 bytes.
/// This method emits a <see cref="OnError"/> event if the length of
/// <paramref name="reason"/> is greater than 123 bytes.
/// </remarks>
/// <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 name="reason">
/// A <see cref="string"/> that contains the reason for closure.
/// A <see cref="string"/> that represents the reason for closure.
/// </param>
public void Close (CloseStatusCode code, string reason)
{
var data = ((ushort) code).Append (reason);
var msg = data.CheckIfValidCloseData ();
if (msg != null)
{
_logger.Error (String.Format ("{0}\nreason: {1}", msg, reason));
byte [] data = null;
var msg = _readyState.CheckIfCanClose () ??
(data = ((ushort) code).Append (reason)).CheckIfValidCloseData ();
if (msg != null) {
_logger.Error (
String.Format (
"{0}\nstate: {1} reason: {2}", msg, _readyState, reason));
error (msg);
return;
}
var send = _readyState == WebSocketState.OPEN && !code.IsReserved ();
close (new PayloadData (data), send, true);
close (new PayloadData (data), send, send);
}
/// <summary>
@ -1642,14 +1670,15 @@ namespace WebSocketSharp
}
/// <summary>
/// Closes the WebSocket connection and releases all associated resources.
/// Closes the WebSocket connection, and releases all associated resources.
/// </summary>
/// <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>
public void Dispose ()
{
Close (CloseStatusCode.AWAY);
Close (CloseStatusCode.AWAY, null);
}
/// <summary>