Added internal 'wait time' for the ping and close

This commit is contained in:
sta 2014-09-23 15:45:40 +09:00
parent b6b30e04d0
commit 14914787a6
8 changed files with 138 additions and 74 deletions

View File

@ -424,7 +424,7 @@ namespace WebSocketSharp.Server
_state = ServerState.ShuttingDown; _state = ServerState.ShuttingDown;
} }
_services.Stop (new CloseEventArgs (CloseStatusCode.ServerError), true); _services.Stop (new CloseEventArgs (CloseStatusCode.ServerError), true, false);
_listener.Abort (); _listener.Abort ();
_state = ServerState.Stop; _state = ServerState.Stop;
@ -696,7 +696,7 @@ namespace WebSocketSharp.Server
_state = ServerState.ShuttingDown; _state = ServerState.ShuttingDown;
} }
_services.Stop (new CloseEventArgs (), true); _services.Stop (new CloseEventArgs (), true, true);
stopReceiving (5000); stopReceiving (5000);
_state = ServerState.Stop; _state = ServerState.Stop;
@ -729,7 +729,9 @@ namespace WebSocketSharp.Server
_state = ServerState.ShuttingDown; _state = ServerState.ShuttingDown;
} }
_services.Stop (e, !code.IsReserved ()); var send = !code.IsReserved ();
_services.Stop (e, send, send);
stopReceiving (5000); stopReceiving (5000);
_state = ServerState.Stop; _state = ServerState.Stop;
@ -762,7 +764,9 @@ namespace WebSocketSharp.Server
_state = ServerState.ShuttingDown; _state = ServerState.ShuttingDown;
} }
_services.Stop (e, !code.IsReserved ()); var send = !code.IsReserved ();
_services.Stop (e, send, send);
stopReceiving (5000); stopReceiving (5000);
_state = ServerState.Stop; _state = ServerState.Stop;

View File

@ -315,8 +315,9 @@ namespace WebSocketSharp.Server
_sessions = sessions; _sessions = sessions;
_websocket = context.WebSocket; _websocket = context.WebSocket;
_websocket.Protocol = _protocol;
_websocket.CustomHandshakeRequestChecker = checkIfValidConnectionRequest; _websocket.CustomHandshakeRequestChecker = checkIfValidConnectionRequest;
_websocket.Protocol = _protocol;
_websocket.WaitTime = sessions.WaitTime;
_websocket.OnOpen += onOpen; _websocket.OnOpen += onOpen;
_websocket.OnMessage += onMessage; _websocket.OnMessage += onMessage;

View File

@ -507,7 +507,7 @@ namespace WebSocketSharp.Server
} }
_listener.Stop (); _listener.Stop ();
_services.Stop (new CloseEventArgs (CloseStatusCode.ServerError), true); _services.Stop (new CloseEventArgs (CloseStatusCode.ServerError), true, false);
_state = ServerState.Stop; _state = ServerState.Stop;
} }
@ -793,7 +793,7 @@ namespace WebSocketSharp.Server
} }
stopReceiving (5000); stopReceiving (5000);
_services.Stop (new CloseEventArgs (), true); _services.Stop (new CloseEventArgs (), true, true);
_state = ServerState.Stop; _state = ServerState.Stop;
} }
@ -826,7 +826,9 @@ namespace WebSocketSharp.Server
} }
stopReceiving (5000); stopReceiving (5000);
_services.Stop (e, !code.IsReserved ());
var send = !code.IsReserved ();
_services.Stop (e, send, send);
_state = ServerState.Stop; _state = ServerState.Stop;
} }
@ -859,7 +861,9 @@ namespace WebSocketSharp.Server
} }
stopReceiving (5000); stopReceiving (5000);
_services.Stop (e, !code.IsReserved ());
var send = !code.IsReserved ();
_services.Stop (e, send, send);
_state = ServerState.Stop; _state = ServerState.Stop;
} }

View File

