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>
<OutputType>Exe</OutputType>
<RootNamespace>Example3</RootNamespace>
<AssemblyName>Example3</AssemblyName>
<AssemblyName>example3</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

View File

@ -49,6 +49,7 @@ using System.Security.Cryptography.X509Certificates;
using System.Text;
using WebSocketSharp.Net;
using WebSocketSharp.Net.WebSockets;
using WebSocketSharp.Server;
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)
{
return data.Length > 125

View File

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

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
private WebSocketServiceHostManager _serviceHosts;
private volatile ServerState _state;
private object _sync;
#endregion
@ -87,6 +89,8 @@ namespace WebSocketSharp.Server
throw new ArgumentException ("Must not contain the path component: " + url, "url");
_serviceHosts = new WebSocketServiceHostManager (Log);
_state = ServerState.READY;
_sync = new object ();
}
/// <summary>
@ -139,6 +143,8 @@ namespace WebSocketSharp.Server
: base (address, port, "/", secure)
{
_serviceHosts = new WebSocketServiceHostManager (Log);
_state = ServerState.READY;
_sync = new object ();
}
#endregion
@ -193,26 +199,30 @@ namespace WebSocketSharp.Server
#endregion
#region Private Methods
#region Protected Methods
private void stop (ushort code, string reason)
/// <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 ()
{
var data = code.Append (reason);
var msg = data.CheckIfValidCloseData ();
if (msg != null)
lock (_sync)
{
Log.Error (String.Format ("{0}\ncode: {1}\nreason: {2}", msg, code, reason));
return;
if (_state != ServerState.START)
return;
_state = ServerState.SHUTDOWN;
}
base.Stop ();
_serviceHosts.Stop (data);
StopListener ();
_serviceHosts.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG));
_state = ServerState.STOP;
}
#endregion
#region Protected Methods
/// <summary>
/// Accepts a WebSocket connection request.
/// </summary>
@ -301,13 +311,54 @@ namespace WebSocketSharp.Server
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>
/// Stops receiving the WebSocket connection requests.
/// </summary>
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 ();
_serviceHosts.Stop ();
_state = ServerState.STOP;
}
/// <summary>
@ -322,14 +373,26 @@ namespace WebSocketSharp.Server
/// </param>
public void Stop (ushort code, string reason)
{
var msg = code.CheckIfValidCloseStatusCode ();
if (msg != null)
byte [] data = null;
lock (_sync)
{
Log.Error (String.Format ("{0}\ncode: {1}", msg, code));
return;
var msg = _state.CheckIfStarted () ??
code.CheckIfValidCloseStatusCode () ??
(data = code.Append (reason)).CheckIfValidCloseData ();
if (msg != null)
{
Log.Error (String.Format ("{0}\nstate: {1}\ncode: {2}\nreason: {3}", msg, _state, code, reason));
return;
}
_state = ServerState.SHUTDOWN;
}
stop (code, reason);
base.Stop ();
_serviceHosts.Stop (data);
_state = ServerState.STOP;
}
/// <summary>
@ -337,14 +400,33 @@ namespace WebSocketSharp.Server
/// and <see cref="string"/>.
/// </summary>
/// <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 name="reason">
/// A <see cref="string"/> that contains the reason for stop.
/// </param>
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

View File

