diff --git a/Example3/Example3.csproj b/Example3/Example3.csproj
index cfb81b7b..ce4fe265 100644
--- a/Example3/Example3.csproj
+++ b/Example3/Example3.csproj
@@ -8,7 +8,7 @@
{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}
Exe
Example3
- Example3
+ example3
v3.5
diff --git a/websocket-sharp/Ext.cs b/websocket-sharp/Ext.cs
index 34a87f29..7f6aa368 100644
--- a/websocket-sharp/Ext.cs
+++ b/websocket-sharp/Ext.cs
@@ -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
diff --git a/websocket-sharp/Server/HttpServer.cs b/websocket-sharp/Server/HttpServer.cs
index 7269f7fb..69d9fbc2 100644
--- a/websocket-sharp/Server/HttpServer.cs
+++ b/websocket-sharp/Server/HttpServer.cs
@@ -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
///
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;
+ }
}
///
@@ -576,13 +605,22 @@ namespace WebSocketSharp.Server
///
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;
}
///
@@ -597,17 +635,26 @@ namespace WebSocketSharp.Server
///
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;
}
///
@@ -615,17 +662,33 @@ namespace WebSocketSharp.Server
/// and used to stop the WebSocket services.
///
///
- /// A that contains a status code indicating the reason for stop.
+ /// One of the values that represent the status codes indicating
+ /// the reasons for stop.
///
///
/// A that contains the reason for stop.
///
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
diff --git a/websocket-sharp/Server/ServerState.cs b/websocket-sharp/Server/ServerState.cs
new file mode 100644
index 00000000..1a4b9254
--- /dev/null
+++ b/websocket-sharp/Server/ServerState.cs
@@ -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
+ }
+}
diff --git a/websocket-sharp/Server/WebSocketServer.cs b/websocket-sharp/Server/WebSocketServer.cs
index 0c44bde5..bd86ebe4 100644
--- a/websocket-sharp/Server/WebSocketServer.cs
+++ b/websocket-sharp/Server/WebSocketServer.cs
@@ -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 ();
}
///
@@ -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)
+ ///
+ /// Aborts receiving the WebSocket connection requests.
+ ///
+ ///
+ /// This method is called when an exception occurs while receiving the WebSocket connection requests.
+ ///
+ 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
-
///
/// Accepts a WebSocket connection request.
///
@@ -301,13 +311,54 @@ namespace WebSocketSharp.Server
return _serviceHosts.Remove (servicePath);
}
+ ///
+ /// Starts to receive the WebSocket connection requests.
+ ///
+ 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;
+ }
+ }
+
///
/// Stops receiving the WebSocket connection requests.
///
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;
}
///
@@ -322,14 +373,26 @@ namespace WebSocketSharp.Server
///
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;
}
///
@@ -337,14 +400,33 @@ namespace WebSocketSharp.Server
/// and .
///
///
- /// A that contains a status code indicating the reason for stop.
+ /// One of the values that represent the status codes indicating
+ /// the reasons for stop.
///
///
/// A that contains the reason for stop.
///
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
diff --git a/websocket-sharp/Server/WebSocketServerBase.cs b/websocket-sharp/Server/WebSocketServerBase.cs
index 711347f7..1901ba54 100644
--- a/websocket-sharp/Server/WebSocketServerBase.cs
+++ b/websocket-sharp/Server/WebSocketServerBase.cs
@@ -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
+ ///
+ /// Aborts receiving the WebSocket connection requests.
+ ///
+ ///
+ /// This method is called when an exception occurs while receiving the WebSocket connection requests.
+ ///
+ protected abstract void Abort ();
+
///
/// Accepts a WebSocket connection request.
///
@@ -400,6 +411,18 @@ namespace WebSocketSharp.Server
///
protected abstract void AcceptWebSocket (TcpListenerWebSocketContext context);
+ ///
+ /// Stops the inner used to receive the WebSocket connection requests.
+ ///
+ 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
diff --git a/websocket-sharp/Server/WebSocketServiceHost.cs b/websocket-sharp/Server/WebSocketServiceHost.cs
index c0680da7..1a6fb525 100644
--- a/websocket-sharp/Server/WebSocketServiceHost.cs
+++ b/websocket-sharp/Server/WebSocketServiceHost.cs
@@ -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 ();
}
///
@@ -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)
+ ///
+ /// Aborts receiving the WebSocket connection requests.
+ ///
+ ///
+ /// This method is called when an exception occurs while receiving the WebSocket connection requests.
+ ///
+ 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
-
///
/// Accepts a WebSocket connection request.
///
@@ -315,13 +327,54 @@ namespace WebSocketSharp.Server
#region Public Methods
+ ///
+ /// Starts to receive the WebSocket connection requests.
+ ///
+ 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;
+ }
+ }
+
///
/// Stops receiving the WebSocket connection requests.
///
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;
}
///
@@ -336,14 +389,26 @@ namespace WebSocketSharp.Server
///
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;
}
///
@@ -351,14 +416,33 @@ namespace WebSocketSharp.Server
/// and .
///
///
- /// A that contains a status code indicating the reason for stop.
+ /// One of the values that represent the status codes indicating
+ /// the reasons for stop.
///
///
/// A that contains the reason for stop.
///
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
diff --git a/websocket-sharp/Server/WebSocketServiceHostManager.cs b/websocket-sharp/Server/WebSocketServiceHostManager.cs
index 95ab6e96..56b4be4f 100644
--- a/websocket-sharp/Server/WebSocketServiceHostManager.cs
+++ b/websocket-sharp/Server/WebSocketServiceHostManager.cs
@@ -45,6 +45,7 @@ namespace WebSocketSharp.Server
private volatile bool _keepClean;
private Logger _logger;
private Dictionary _serviceHosts;
+ private volatile ServerState _state;
private object _sync;
#endregion
@@ -61,6 +62,7 @@ namespace WebSocketSharp.Server
_logger = logger;
_keepClean = true;
_serviceHosts = new Dictionary ();
+ _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> ();
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
///
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);
+ }
}
///
@@ -302,7 +339,7 @@ namespace WebSocketSharp.Server
///
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);
+ }
}
///
@@ -328,7 +370,7 @@ namespace WebSocketSharp.Server
///
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
///
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
///
public Dictionary> 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> 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
///
public Dictionary 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
///
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
///
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
///
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
///
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
///
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
///
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
///
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
///
public bool TryGetServiceHost (string servicePath, out IWebSocketServiceHost serviceHost)
{
- var msg = servicePath.CheckIfValidServicePath ();
+ var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error (msg);
diff --git a/websocket-sharp/Server/WebSocketSessionManager.cs b/websocket-sharp/Server/WebSocketSessionManager.cs
index 30135d53..713c2f82 100644
--- a/websocket-sharp/Server/WebSocketSessionManager.cs
+++ b/websocket-sharp/Server/WebSocketSessionManager.cs
@@ -42,9 +42,10 @@ namespace WebSocketSharp.Server
#region Private Fields
private object _forSweep;
+ private volatile bool _keepClean;
private Logger _logger;
private Dictionary _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 ();
- _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 ServiceInstances {
get {
+ if (_state != ServerState.START)
+ return new List ();
+
lock (_sync)
{
return _sessions.Values.ToList ();
@@ -158,7 +168,7 @@ namespace WebSocketSharp.Server
///
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
///
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 BroadpingInternally (byte [] data)
{
var result = new Dictionary ();
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
///
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
///
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
///
public Dictionary 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 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
///
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
///
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
///
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
///
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
///
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
///
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
///
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
///
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
///
public bool TryGetSession (string id, out IWebSocketSession session)
{
- var msg = id.CheckIfValidSessionID ();
+ var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID ();
if (msg != null)
{
_logger.Error (msg);
diff --git a/websocket-sharp/websocket-sharp.csproj b/websocket-sharp/websocket-sharp.csproj
index 0774bf83..13553bcf 100644
--- a/websocket-sharp/websocket-sharp.csproj
+++ b/websocket-sharp/websocket-sharp.csproj
@@ -129,6 +129,7 @@
+