Fix for issue #20

This commit is contained in:
sta 2013-09-25 20:35:06 +09:00
parent 403cf2a3f2
commit adcb5ec09c
10 changed files with 561 additions and 217 deletions

View File

@ -8,7 +8,7 @@
<ProjectGuid>{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}</ProjectGuid> <ProjectGuid>{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}</ProjectGuid>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RootNamespace>Example3</RootNamespace> <RootNamespace>Example3</RootNamespace>
<AssemblyName>Example3</AssemblyName> <AssemblyName>example3</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

View File

@ -49,6 +49,7 @@ using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using WebSocketSharp.Net; using WebSocketSharp.Net;
using WebSocketSharp.Net.WebSockets; using WebSocketSharp.Net.WebSockets;
using WebSocketSharp.Server;
namespace WebSocketSharp namespace WebSocketSharp
{ {
@ -164,6 +165,20 @@ namespace WebSocketSharp
} }
} }
internal static string CheckIfStarted (this ServerState state)
{
return state != ServerState.START
? "Not started, on shutdown or stopped."
: null;
}
internal static string CheckIfStopped (this ServerState state)
{
return state == ServerState.START || state == ServerState.SHUTDOWN
? "Already started or on shutdown."
: null;
}
internal static string CheckIfValidCloseData (this byte [] data) internal static string CheckIfValidCloseData (this byte [] data)
{ {
return data.Length > 125 return data.Length > 125

View File

@ -47,13 +47,15 @@ namespace WebSocketSharp.Server
#region Private Fields #region Private Fields
private HttpListener _listener; private HttpListener _listener;
private bool _listening; private volatile bool _listening;
private Logger _logger; private Logger _logger;
private int _port; private int _port;
private Thread _receiveRequestThread; private Thread _receiveRequestThread;
private string _rootPath; private string _rootPath;
private bool _secure; private bool _secure;
private WebSocketServiceHostManager _serviceHosts; private WebSocketServiceHostManager _serviceHosts;
private volatile ServerState _state;
private object _sync;
private bool _windows; private bool _windows;
#endregion #endregion
@ -308,12 +310,40 @@ namespace WebSocketSharp.Server
#region Private Methods #region Private Methods
private void abort ()
{
lock (_sync)
{
if (_state != ServerState.START)
return;
_state = ServerState.SHUTDOWN;
}
_listening = false;
_serviceHosts.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG));
_listener.Abort ();
_state = ServerState.STOP;
}
private string checkIfCertExists ()
{
return _secure &&
!EndPointListener.CertificateExists (_port, _listener.CertificateFolderPath) &&
Certificate == null
? "The secure connection requires a server certificate."
: null;
}
private void init () private void init ()
{ {
_listener = new HttpListener (); _listener = new HttpListener ();
_listening = false; _listening = false;
_logger = new Logger (); _logger = new Logger ();
_serviceHosts = new WebSocketServiceHostManager (_logger); _serviceHosts = new WebSocketServiceHostManager (_logger);
_state = ServerState.READY;
_sync = new object ();
_windows = false; _windows = false;
var os = Environment.OSVersion; var os = Environment.OSVersion;
@ -420,7 +450,8 @@ namespace WebSocketSharp.Server
context.Response.Close (); context.Response.Close ();
} }
catch (Exception ex) { catch (Exception ex) {
_logger.Fatal (ex.Message); _logger.Fatal (ex.ToString ());
context.Connection.Close (true);
} }
}; };
@ -434,15 +465,18 @@ namespace WebSocketSharp.Server
try { try {
processRequestAsync (_listener.GetContext ()); processRequestAsync (_listener.GetContext ());
} }
catch (HttpListenerException) { catch (HttpListenerException ex) {
_logger.Info ("HttpListener has been stopped."); _logger.Warn (String.Format ("Receiving has been stopped.\nreason: {0}.", ex.Message));
break; break;
} }
catch (Exception ex) { catch (Exception ex) {
_logger.Fatal (ex.Message); _logger.Fatal (ex.ToString ());
break; break;
} }
} }
if (_listening)
abort ();
} }
private void startReceiveRequestThread () private void startReceiveRequestThread ()
@ -452,20 +486,14 @@ namespace WebSocketSharp.Server
_receiveRequestThread.Start (); _receiveRequestThread.Start ();
} }
private void stop (ushort code, string reason) private void stopListener ()
{ {
var data = code.Append (reason); if (!_listening)
var msg = data.CheckIfValidCloseData ();
if (msg != null)
{
_logger.Error (String.Format ("{0}\ncode: {1}\nreason: {2}", msg, code, reason));
return; return;
}
_serviceHosts.Stop (data); _listening = false;
_listener.Close (); _listener.Close ();
_receiveRequestThread.Join (5 * 1000); _receiveRequestThread.Join (5 * 1000);
_listening = false;
} }
#endregion #endregion
@ -554,21 +582,22 @@ namespace WebSocketSharp.Server
/// </summary> /// </summary>
public void Start () public void Start ()
{ {
if (_listening) lock (_sync)
return;
if (_secure &&
!EndPointListener.CertificateExists (_port, _listener.CertificateFolderPath) &&
Certificate == null
)
{ {
_logger.Error ("Secure connection requires a server certificate."); var msg = _state.CheckIfStopped () ?? checkIfCertExists ();
if (msg != null)
{
_logger.Error (String.Format ("{0}\nstate: {1}\nsecure: {2}", msg, _state, _secure));
return; return;
} }
_serviceHosts.Start ();
_listener.Start (); _listener.Start ();
startReceiveRequestThread (); startReceiveRequestThread ();
_listening = true; _listening = true;
_state = ServerState.START;
}
} }
/// <summary> /// <summary>
@ -576,13 +605,22 @@ namespace WebSocketSharp.Server
/// </summary> /// </summary>
public void Stop () public void Stop ()
{ {
if (!_listening) lock (_sync)
{
var msg = _state.CheckIfStarted ();
if (msg != null)
{
_logger.Error (String.Format ("{0}\nstate: {1}", msg, _state));
return; return;
}
_state = ServerState.SHUTDOWN;
}
_serviceHosts.Stop (); _serviceHosts.Stop ();
_listener.Close (); stopListener ();
_receiveRequestThread.Join (5 * 1000);
_listening = false; _state = ServerState.STOP;
} }
/// <summary> /// <summary>
@ -597,17 +635,26 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public void Stop (ushort code, string reason) public void Stop (ushort code, string reason)
{ {
if (!_listening) byte [] data = null;
return; lock (_sync)
{
var msg = _state.CheckIfStarted () ??
code.CheckIfValidCloseStatusCode () ??
(data = code.Append (reason)).CheckIfValidCloseData ();
var msg = code.CheckIfValidCloseStatusCode ();
if (msg != null) if (msg != null)
{ {
_logger.Error (String.Format ("{0}\ncode: {1}", msg, code)); _logger.Error (String.Format ("{0}\nstate: {1}\ncode: {2}\nreason: {3}", msg, _state, code, reason));
return; return;
} }
stop (code, reason); _state = ServerState.SHUTDOWN;
}
_serviceHosts.Stop (data);
stopListener ();
_state = ServerState.STOP;
} }
/// <summary> /// <summary>
@ -615,17 +662,33 @@ namespace WebSocketSharp.Server
/// and <see cref="string"/> used to stop the WebSocket services. /// and <see cref="string"/> used to stop the WebSocket services.
/// </summary> /// </summary>
/// <param name="code"> /// <param name="code">
/// A <see cref="CloseStatusCode"/> that contains a status code indicating the reason for stop. /// One of the <see cref="CloseStatusCode"/> values that represent the status codes indicating
/// the reasons for stop.
/// </param> /// </param>
/// <param name="reason"> /// <param name="reason">
/// A <see cref="string"/> that contains the reason for stop. /// A <see cref="string"/> that contains the reason for stop.
/// </param> /// </param>
public void Stop (CloseStatusCode code, string reason) public void Stop (CloseStatusCode code, string reason)
{ {
if (!_listening) byte [] data = null;
return; lock (_sync)
{
var msg = _state.CheckIfStarted () ??
(data = ((ushort) code).Append (reason)).CheckIfValidCloseData ();
stop ((ushort) code, reason); if (msg != null)
{
_logger.Error (String.Format ("{0}\nstate: {1}\nreason: {2}", msg, _state, reason));
return;
}
_state = ServerState.SHUTDOWN;
}
_serviceHosts.Stop (data);
stopListener ();
_state = ServerState.STOP;
} }
#endregion #endregion