@ -67,6 +67,16 @@ namespace WebSocketSharp.Server
} }
} }
internal TimeSpan WaitTime {
get {
return Sessions.WaitTime;
}
set {
Sessions.WaitTime = value;
}
}
#endregion #endregion
#region Public Properties #region Public Properties
@ -122,11 +132,13 @@ namespace WebSocketSharp.Server
internal void Stop (ushort code, string reason) internal void Stop (ushort code, string reason)
{ {
var e = new CloseEventArgs (code, reason); var e = new CloseEventArgs (code, reason);
var bytes = !code.IsReserved ()
? WebSocketFrame.CreateCloseFrame (Mask.Unmask, e.PayloadData).ToByteArray ()
: null;
Sessions.Stop (e, bytes); var send = !code.IsReserved ();
var bytes =
send ? WebSocketFrame.CreateCloseFrame (e.PayloadData, false).ToByteArray () : null;
var timeout = send ? WaitTime : TimeSpan.Zero;
Sessions.Stop (e, bytes, timeout);
} }
#endregion #endregion

View File

@ -49,6 +49,7 @@ namespace WebSocketSharp.Server
private Logger _logger; private Logger _logger;
private volatile ServerState _state; private volatile ServerState _state;
private object _sync; private object _sync;
private TimeSpan _waitTime;
#endregion #endregion
@ -67,6 +68,28 @@ namespace WebSocketSharp.Server
_hosts = new Dictionary<string, WebSocketServiceHost> (); _hosts = new Dictionary<string, WebSocketServiceHost> ();
_state = ServerState.Ready; _state = ServerState.Ready;
_sync = ((ICollection) _hosts).SyncRoot; _sync = ((ICollection) _hosts).SyncRoot;
_waitTime = TimeSpan.FromSeconds (1);
}
#endregion
#region Internal Properties
internal TimeSpan WaitTime {
get {
return _waitTime;
}
set {
lock (_sync) {
if (value == _waitTime)
return;
_waitTime = value;
foreach (var host in _hosts.Values)
host.WaitTime = value;
}
}
} }
#endregion #endregion
@ -240,14 +263,14 @@ namespace WebSocketSharp.Server
} }
private Dictionary<string, Dictionary<string, bool>> broadping ( private Dictionary<string, Dictionary<string, bool>> broadping (
byte[] frameAsBytes, int millisecondsTimeout) byte[] frameAsBytes, TimeSpan timeout)
{ {
var res = new Dictionary<string, Dictionary<string, bool>> (); var res = new Dictionary<string, Dictionary<string, bool>> ();
foreach (var host in Hosts) { foreach (var host in Hosts) {
if (_state != ServerState.Start) if (_state != ServerState.Start)
break; break;
res.Add (host.Path, host.Sessions.Broadping (frameAsBytes, millisecondsTimeout)); res.Add (host.Path, host.Sessions.Broadping (frameAsBytes, timeout));
} }
return res; return res;
@ -275,6 +298,9 @@ namespace WebSocketSharp.Server
if (!_clean) if (!_clean)
host.KeepClean = false; host.KeepClean = false;
if (_waitTime != host.WaitTime)
host.WaitTime = _waitTime;
if (_state == ServerState.Start) if (_state == ServerState.Start)
host.Start (); host.Start ();
@ -325,16 +351,17 @@ namespace WebSocketSharp.Server
} }
} }
internal void Stop (CloseEventArgs e, bool send) internal void Stop (CloseEventArgs e, bool send, bool wait)
{ {
lock (_sync) { lock (_sync) {
_state = ServerState.ShuttingDown; _state = ServerState.ShuttingDown;
var bytes = send
? WebSocketFrame.CreateCloseFrame (Mask.Unmask, e.PayloadData).ToByteArray ()
: null;
var bytes =
send ? WebSocketFrame.CreateCloseFrame (e.PayloadData, false).ToByteArray () : null;
var timeout = wait ? _waitTime : TimeSpan.Zero;
foreach (var host in _hosts.Values) foreach (var host in _hosts.Values)
host.Sessions.Stop (e, bytes); host.Sessions.Stop (e, bytes, timeout);
_hosts.Clear (); _hosts.Clear ();
_state = ServerState.Stop; _state = ServerState.Stop;
@ -512,7 +539,7 @@ namespace WebSocketSharp.Server
return null; return null;
} }
return broadping (WebSocketFrame.EmptyUnmaskPingData, 1000); return broadping (WebSocketFrame.EmptyUnmaskPingData, _waitTime);
} }
/// <summary> /// <summary>
@ -543,7 +570,7 @@ namespace WebSocketSharp.Server
return null; return null;
} }
return broadping (WebSocketFrame.CreatePingFrame (Mask.Unmask, data).ToByteArray (), 1000); return broadping (WebSocketFrame.CreatePingFrame (data, false).ToByteArray (), _waitTime);
} }
/// <summary> /// <summary>