@ -48,7 +48,7 @@ namespace WebSocketSharp.Server
private IPAddress _address;
private X509Certificate2 _cert;
private bool _listening;
private volatile bool _listening;
private Logger _logger;
private int _port;
private Thread _receiveRequestThread;
@ -339,8 +339,8 @@ namespace WebSocketSharp.Server
}
catch (Exception ex)
{
_logger.Fatal (ex.ToString ());
client.Close ();
_logger.Fatal (ex.Message);
}
};
@ -354,15 +354,18 @@ namespace WebSocketSharp.Server
try {
processRequestAsync (_listener.AcceptTcpClient ());
}
catch (SocketException) {
_logger.Info ("TcpListener has been stopped.");
catch (SocketException ex) {
_logger.Warn (String.Format ("Receiving has been stopped.\nreason: {0}.", ex.Message));
break;
}
catch (Exception ex) {
_logger.Fatal (ex.Message);
_logger.Fatal (ex.ToString ());
break;
}
}
if (_listening)
Abort ();
}
private void startReceiveRequestThread ()
@ -392,6 +395,14 @@ namespace WebSocketSharp.Server
#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>
/// Accepts a WebSocket connection request.
/// </summary>
@ -400,6 +411,18 @@ namespace WebSocketSharp.Server
/// </param>
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
#region Public Methods
@ -414,7 +437,7 @@ namespace WebSocketSharp.Server
if (_secure && _cert == null)
{
_logger.Error ("Secure connection requires a server certificate.");
_logger.Error ("The secure connection requires a server certificate.");
return;
}
@ -431,9 +454,9 @@ namespace WebSocketSharp.Server
if (!_selfHost || !_listening)
return;
_listening = false;
_listener.Stop ();
_receiveRequestThread.Join (5 * 1000);
_listening = false;
}
#endregion

View File

@ -54,6 +54,8 @@ namespace WebSocketSharp.Server
private string _servicePath;
private WebSocketSessionManager _sessions;
private volatile ServerState _state;
private object _sync;
#endregion
@ -63,6 +65,8 @@ namespace WebSocketSharp.Server
: base (logger)
{
_sessions = new WebSocketSessionManager (logger);
_state = ServerState.READY;
_sync = new object ();
}
#endregion
@ -92,6 +96,8 @@ namespace WebSocketSharp.Server
: base (url)
{
_sessions = new WebSocketSessionManager (Log);
_state = ServerState.READY;
_sync = new object ();
}
/// <summary>
@ -186,6 +192,8 @@ namespace WebSocketSharp.Server
: base (address, port, servicePath, secure)
{
_sessions = new WebSocketSessionManager (Log);
_state = ServerState.READY;
_sync = new object ();
}
#endregion
@ -267,26 +275,30 @@ namespace WebSocketSharp.Server
#endregion
#region Private Methods
#region Protected Methods
private void stop (ushort code, string reason)
/// <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 ()
{
var data = code.Append (reason);
var msg = data.CheckIfValidCloseData ();
if (msg != null)
lock (_sync)
{
Log.Error (String.Format ("{0}\ncode: {1}\nreason: {2}", msg, code, reason));
return;
if (_state != ServerState.START)
return;
_state = ServerState.SHUTDOWN;
}
base.Stop ();
_sessions.Stop (data);
StopListener ();
_sessions.Stop (((ushort) CloseStatusCode.SERVER_ERROR).ToByteArray (ByteOrder.BIG));
_state = ServerState.STOP;
}
#endregion
#region Protected Methods
/// <summary>
/// Accepts a WebSocket connection request.
/// </summary>
@ -315,13 +327,54 @@ namespace WebSocketSharp.Server
#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>
/// Stops receiving the WebSocket connection requests.
/// </summary>
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 ();
_sessions.Stop ();
_state = ServerState.STOP;
}
/// <summary>
@ -336,14 +389,26 @@ namespace WebSocketSharp.Server
/// </param>
public void Stop (ushort code, string reason)
{
var msg = code.CheckIfValidCloseStatusCode ();
if (msg != null)
byte [] data = null;
lock (_sync)
{
Log.Error (String.Format ("{0}\ncode: {1}", msg, code));
return;
var msg = _state.CheckIfStarted () ??
code.CheckIfValidCloseStatusCode () ??
(data = code.Append (reason)).CheckIfValidCloseData ();
if (msg != null)
{
Log.Error (String.Format ("{0}\nstate: {1}\ncode: {2}\nreason: {3}", msg, _state, code, reason));
return;
}
_state = ServerState.SHUTDOWN;
}
stop (code, reason);
base.Stop ();
_sessions.Stop (data);
_state = ServerState.STOP;
}
/// <summary>
@ -351,14 +416,33 @@ namespace WebSocketSharp.Server
/// and <see cref="string"/>.
/// </summary>
/// <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 name="reason">
/// A <see cref="string"/> that contains the reason for stop.
/// </param>
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

View File

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

View File

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

View File

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