View File

@ -0,0 +1,40 @@
#region License
/*
* ServerState.cs
*
* The MIT License
*
* Copyright (c) 2013 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp.Server
{
internal enum ServerState
{
READY,
START,
SHUTDOWN,
STOP
}
}

View File

@ -48,6 +48,8 @@ namespace WebSocketSharp.Server
#region Private Fields #region Private Fields
private WebSocketServiceHostManager _serviceHosts; private WebSocketServiceHostManager _serviceHosts;
private volatile ServerState _state;
private object _sync;
#endregion #endregion
@ -87,6 +89,8 @@ namespace WebSocketSharp.Server
throw new ArgumentException ("Must not contain the path component: " + url, "url"); throw new ArgumentException ("Must not contain the path component: " + url, "url");
_serviceHosts = new WebSocketServiceHostManager (Log); _serviceHosts = new WebSocketServiceHostManager (Log);
_state = ServerState.READY;
_sync = new object ();
} }
/// <summary> /// <summary>
@ -139,6 +143,8 @@ namespace WebSocketSharp.Server
: base (address, port, "/", secure) : base (address, port, "/", secure)
{ {
_serviceHosts = new WebSocketServiceHostManager (Log); _serviceHosts = new WebSocketServiceHostManager (Log);
_state = ServerState.READY;
_sync = new object ();
} }
#endregion #endregion
@ -193,26 +199,30 @@ namespace WebSocketSharp.Server
#endregion #endregion
#region Private Methods
private void stop (ushort code, string reason)
{
var data = code.Append (reason);
var msg = data.CheckIfValidCloseData ();
if (msg != null)
{
Log.Error (String.Format ("{0}\ncode: {1}\nreason: {2}", msg, code, reason));
return;
}
base.Stop ();
_serviceHosts.Stop (data);
}
#endregion
#region Protected Methods #region Protected Methods
/// <summary>
/// Aborts receiving the WebSocket connection requests.
/// </summary>
/// <remarks>
/// This method is called when an exception occurs while receiving the WebSocket connection requests.
/// </remarks>
protected override void Abort ()
{
lock (_sync)
{
if (_state != ServerState.START)
return;
_state = ServerState.SHUTDOWN;
}
StopListener ();
_serviceHosts.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG));
_state = ServerState.STOP;
}
/// <summary> /// <summary>
/// Accepts a WebSocket connection request. /// Accepts a WebSocket connection request.
/// </summary> /// </summary>
@ -301,13 +311,54 @@ namespace WebSocketSharp.Server
return _serviceHosts.Remove (servicePath); return _serviceHosts.Remove (servicePath);
} }
/// <summary>
/// Starts to receive the WebSocket connection requests.
/// </summary>
public override void Start ()
{
lock (_sync)
{
var msg = _state.CheckIfStopped ();
if (msg != null)
{
Log.Error (String.Format ("{0}\nstate: {1}", msg, _state));
return;
}
_serviceHosts.Start ();
base.Start ();
if (!IsListening)
{
_serviceHosts.Stop ();
return;
}
_state = ServerState.START;
}
}
/// <summary> /// <summary>
/// Stops receiving the WebSocket connection requests. /// Stops receiving the WebSocket connection requests.
/// </summary> /// </summary>
public override void Stop () public override void Stop ()
{ {
lock (_sync)
{
var msg = _state.CheckIfStarted ();
if (msg != null)
{
Log.Error (String.Format ("{0}\nstate: {1}", msg, _state));
return;
}
_state = ServerState.SHUTDOWN;
}
base.Stop (); base.Stop ();
_serviceHosts.Stop (); _serviceHosts.Stop ();
_state = ServerState.STOP;
} }
/// <summary> /// <summary>
@ -322,14 +373,26 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public void Stop (ushort code, string reason) public void Stop (ushort code, string reason)
{ {
var msg = code.CheckIfValidCloseStatusCode (); byte [] data = null;
lock (_sync)
{
var msg = _state.CheckIfStarted () ??
code.CheckIfValidCloseStatusCode () ??
(data = code.Append (reason)).CheckIfValidCloseData ();
if (msg != null) if (msg != null)
{ {
Log.Error (String.Format ("{0}\ncode: {1}", msg, code)); Log.Error (String.Format ("{0}\nstate: {1}\ncode: {2}\nreason: {3}", msg, _state, code, reason));
return; return;
} }
stop (code, reason); _state = ServerState.SHUTDOWN;
}
base.Stop ();
_serviceHosts.Stop (data);
_state = ServerState.STOP;
} }
/// <summary> /// <summary>
@ -337,14 +400,33 @@ namespace WebSocketSharp.Server
/// and <see cref="string"/>. /// and <see cref="string"/>.
/// </summary> /// </summary>
/// <param name="code"> /// <param name="code">
/// A <see cref="CloseStatusCode"/> that contains a status code indicating the reason for stop. /// One of the <see cref="CloseStatusCode"/> values that represent the status codes indicating
/// the reasons for stop.
/// </param> /// </param>
/// <param name="reason"> /// <param name="reason">
/// A <see cref="string"/> that contains the reason for stop. /// A <see cref="string"/> that contains the reason for stop.
/// </param> /// </param>
public void Stop (CloseStatusCode code, string reason) public void Stop (CloseStatusCode code, string reason)
{ {
stop ((ushort) code, reason); byte [] data = null;
lock (_sync)
{
var msg = _state.CheckIfStarted () ??
(data = ((ushort) code).Append (reason)).CheckIfValidCloseData ();
if (msg != null)
{
Log.Error (String.Format ("{0}\nstate: {1}\nreason: {2}", msg, _state, reason));
return;
}
_state = ServerState.SHUTDOWN;
}
base.Stop ();
_serviceHosts.Stop (data);
_state = ServerState.STOP;
} }
#endregion #endregion

View File

@ -48,7 +48,7 @@ namespace WebSocketSharp.Server
private IPAddress _address; private IPAddress _address;
private X509Certificate2 _cert; private X509Certificate2 _cert;
private bool _listening; private volatile bool _listening;
private Logger _logger; private Logger _logger;
private int _port; private int _port;
private Thread _receiveRequestThread; private Thread _receiveRequestThread;
@ -339,8 +339,8 @@ namespace WebSocketSharp.Server
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Fatal (ex.ToString ());
client.Close (); client.Close ();
_logger.Fatal (ex.Message);
} }
}; };
@ -354,15 +354,18 @@ namespace WebSocketSharp.Server
try { try {
processRequestAsync (_listener.AcceptTcpClient ()); processRequestAsync (_listener.AcceptTcpClient ());
} }
catch (SocketException) { catch (SocketException ex) {
_logger.Info ("TcpListener has been stopped."); _logger.Warn (String.Format ("Receiving has been stopped.\nreason: {0}.", ex.Message));
break; break;
} }
catch (Exception ex) { catch (Exception ex) {
_logger.Fatal (ex.Message); _logger.Fatal (ex.ToString ());
break; break;
} }
} }
if (_listening)
Abort ();
} }
private void startReceiveRequestThread () private void startReceiveRequestThread ()
@ -392,6 +395,14 @@ namespace WebSocketSharp.Server
#region Protected Methods #region Protected Methods
/// <summary>
/// Aborts receiving the WebSocket connection requests.
/// </summary>
/// <remarks>
/// This method is called when an exception occurs while receiving the WebSocket connection requests.
/// </remarks>
protected abstract void Abort ();
/// <summary> /// <summary>
/// Accepts a WebSocket connection request. /// Accepts a WebSocket connection request.
/// </summary> /// </summary>
@ -400,6 +411,18 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
protected abstract void AcceptWebSocket (TcpListenerWebSocketContext context); protected abstract void AcceptWebSocket (TcpListenerWebSocketContext context);
/// <summary>
/// Stops the inner <see cref="TcpListener"/> used to receive the WebSocket connection requests.
/// </summary>
protected void StopListener ()
{
if (!_listening)
return;
_listening = false;
_listener.Stop ();
}
#endregion #endregion
#region Public Methods #region Public Methods
@ -414,7 +437,7 @@ namespace WebSocketSharp.Server
if (_secure && _cert == null) if (_secure && _cert == null)
{ {
_logger.Error ("Secure connection requires a server certificate."); _logger.Error ("The secure connection requires a server certificate.");
return; return;
} }
@ -431,9 +454,9 @@ namespace WebSocketSharp.Server
if (!_selfHost || !_listening) if (!_selfHost || !_listening)
return; return;
_listening = false;
_listener.Stop (); _listener.Stop ();
_receiveRequestThread.Join (5 * 1000); _receiveRequestThread.Join (5 * 1000);
_listening = false;
} }
#endregion #endregion

View File

@ -54,6 +54,8 @@ namespace WebSocketSharp.Server
private string _servicePath; private string _servicePath;
private WebSocketSessionManager _sessions; private WebSocketSessionManager _sessions;
private volatile ServerState _state;
private object _sync;
#endregion #endregion
@ -63,6 +65,8 @@ namespace WebSocketSharp.Server
: base (logger) : base (logger)
{ {
_sessions = new WebSocketSessionManager (logger); _sessions = new WebSocketSessionManager (logger);
_state = ServerState.READY;
_sync = new object ();
} }
#endregion #endregion
@ -92,6 +96,8 @@ namespace WebSocketSharp.Server
: base (url) : base (url)
{ {
_sessions = new WebSocketSessionManager (Log); _sessions = new WebSocketSessionManager (Log);
_state = ServerState.READY;
_sync = new object ();
} }
/// <summary> /// <summary>
@ -186,6 +192,8 @@ namespace WebSocketSharp.Server
: base (address, port, servicePath, secure) : base (address, port, servicePath, secure)
{ {
_sessions = new WebSocketSessionManager (Log); _sessions = new WebSocketSessionManager (Log);
_state = ServerState.READY;
_sync = new object ();
} }
#endregion #endregion
@ -267,26 +275,30 @@ namespace WebSocketSharp.Server
#endregion #endregion
#region Private Methods
private void stop (ushort code, string reason)
{
var data = code.Append (reason);
var msg = data.CheckIfValidCloseData ();
if (msg != null)
{
Log.Error (String.Format ("{0}\ncode: {1}\nreason: {2}", msg, code, reason));
return;
}
base.Stop ();
_sessions.Stop (data);
}
#endregion
#region Protected Methods #region Protected Methods
/// <summary>
/// Aborts receiving the WebSocket connection requests.
/// </summary>
/// <remarks>
/// This method is called when an exception occurs while receiving the WebSocket connection requests.
/// </remarks>
protected override void Abort ()
{
lock (_sync)
{
if (_state != ServerState.START)
return;
_state = ServerState.SHUTDOWN;
}
StopListener ();
_sessions.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG));
_state = ServerState.STOP;
}
/// <summary> /// <summary>
/// Accepts a WebSocket connection request. /// Accepts a WebSocket connection request.
/// </summary> /// </summary>
@ -315,13 +327,54 @@ namespace WebSocketSharp.Server
#region Public Methods #region Public Methods
/// <summary>
/// Starts to receive the WebSocket connection requests.
/// </summary>
public override void Start ()
{
lock (_sync)
{
var msg = _state.CheckIfStopped ();
if (msg != null)
{
Log.Error (String.Format ("{0}\nstate: {1}", msg, _state));
return;
}
_sessions.Start ();
base.Start ();
if (!IsListening)
{
_sessions.Stop ();
return;
}
_state = ServerState.START;
}
}
/// <summary> /// <summary>
/// Stops receiving the WebSocket connection requests. /// Stops receiving the WebSocket connection requests.
/// </summary> /// </summary>
public override void Stop () public override void Stop ()
{ {
lock (_sync)
{
var msg = _state.CheckIfStarted ();
if (msg != null)
{
Log.Error (String.Format ("{0}\nstate: {1}", msg, _state));
return;
}
_state = ServerState.SHUTDOWN;
}
base.Stop (); base.Stop ();
_sessions.Stop (); _sessions.Stop ();
_state = ServerState.STOP;
} }
/// <summary> /// <summary>
@ -336,14 +389,26 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public void Stop (ushort code, string reason) public void Stop (ushort code, string reason)
{ {
var msg = code.CheckIfValidCloseStatusCode (); byte [] data = null;
lock (_sync)
{
var msg = _state.CheckIfStarted () ??
code.CheckIfValidCloseStatusCode () ??
(data = code.Append (reason)).CheckIfValidCloseData ();
if (msg != null) if (msg != null)
{ {
Log.Error (String.Format ("{0}\ncode: {1}", msg, code)); Log.Error (String.Format ("{0}\nstate: {1}\ncode: {2}\nreason: {3}", msg, _state, code, reason));
return; return;
} }
stop (code, reason); _state = ServerState.SHUTDOWN;
}
base.Stop ();
_sessions.Stop (data);
_state = ServerState.STOP;
} }
/// <summary> /// <summary>
@ -351,14 +416,33 @@ namespace WebSocketSharp.Server
/// and <see cref="string"/>. /// and <see cref="string"/>.
/// </summary> /// </summary>
/// <param name="code"> /// <param name="code">
/// A <see cref="CloseStatusCode"/> that contains a status code indicating the reason for stop. /// One of the <see cref="CloseStatusCode"/> values that represent the status codes indicating
/// the reasons for stop.
/// </param> /// </param>
/// <param name="reason"> /// <param name="reason">
/// A <see cref="string"/> that contains the reason for stop. /// A <see cref="string"/> that contains the reason for stop.
/// </param> /// </param>
public void Stop (CloseStatusCode code, string reason) public void Stop (CloseStatusCode code, string reason)
{ {
stop ((ushort) code, reason); byte [] data = null;
lock (_sync)
{
var msg = _state.CheckIfStarted () ??
(data = ((ushort) code).Append (reason)).CheckIfValidCloseData ();
if (msg != null)
{
Log.Error (String.Format ("{0}\nstate: {1}\nreason: {2}", msg, _state, reason));
return;
}
_state = ServerState.SHUTDOWN;
}
base.Stop ();
_sessions.Stop (data);
_state = ServerState.STOP;
} }
#endregion #endregion

View File

@ -45,6 +45,7 @@ namespace WebSocketSharp.Server
private volatile bool _keepClean; private volatile bool _keepClean;
private Logger _logger; private Logger _logger;
private Dictionary<string, IWebSocketServiceHost> _serviceHosts; private Dictionary<string, IWebSocketServiceHost> _serviceHosts;
private volatile ServerState _state;
private object _sync; private object _sync;
#endregion #endregion
@ -61,6 +62,7 @@ namespace WebSocketSharp.Server
_logger = logger; _logger = logger;
_keepClean = true; _keepClean = true;
_serviceHosts = new Dictionary<string, IWebSocketServiceHost> (); _serviceHosts = new Dictionary<string, IWebSocketServiceHost> ();
_state = ServerState.READY;
_sync = new object (); _sync = new object ();
} }
@ -78,7 +80,12 @@ namespace WebSocketSharp.Server
get { get {
var count = 0; var count = 0;
foreach (var host in ServiceHosts) foreach (var host in ServiceHosts)
{
if (_state != ServerState.START)
break;
count += host.ConnectionCount; count += host.ConnectionCount;
}
return count; return count;
} }
@ -143,15 +150,15 @@ namespace WebSocketSharp.Server
internal set { internal set {
lock (_sync) lock (_sync)
{ {
if (_keepClean ^ value) if (!(value ^ _keepClean))
{ return;
_keepClean = value; _keepClean = value;
foreach (var host in _serviceHosts.Values) foreach (var host in _serviceHosts.Values)
host.KeepClean = value; host.KeepClean = value;
} }
} }
} }
}
/// <summary> /// <summary>
/// Gets the collection of the WebSocket service hosts managed by the WebSocket server. /// Gets the collection of the WebSocket service hosts managed by the WebSocket server.
@ -192,7 +199,12 @@ namespace WebSocketSharp.Server
{ {
var result = new Dictionary<string, Dictionary<string, bool>> (); var result = new Dictionary<string, Dictionary<string, bool>> ();
foreach (var host in ServiceHosts) foreach (var host in ServiceHosts)
{
if (_state != ServerState.START)
break;
result.Add (host.ServicePath, host.Sessions.BroadpingInternally (data)); result.Add (host.ServicePath, host.Sessions.BroadpingInternally (data));
}
return result; return result;
} }
@ -214,6 +226,9 @@ namespace WebSocketSharp.Server
return; return;
} }
if (_state == ServerState.START)
serviceHost.Sessions.Start ();
_serviceHosts.Add (servicePath, serviceHost); _serviceHosts.Add (servicePath, serviceHost);
} }
} }
@ -234,18 +249,33 @@ namespace WebSocketSharp.Server
_serviceHosts.Remove (servicePath); _serviceHosts.Remove (servicePath);
} }
if (host.Sessions.State == ServerState.START)
host.Sessions.Stop (((ushort) CloseStatusCode.AWAY).ToByteArray (ByteOrder.BIG)); host.Sessions.Stop (((ushort) CloseStatusCode.AWAY).ToByteArray (ByteOrder.BIG));
return true; return true;
} }
internal void Start ()
{
lock (_sync)
{
foreach (var host in _serviceHosts.Values)
host.Sessions.Start ();
_state = ServerState.START;
}
}
internal void Stop () internal void Stop ()
{ {
lock (_sync) lock (_sync)
{ {
_state = ServerState.SHUTDOWN;
foreach (var host in _serviceHosts.Values) foreach (var host in _serviceHosts.Values)
host.Sessions.Stop (); host.Sessions.Stop ();
_serviceHosts.Clear (); _serviceHosts.Clear ();
_state = ServerState.STOP;
} }
} }
@ -253,10 +283,12 @@ namespace WebSocketSharp.Server
{ {
lock (_sync) lock (_sync)
{ {
_state = ServerState.SHUTDOWN;
foreach (var host in _serviceHosts.Values) foreach (var host in _serviceHosts.Values)
host.Sessions.Stop (data); host.Sessions.Stop (data);
_serviceHosts.Clear (); _serviceHosts.Clear ();
_state = ServerState.STOP;
} }
} }
@ -282,7 +314,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public void Broadcast (byte [] data) public void Broadcast (byte [] data)
{ {
var msg = data.CheckIfValidSendData (); var msg = _state.CheckIfStarted () ?? data.CheckIfValidSendData ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -290,8 +322,13 @@ namespace WebSocketSharp.Server
} }
foreach (var host in ServiceHosts) foreach (var host in ServiceHosts)
{
if (_state != ServerState.START)
break;
host.Sessions.BroadcastInternally (data); host.Sessions.BroadcastInternally (data);
} }
}
/// <summary> /// <summary>
/// Broadcasts the specified <see cref="string"/> to all clients of the WebSocket services /// Broadcasts the specified <see cref="string"/> to all clients of the WebSocket services
@ -302,7 +339,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public void Broadcast (string data) public void Broadcast (string data)
{ {
var msg = data.CheckIfValidSendData (); var msg = _state.CheckIfStarted () ?? data.CheckIfValidSendData ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -310,8 +347,13 @@ namespace WebSocketSharp.Server
} }
foreach (var host in ServiceHosts) foreach (var host in ServiceHosts)
{
if (_state != ServerState.START)
break;
host.Sessions.BroadcastInternally (data); host.Sessions.BroadcastInternally (data);
} }
}
/// <summary> /// <summary>
/// Broadcasts the specified array of <see cref="byte"/> to all clients of the WebSocket service /// Broadcasts the specified array of <see cref="byte"/> to all clients of the WebSocket service
@ -328,7 +370,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public bool BroadcastTo (byte [] data, string servicePath) public bool BroadcastTo (byte [] data, string servicePath)
{ {
var msg = data.CheckIfValidSendData () ?? servicePath.CheckIfValidServicePath (); var msg = _state.CheckIfStarted () ?? data.CheckIfValidSendData () ?? servicePath.CheckIfValidServicePath ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -361,7 +403,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public bool BroadcastTo (string data, string servicePath) public bool BroadcastTo (string data, string servicePath)
{ {
var msg = data.CheckIfValidSendData () ?? servicePath.CheckIfValidServicePath (); var msg = _state.CheckIfStarted () ?? data.CheckIfValidSendData () ?? servicePath.CheckIfValidServicePath ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -389,6 +431,13 @@ namespace WebSocketSharp.Server
/// </returns> /// </returns>
public Dictionary<string, Dictionary<string, bool>> Broadping () public Dictionary<string, Dictionary<string, bool>> Broadping ()
{ {
var msg = _state.CheckIfStarted ();
if (msg != null)
{
_logger.Error (msg);
return null;
}
return broadping (new byte [] {}); return broadping (new byte [] {});
} }
@ -408,10 +457,10 @@ namespace WebSocketSharp.Server
public Dictionary<string, Dictionary<string, bool>> Broadping (string message) public Dictionary<string, Dictionary<string, bool>> Broadping (string message)
{ {
if (message == null || message.Length == 0) if (message == null || message.Length == 0)
return broadping (new byte [] {}); return Broadping ();
var data = Encoding.UTF8.GetBytes (message); var data = Encoding.UTF8.GetBytes (message);
var msg = data.CheckIfValidPingData (); var msg = _state.CheckIfStarted () ?? data.CheckIfValidPingData ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -434,7 +483,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public Dictionary<string, bool> BroadpingTo (string servicePath) public Dictionary<string, bool> BroadpingTo (string servicePath)
{ {
var msg = servicePath.CheckIfValidServicePath (); var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -472,7 +521,7 @@ namespace WebSocketSharp.Server
return BroadpingTo (servicePath); return BroadpingTo (servicePath);
var data = Encoding.UTF8.GetBytes (message); var data = Encoding.UTF8.GetBytes (message);
var msg = data.CheckIfValidPingData () ?? servicePath.CheckIfValidServicePath (); var msg = _state.CheckIfStarted () ?? data.CheckIfValidPingData () ?? servicePath.CheckIfValidServicePath ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -501,7 +550,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public void CloseSession (string id, string servicePath) public void CloseSession (string id, string servicePath)
{ {
var msg = servicePath.CheckIfValidServicePath (); var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -536,7 +585,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public void CloseSession (ushort code, string reason, string id, string servicePath) public void CloseSession (ushort code, string reason, string id, string servicePath)
{ {
var msg = servicePath.CheckIfValidServicePath (); var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -571,7 +620,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public void CloseSession (CloseStatusCode code, string reason, string id, string servicePath) public void CloseSession (CloseStatusCode code, string reason, string id, string servicePath)
{ {
var msg = servicePath.CheckIfValidServicePath (); var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -604,7 +653,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public bool PingTo (string id, string servicePath) public bool PingTo (string id, string servicePath)
{ {
var msg = servicePath.CheckIfValidServicePath (); var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -640,7 +689,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public bool PingTo (string message, string id, string servicePath) public bool PingTo (string message, string id, string servicePath)
{ {
var msg = servicePath.CheckIfValidServicePath (); var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -675,7 +724,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public bool SendTo (byte [] data, string id, string servicePath) public bool SendTo (byte [] data, string id, string servicePath)
{ {
var msg = servicePath.CheckIfValidServicePath (); var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -710,7 +759,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public bool SendTo (string data, string id, string servicePath) public bool SendTo (string data, string id, string servicePath)
{ {
var msg = servicePath.CheckIfValidServicePath (); var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -744,7 +793,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public bool TryGetServiceHost (string servicePath, out IWebSocketServiceHost serviceHost) public bool TryGetServiceHost (string servicePath, out IWebSocketServiceHost serviceHost)
{ {
var msg = servicePath.CheckIfValidServicePath (); var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);

View File

@ -42,9 +42,10 @@ namespace WebSocketSharp.Server
#region Private Fields #region Private Fields
private object _forSweep; private object _forSweep;
private volatile bool _keepClean;
private Logger _logger; private Logger _logger;
private Dictionary<string, WebSocketService> _sessions; private Dictionary<string, WebSocketService> _sessions;
private volatile bool _stopped; private volatile ServerState _state;
private volatile bool _sweeping; private volatile bool _sweeping;
private Timer _sweepTimer; private Timer _sweepTimer;
private object _sync; private object _sync;
@ -62,21 +63,30 @@ namespace WebSocketSharp.Server
{ {
_logger = logger; _logger = logger;
_forSweep = new object (); _forSweep = new object ();
_keepClean = true;
_sessions = new Dictionary<string, WebSocketService> (); _sessions = new Dictionary<string, WebSocketService> ();
_stopped = false; _state = ServerState.READY;
_sweeping = false; _sweeping = false;
_sync = new object (); _sync = new object ();
setSweepTimer (); setSweepTimer (60 * 1000);
startSweepTimer ();
} }
#endregion #endregion
#region Internal Properties #region Internal Properties
internal ServerState State {
get {
return _state;
}
}
internal IEnumerable<WebSocketService> ServiceInstances { internal IEnumerable<WebSocketService> ServiceInstances {
get { get {
if (_state != ServerState.START)
return new List<WebSocketService> ();
lock (_sync) lock (_sync)
{ {
return _sessions.Values.ToList (); return _sessions.Values.ToList ();
@ -158,7 +168,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public IWebSocketSession this [string id] { public IWebSocketSession this [string id] {
get { get {
var msg = id.CheckIfValidSessionID (); var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -182,17 +192,16 @@ namespace WebSocketSharp.Server
/// </value> /// </value>
public bool KeepClean { public bool KeepClean {
get { get {
return _sweepTimer.Enabled; return _keepClean;
} }
internal set { internal set {
if (value) if (!(value ^ _keepClean))
{ return;
if (!_stopped)
startSweepTimer (); _keepClean = value;
} if (_state == ServerState.START)
else _sweepTimer.Enabled = value;
stopSweepTimer ();
} }
} }
@ -213,72 +222,20 @@ namespace WebSocketSharp.Server
#region Private Methods #region Private Methods
private void broadcast (byte [] data)
{
foreach (var service in ServiceInstances)
service.Send (data);
}
private void broadcast (string data)
{
foreach (var service in ServiceInstances)
service.Send (data);
}
private void broadcastAsync (byte [] data)
{
var services = ServiceInstances.GetEnumerator ();
Action completed = null;
completed = () =>
{
if (services.MoveNext ())
services.Current.SendAsync (data, completed);
};
if (services.MoveNext ())
services.Current.SendAsync (data, completed);
}
private void broadcastAsync (string data)
{
var services = ServiceInstances.GetEnumerator ();
Action completed = null;
completed = () =>
{
if (services.MoveNext ())
services.Current.SendAsync (data, completed);
};
if (services.MoveNext ())
services.Current.SendAsync (data, completed);
}
private static string createID () private static string createID ()
{ {
return Guid.NewGuid ().ToString ("N"); return Guid.NewGuid ().ToString ("N");
} }
private void setSweepTimer () private void setSweepTimer (double interval)
{ {
_sweepTimer = new Timer (60 * 1000); _sweepTimer = new Timer (interval);
_sweepTimer.Elapsed += (sender, e) => _sweepTimer.Elapsed += (sender, e) =>
{ {
Sweep (); Sweep ();
}; };
} }
private void startSweepTimer ()
{
if (!_sweepTimer.Enabled)
_sweepTimer.Start ();
}
private void stopSweepTimer ()
{
if (_sweepTimer.Enabled)
_sweepTimer.Stop ();
}
#endregion #endregion
#region Internal Methods #region Internal Methods
@ -287,7 +244,7 @@ namespace WebSocketSharp.Server
{ {
lock (_sync) lock (_sync)
{ {
if (_stopped) if (_state != ServerState.START)
return null; return null;
var id = createID (); var id = createID ();
@ -299,25 +256,42 @@ namespace WebSocketSharp.Server
internal void BroadcastInternally (byte [] data) internal void BroadcastInternally (byte [] data)
{ {
if (_stopped) var services = ServiceInstances.GetEnumerator ();
broadcast (data); Action completed = null;
else completed = () =>
broadcastAsync (data); {
if (_state == ServerState.START && services.MoveNext ())
services.Current.SendAsync (data, completed);
};
if (_state == ServerState.START && services.MoveNext ())
services.Current.SendAsync (data, completed);
} }
internal void BroadcastInternally (string data) internal void BroadcastInternally (string data)
{ {
if (_stopped) var services = ServiceInstances.GetEnumerator ();
broadcast (data); Action completed = null;
else completed = () =>
broadcastAsync (data); {
if (_state == ServerState.START && services.MoveNext ())
services.Current.SendAsync (data, completed);
};
if (_state == ServerState.START && services.MoveNext ())
services.Current.SendAsync (data, completed);
} }
internal Dictionary<string, bool> BroadpingInternally (byte [] data) internal Dictionary<string, bool> BroadpingInternally (byte [] data)
{ {
var result = new Dictionary<string, bool> (); var result = new Dictionary<string, bool> ();
foreach (var session in ServiceInstances) foreach (var session in ServiceInstances)
{
if (_state != ServerState.START)
break;
result.Add (session.ID, session.Context.WebSocket.Ping (data)); result.Add (session.ID, session.Context.WebSocket.Ping (data));
}
return result; return result;
} }
@ -330,31 +304,37 @@ namespace WebSocketSharp.Server
} }
} }
internal void Start ()
{
_sweepTimer.Enabled = _keepClean;
_state = ServerState.START;
}
internal void Stop () internal void Stop ()
{ {
stopSweepTimer ();
lock (_sync) lock (_sync)
{ {
if (_stopped) _state = ServerState.SHUTDOWN;
return;
_stopped = true; _sweepTimer.Enabled = false;
foreach (var session in ServiceInstances) foreach (var session in _sessions.Values.ToList ())
session.Context.WebSocket.Close (); session.Context.WebSocket.Close ();
_state = ServerState.STOP;
} }
} }
internal void Stop (byte [] data) internal void Stop (byte [] data)
{ {
stopSweepTimer ();
lock (_sync) lock (_sync)
{ {
if (_stopped) _state = ServerState.SHUTDOWN;
return;
_stopped = true; _sweepTimer.Enabled = false;
foreach (var session in ServiceInstances) foreach (var session in _sessions.Values.ToList ())
session.Context.WebSocket.Close (data); session.Context.WebSocket.Close (data);
_state = ServerState.STOP;
} }
} }
@ -378,7 +358,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public void Broadcast (byte [] data) public void Broadcast (byte [] data)
{ {
var msg = data.CheckIfValidSendData (); var msg = _state.CheckIfStarted () ?? data.CheckIfValidSendData ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -396,7 +376,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public void Broadcast (string data) public void Broadcast (string data)
{ {
var msg = data.CheckIfValidSendData (); var msg = _state.CheckIfStarted () ?? data.CheckIfValidSendData ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -415,6 +395,13 @@ namespace WebSocketSharp.Server
/// </returns> /// </returns>
public Dictionary<string, bool> Broadping () public Dictionary<string, bool> Broadping ()
{ {
var msg = _state.CheckIfStarted ();
if (msg != null)
{
_logger.Error (msg);
return null;
}
return BroadpingInternally (new byte [] {}); return BroadpingInternally (new byte [] {});
} }
@ -431,10 +418,10 @@ namespace WebSocketSharp.Server
public Dictionary<string, bool> Broadping (string message) public Dictionary<string, bool> Broadping (string message)
{ {
if (message == null || message.Length == 0) if (message == null || message.Length == 0)
return BroadpingInternally (new byte [] {}); return Broadping ();
var data = Encoding.UTF8.GetBytes (message); var data = Encoding.UTF8.GetBytes (message);
var msg = data.CheckIfValidPingData (); var msg = _state.CheckIfStarted () ?? data.CheckIfValidPingData ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -452,7 +439,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public void CloseSession (string id) public void CloseSession (string id)
{ {
var msg = id.CheckIfValidSessionID (); var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -484,7 +471,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public void CloseSession (ushort code, string reason, string id) public void CloseSession (ushort code, string reason, string id)
{ {
var msg = id.CheckIfValidSessionID (); var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -516,7 +503,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public void CloseSession (CloseStatusCode code, string reason, string id) public void CloseSession (CloseStatusCode code, string reason, string id)
{ {
var msg = id.CheckIfValidSessionID (); var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -545,7 +532,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public bool PingTo (string id) public bool PingTo (string id)
{ {
var msg = id.CheckIfValidSessionID (); var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -578,7 +565,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public bool PingTo (string message, string id) public bool PingTo (string message, string id)
{ {
var msg = id.CheckIfValidSessionID (); var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -610,7 +597,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public bool SendTo (byte [] data, string id) public bool SendTo (byte [] data, string id)
{ {
var msg = id.CheckIfValidSessionID (); var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -643,7 +630,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public bool SendTo (string data, string id) public bool SendTo (string data, string id)
{ {
var msg = id.CheckIfValidSessionID (); var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);
@ -666,7 +653,7 @@ namespace WebSocketSharp.Server
/// </summary> /// </summary>
public void Sweep () public void Sweep ()
{ {
if (_stopped || _sweeping || Count == 0) if (_state != ServerState.START || _sweeping || Count == 0)
return; return;
lock (_forSweep) lock (_forSweep)
@ -674,11 +661,11 @@ namespace WebSocketSharp.Server
_sweeping = true; _sweeping = true;
foreach (var id in InactiveIDs) foreach (var id in InactiveIDs)
{ {
lock (_sync) if (_state != ServerState.START)
{
if (_stopped)
break; break;
lock (_sync)
{
WebSocketService session; WebSocketService session;
if (_sessions.TryGetValue (id, out session)) if (_sessions.TryGetValue (id, out session))
{ {
@ -714,7 +701,7 @@ namespace WebSocketSharp.Server
/// </param> /// </param>
public bool TryGetSession (string id, out IWebSocketSession session) public bool TryGetSession (string id, out IWebSocketSession session)
{ {
var msg = id.CheckIfValidSessionID (); var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID ();
if (msg != null) if (msg != null)
{ {
_logger.Error (msg); _logger.Error (msg);

View File

@ -129,6 +129,7 @@
<Compile Include="WebSocketState.cs" /> <Compile Include="WebSocketState.cs" />
<Compile Include="Server\IWebSocketSession.cs" /> <Compile Include="Server\IWebSocketSession.cs" />
<Compile Include="Server\WebSocketSessionManager.cs" /> <Compile Include="Server\WebSocketSessionManager.cs" />
<Compile Include="Server\ServerState.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>