View File

@ -51,6 +51,7 @@ namespace WebSocketSharp.Server
private volatile bool _sweeping; private volatile bool _sweeping;
private System.Timers.Timer _sweepTimer; private System.Timers.Timer _sweepTimer;
private object _sync; private object _sync;
private TimeSpan _waitTime;
#endregion #endregion
@ -70,6 +71,7 @@ namespace WebSocketSharp.Server
_sessions = new Dictionary<string, IWebSocketSession> (); _sessions = new Dictionary<string, IWebSocketSession> ();
_state = ServerState.Ready; _state = ServerState.Ready;
_sync = ((ICollection) _sessions).SyncRoot; _sync = ((ICollection) _sessions).SyncRoot;
_waitTime = TimeSpan.FromSeconds (1);
setSweepTimer (60000); setSweepTimer (60000);
} }
@ -84,6 +86,21 @@ namespace WebSocketSharp.Server
} }
} }
internal TimeSpan WaitTime {
get {
return _waitTime;
}
set {
if (value == _waitTime)
return;
_waitTime = value;
foreach (var session in Sessions)
session.Context.WebSocket.WaitTime = value;
}
}
#endregion #endregion
#region Public Properties #region Public Properties
@ -97,7 +114,7 @@ namespace WebSocketSharp.Server
/// </value> /// </value>
public IEnumerable<string> ActiveIDs { public IEnumerable<string> ActiveIDs {
get { get {
foreach (var res in Broadping (WebSocketFrame.EmptyUnmaskPingData, 1000)) foreach (var res in Broadping (WebSocketFrame.EmptyUnmaskPingData, _waitTime))
if (res.Value) if (res.Value)
yield return res.Key; yield return res.Key;
} }
@ -142,7 +159,7 @@ namespace WebSocketSharp.Server
/// </value> /// </value>
public IEnumerable<string> InactiveIDs { public IEnumerable<string> InactiveIDs {
get { get {
foreach (var res in Broadping (WebSocketFrame.EmptyUnmaskPingData, 1000)) foreach (var res in Broadping (WebSocketFrame.EmptyUnmaskPingData, _waitTime))
if (!res.Value) if (!res.Value)
yield return res.Key; yield return res.Key;
} }
@ -318,14 +335,14 @@ namespace WebSocketSharp.Server
} }
} }
internal Dictionary<string, bool> Broadping (byte[] frameAsBytes, int millisecondsTimeout) internal Dictionary<string, bool> Broadping (byte[] frameAsBytes, TimeSpan timeout)
{ {
var res = new Dictionary<string, bool> (); var res = new Dictionary<string, bool> ();
foreach (var session in Sessions) { foreach (var session in Sessions) {
if (_state != ServerState.Start) if (_state != ServerState.Start)
break; break;
res.Add (session.ID, session.Context.WebSocket.Ping (frameAsBytes, millisecondsTimeout)); res.Add (session.ID, session.Context.WebSocket.Ping (frameAsBytes, timeout));
} }
return res; return res;
@ -345,14 +362,14 @@ namespace WebSocketSharp.Server
} }
} }
internal void Stop (CloseEventArgs e, byte[] frameAsBytes) internal void Stop (CloseEventArgs e, byte[] frameAsBytes, TimeSpan timeout)
{ {
lock (_sync) { lock (_sync) {
_state = ServerState.ShuttingDown; _state = ServerState.ShuttingDown;
_sweepTimer.Enabled = false; _sweepTimer.Enabled = false;
foreach (var session in _sessions.Values.ToList ()) foreach (var session in _sessions.Values.ToList ())
session.Context.WebSocket.Close (e, frameAsBytes, 1000); session.Context.WebSocket.Close (e, frameAsBytes, timeout);
_state = ServerState.Stop; _state = ServerState.Stop;
} }
@ -528,7 +545,7 @@ namespace WebSocketSharp.Server
return null; return null;
} }
return Broadping (WebSocketFrame.EmptyUnmaskPingData, 1000); return Broadping (WebSocketFrame.EmptyUnmaskPingData, _waitTime);
} }
/// <summary> /// <summary>
@ -557,7 +574,7 @@ namespace WebSocketSharp.Server
return null; return null;
} }
return Broadping (WebSocketFrame.CreatePingFrame (Mask.Unmask, data).ToByteArray (), 1000); return Broadping (WebSocketFrame.CreatePingFrame (data, false).ToByteArray (), _waitTime);
} }
/// <summary> /// <summary>

View File

@ -101,6 +101,7 @@ namespace WebSocketSharp
private TcpClient _tcpClient; private TcpClient _tcpClient;
private Uri _uri; private Uri _uri;
private const string _version = "13"; private const string _version = "13";
private TimeSpan _waitTime;
#endregion #endregion
@ -122,6 +123,7 @@ namespace WebSocketSharp
_closeContext = context.Close; _closeContext = context.Close;
_secure = context.IsSecureConnection; _secure = context.IsSecureConnection;
_stream = context.Stream; _stream = context.Stream;
_waitTime = TimeSpan.FromSeconds (1);
init (); init ();
} }
@ -136,6 +138,7 @@ namespace WebSocketSharp
_closeContext = context.Close; _closeContext = context.Close;
_secure = context.IsSecureConnection; _secure = context.IsSecureConnection;
_stream = context.Stream; _stream = context.Stream;
_waitTime = TimeSpan.FromSeconds (1);
init (); init ();
} }
@ -191,6 +194,7 @@ namespace WebSocketSharp
_client = true; _client = true;
_logger = new Logger (); _logger = new Logger ();
_secure = _uri.Scheme == "wss"; _secure = _uri.Scheme == "wss";
_waitTime = TimeSpan.FromSeconds (5);
init (); init ();
} }
@ -222,6 +226,16 @@ namespace WebSocketSharp
} }
} }
internal TimeSpan WaitTime {
get {
return _waitTime;
}
set {
_waitTime = value;
}
}
#endregion #endregion
#region Public Properties #region Public Properties
@ -596,18 +610,10 @@ namespace WebSocketSharp
_logger.Trace ("Start closing the connection."); _logger.Trace ("Start closing the connection.");
e.WasClean = e.WasClean = closeHandshake (
_client WebSocketFrame.CreateCloseFrame (e.PayloadData, _client).ToByteArray (),
? closeHandshake ( wait ? _waitTime : TimeSpan.Zero,
send ? WebSocketFrame.CreateCloseFrame (Mask.Mask, e.PayloadData).ToByteArray () _client ? (Action) releaseClientResources : releaseServerResources);
: null,
wait ? 5000 : 0,
releaseClientResources)
: closeHandshake (
send ? WebSocketFrame.CreateCloseFrame (Mask.Unmask, e.PayloadData).ToByteArray ()
: null,
wait ? 1000 : 0,
releaseServerResources);
_logger.Trace ("End closing the connection."); _logger.Trace ("End closing the connection.");
@ -627,13 +633,11 @@ namespace WebSocketSharp
closer.BeginInvoke (e, send, wait, ar => closer.EndInvoke (ar), null); closer.BeginInvoke (e, send, wait, ar => closer.EndInvoke (ar), null);
} }
private bool closeHandshake (byte[] frameAsBytes, int millisecondsTimeout, Action release) private bool closeHandshake (byte[] frameAsBytes, TimeSpan timeout, Action release)
{ {
var sent = frameAsBytes != null && sendBytes (frameAsBytes); var sent = frameAsBytes != null && sendBytes (frameAsBytes);
var received = millisecondsTimeout == 0 || var received = timeout == TimeSpan.Zero ||
(sent && (sent && _exitReceiving != null && _exitReceiving.WaitOne (timeout));
_exitReceiving != null &&
_exitReceiving.WaitOne (millisecondsTimeout));
release (); release ();
if (_receivePong != null) { if (_receivePong != null) {
@ -1412,7 +1416,7 @@ namespace WebSocketSharp
} }
// As server // As server
internal void Close (CloseEventArgs e, byte[] frameAsBytes, int millisecondsTimeout) internal void Close (CloseEventArgs e, byte[] frameAsBytes, TimeSpan timeout)
{ {
lock (_forConn) { lock (_forConn) {
if (_readyState == WebSocketState.Closing || _readyState == WebSocketState.Closed) { if (_readyState == WebSocketState.Closing || _readyState == WebSocketState.Closed) {
@ -1423,7 +1427,7 @@ namespace WebSocketSharp
_readyState = WebSocketState.Closing; _readyState = WebSocketState.Closing;
} }
e.WasClean = closeHandshake (frameAsBytes, millisecondsTimeout, releaseServerResources); e.WasClean = closeHandshake (frameAsBytes, timeout, releaseServerResources);
_readyState = WebSocketState.Closed; _readyState = WebSocketState.Closed;
try { try {
@ -1468,14 +1472,14 @@ namespace WebSocketSharp
return Convert.ToBase64String (src); return Convert.ToBase64String (src);
} }
internal bool Ping (byte[] frameAsBytes, int millisecondsTimeout) internal bool Ping (byte[] frameAsBytes, TimeSpan timeout)
{ {
try { try {
AutoResetEvent pong; AutoResetEvent pong;
return _readyState == WebSocketState.Open && return _readyState == WebSocketState.Open &&
send (frameAsBytes) && send (frameAsBytes) &&
(pong = _receivePong) != null && (pong = _receivePong) != null &&
pong.WaitOne (millisecondsTimeout); pong.WaitOne (timeout);
} }
catch (Exception ex) { catch (Exception ex) {
_logger.Fatal (ex.ToString ()); _logger.Fatal (ex.ToString ());
@ -1879,9 +1883,11 @@ namespace WebSocketSharp
/// </returns> /// </returns>
public bool Ping () public bool Ping ()
{ {
return _client var bytes = _client
? Ping (WebSocketFrame.CreatePingFrame (Mask.Mask).ToByteArray (), 5000) ? WebSocketFrame.CreatePingFrame (true).ToByteArray ()
: Ping (WebSocketFrame.EmptyUnmaskPingData, 1000); : WebSocketFrame.EmptyUnmaskPingData;
return Ping (bytes, _waitTime);
} }
/// <summary> /// <summary>
@ -1908,9 +1914,7 @@ namespace WebSocketSharp
return false; return false;
} }
return _client return Ping (WebSocketFrame.CreatePingFrame (data, _client).ToByteArray (), _waitTime);
? Ping (WebSocketFrame.CreatePingFrame (Mask.Mask, data).ToByteArray (), 5000)
: Ping (WebSocketFrame.CreatePingFrame (Mask.Unmask, data).ToByteArray (), 1000);
} }
/// <summary> /// <summary>

View File

@ -61,7 +61,7 @@ namespace WebSocketSharp
static WebSocketFrame () static WebSocketFrame ()
{ {
EmptyUnmaskPingData = CreatePingFrame (Mask.Unmask).ToByteArray (); EmptyUnmaskPingData = CreatePingFrame (false).ToByteArray ();
} }
#endregion #endregion
@ -523,30 +523,25 @@ Extended Payload Length: {7}
#region Internal Methods #region Internal Methods
internal static WebSocketFrame CreateCloseFrame (Mask mask, byte[] data) internal static WebSocketFrame CreateCloseFrame (byte[] data, bool mask)
{ {
return new WebSocketFrame (Opcode.Close, mask, new PayloadData (data)); return CreateCloseFrame (new PayloadData (data), mask);
} }
internal static WebSocketFrame CreateCloseFrame (Mask mask, PayloadData payload) internal static WebSocketFrame CreateCloseFrame (PayloadData payloadData, bool mask)
{ {
return new WebSocketFrame (Opcode.Close, mask, payload); return new WebSocketFrame (Opcode.Close, mask ? Mask.Mask : Mask.Unmask, payloadData);
} }
internal static WebSocketFrame CreateCloseFrame (Mask mask, CloseStatusCode code, string reason) internal static WebSocketFrame CreatePingFrame (bool mask)
{
return new WebSocketFrame (Opcode.Ping, mask ? Mask.Mask : Mask.Unmask, new PayloadData ());
}
internal static WebSocketFrame CreatePingFrame (byte[] data, bool mask)
{ {
return new WebSocketFrame ( return new WebSocketFrame (
Opcode.Close, mask, new PayloadData (((ushort) code).Append (reason))); Opcode.Ping, mask ? Mask.Mask : Mask.Unmask, new PayloadData (data));
}
internal static WebSocketFrame CreatePingFrame (Mask mask)
{
return new WebSocketFrame (Opcode.Ping, mask, new PayloadData ());
}
internal static WebSocketFrame CreatePingFrame (Mask mask, byte[] data)
{
return new WebSocketFrame (Opcode.Ping, mask, new PayloadData (data));
} }
internal static WebSocketFrame CreatePongFrame (Mask mask, PayloadData payload) internal static WebSocketFrame CreatePongFrame (Mask mask, PayloadData payload)