From cbf73e98652d5702f1701a996b70360146f673a4 Mon Sep 17 00:00:00 2001 From: sta Date: Mon, 14 Oct 2013 20:38:15 +0900 Subject: [PATCH] Modified WebSocketServer.cs and removed WebSocketServerBase.cs --- Example2/Program.cs | 16 +- Example3/Program.cs | 12 +- websocket-sharp/Ext.cs | 176 +++---- websocket-sharp/Server/HttpServer.cs | 78 ++- websocket-sharp/Server/WebSocketServer.cs | 322 +++++++++--- websocket-sharp/Server/WebSocketServerBase.cs | 464 ------------------ websocket-sharp/WebSocket.cs | 10 +- websocket-sharp/websocket-sharp.csproj | 1 - 8 files changed, 411 insertions(+), 668 deletions(-) delete mode 100644 websocket-sharp/Server/WebSocketServerBase.cs diff --git a/Example2/Program.cs b/Example2/Program.cs index 8ee167aa..5aad0e28 100644 --- a/Example2/Program.cs +++ b/Example2/Program.cs @@ -17,9 +17,9 @@ namespace Example2 #if DEBUG wssv.Log.Level = LogLevel.TRACE; #endif - //var file = ConfigurationManager.AppSettings ["ServerCertFile"]; + //var cert = ConfigurationManager.AppSettings ["ServerCertFile"]; //var password = ConfigurationManager.AppSettings ["CertFilePassword"]; - //wssv.Certificate = new X509Certificate2 (file, password); + //wssv.Certificate = new X509Certificate2 (cert, password); //wssv.KeepClean = false; wssv.AddWebSocketService ("/Echo"); wssv.AddWebSocketService ("/Chat"); @@ -28,10 +28,14 @@ namespace Example2 //wssv.AddWebSocketService ("/チャット"); wssv.Start (); - Console.WriteLine ( - "A WebSocket Server listening on port: {0} service path:", wssv.Port); - foreach (var path in wssv.WebSocketServices.ServicePaths) - Console.WriteLine (" {0}", path); + if (wssv.IsListening) + { + Console.WriteLine ( + "A WebSocket Server listening on port: {0} service paths:", wssv.Port); + + foreach (var path in wssv.WebSocketServices.ServicePaths) + Console.WriteLine (" {0}", path); + } Console.WriteLine ("\nPress Enter key to stop server..."); Console.ReadLine (); diff --git a/Example3/Program.cs b/Example3/Program.cs index deec975d..99f78b48 100644 --- a/Example3/Program.cs +++ b/Example3/Program.cs @@ -19,9 +19,9 @@ namespace Example3 _httpsv.Log.Level = LogLevel.TRACE; #endif _httpsv.RootPath = ConfigurationManager.AppSettings ["RootPath"]; - //var certFile = ConfigurationManager.AppSettings ["ServerCertFile"]; + //var cert = ConfigurationManager.AppSettings ["ServerCertFile"]; //var password = ConfigurationManager.AppSettings ["CertFilePassword"]; - //_httpsv.Certificate = new X509Certificate2 (certFile, password); + //_httpsv.Certificate = new X509Certificate2 (cert, password); //_httpsv.KeepClean = false; _httpsv.AddWebSocketService ("/Echo"); _httpsv.AddWebSocketService ("/Chat"); @@ -35,14 +35,14 @@ namespace Example3 _httpsv.Start (); if (_httpsv.IsListening) { - Console.WriteLine ("An HTTP Server listening on port: {0} service path:", _httpsv.Port); + Console.WriteLine ( + "An HTTP Server listening on port: {0} WebSocket service paths:", _httpsv.Port); + foreach (var path in _httpsv.WebSocketServices.ServicePaths) Console.WriteLine (" {0}", path); - - Console.WriteLine (); } - Console.WriteLine ("Press Enter key to stop the server..."); + Console.WriteLine ("\nPress Enter key to stop the server..."); Console.ReadLine (); _httpsv.Stop (); diff --git a/websocket-sharp/Ext.cs b/websocket-sharp/Ext.cs index 36914e5c..cd7c1692 100644 --- a/websocket-sharp/Ext.cs +++ b/websocket-sharp/Ext.cs @@ -657,6 +657,17 @@ namespace WebSocketSharp return CompressionMethod.NONE; } + internal static System.Net.IPAddress ToIPAddress (this string hostNameOrAddress) + { + try { + var addrs = System.Net.Dns.GetHostAddresses (hostNameOrAddress); + return addrs [0]; + } + catch { + return null; + } + } + internal static ushort ToUInt16 (this byte [] src, ByteOrder srcOrder) { return BitConverter.ToUInt16 (src.ToHostOrder (srcOrder), 0); @@ -675,6 +686,81 @@ namespace WebSocketSharp : "/"; } + /// + /// Tries to create a for WebSocket with the specified . + /// + /// + /// true if the is successfully created; otherwise, false. + /// + /// + /// A that contains a WebSocket URL to try. + /// + /// + /// When this method returns, a that represents the WebSocket URL + /// if is valid; otherwise, . + /// + /// + /// When this method returns, a that contains an error message + /// if is invalid; otherwise, String.Empty. + /// + internal static bool TryCreateWebSocketUri (this string uriString, out Uri result, out string message) + { + result = null; + if (uriString.Length == 0) + { + message = "Must not be empty."; + return false; + } + + var uri = uriString.ToUri (); + if (!uri.IsAbsoluteUri) + { + message = "Must be the absolute URI: " + uriString; + return false; + } + + var scheme = uri.Scheme; + if (scheme != "ws" && scheme != "wss") + { + message = "The scheme part must be 'ws' or 'wss': " + scheme; + return false; + } + + var fragment = uri.Fragment; + if (fragment.Length != 0) + { + message = "Must not contain the fragment component: " + uriString; + return false; + } + + var port = uri.Port; + if (port > 0) + { + if (port > 65535) + { + message = "The port part must be between 1 and 65535: " + port; + return false; + } + + if ((scheme == "ws" && port == 443) || (scheme == "wss" && port == 80)) + { + message = String.Format ("Invalid pair of scheme and port: {0}, {1}", scheme, port); + return false; + } + } + else + { + port = scheme == "ws" ? 80 : 443; + var url = String.Format ("{0}://{1}:{2}{3}", scheme, uri.Host, port, uri.PathAndQuery); + uri = url.ToUri (); + } + + result = uri; + message = String.Empty; + + return true; + } + internal static string Unquote (this string value) { var start = value.IndexOf ('\"'); @@ -1048,10 +1134,12 @@ namespace WebSocketSharp } /// - /// Determines whether the specified represents a local IP address. + /// Determines whether the specified represents + /// the local IP address. /// /// - /// true if represents a local IP address; otherwise, false. + /// true if represents the local IP address; + /// otherwise, false. /// /// /// A to test. @@ -1064,7 +1152,8 @@ namespace WebSocketSharp if (address == null) throw new ArgumentNullException ("address"); - if (System.Net.IPAddress.IsLoopback (address)) + if (address.Equals (System.Net.IPAddress.Any) || + System.Net.IPAddress.IsLoopback (address)) return true; var host = System.Net.Dns.GetHostName (); @@ -1549,87 +1638,6 @@ namespace WebSocketSharp : new Uri (uriString, UriKind.Relative); } - /// - /// Tries to create a new WebSocket with the specified . - /// - /// - /// true if a WebSocket is successfully created; otherwise, false. - /// - /// - /// A that contains a WebSocket URI. - /// - /// - /// When this method returns, contains a created WebSocket - /// if is valid WebSocket URI; otherwise, . - /// - /// - /// When this method returns, contains a error message - /// if is invalid WebSocket URI; otherwise, String.Empty. - /// - /// - /// is . - /// - public static bool TryCreateWebSocketUri (this string uriString, out Uri result, out string message) - { - if (uriString == null) - throw new ArgumentNullException ("uriString"); - - result = null; - if (uriString.Length == 0) - { - message = "Must not be empty."; - return false; - } - - var uri = uriString.ToUri (); - if (!uri.IsAbsoluteUri) - { - message = "Not absolute URI: " + uriString; - return false; - } - - var scheme = uri.Scheme; - if (scheme != "ws" && scheme != "wss") - { - message = "Unsupported scheme: " + scheme; - return false; - } - - var fragment = uri.Fragment; - if (fragment != null && fragment.Length != 0) - { - message = "Must not contain the fragment component: " + uriString; - return false; - } - - var port = uri.Port; - if (port > 0) - { - if (port > 65535) - { - message = "Invalid port number: " + port; - return false; - } - - if ((scheme == "ws" && port == 443) || (scheme == "wss" && port == 80)) - { - message = String.Format ("Invalid pair of scheme and port: {0}, {1}", scheme, port); - return false; - } - } - else - { - port = scheme == "ws" ? 80 : 443; - var url = String.Format ("{0}://{1}:{2}{3}", scheme, uri.Host, port, uri.PathAndQuery); - uri = url.ToUri (); - } - - result = uri; - message = String.Empty; - - return true; - } - /// /// URL-decodes the specified . /// diff --git a/websocket-sharp/Server/HttpServer.cs b/websocket-sharp/Server/HttpServer.cs index 2ccd1a81..6e23bc7b 100644 --- a/websocket-sharp/Server/HttpServer.cs +++ b/websocket-sharp/Server/HttpServer.cs @@ -56,7 +56,6 @@ namespace WebSocketSharp.Server #region Private Fields private HttpListener _listener; - private volatile bool _listening; private Logger _logger; private int _port; private Thread _receiveRequestThread; @@ -72,8 +71,8 @@ namespace WebSocketSharp.Server #region Public Constructors /// - /// Initializes a new instance of the class that listens for incoming requests - /// on port 80. + /// Initializes a new instance of the class that listens for + /// incoming requests on port 80. /// public HttpServer () : this (80) @@ -81,14 +80,14 @@ namespace WebSocketSharp.Server } /// - /// Initializes a new instance of the class that listens for incoming requests - /// on the specified . + /// Initializes a new instance of the class that listens for + /// incoming requests on the specified . /// /// - /// An that contains a port number. + /// An that contains a port number. /// /// - /// is 0 or less, or 65536 or greater. + /// is not between 1 and 65535. /// public HttpServer (int port) : this (port, port == 443 ? true : false) @@ -96,18 +95,18 @@ namespace WebSocketSharp.Server } /// - /// Initializes a new instance of the class that listens for incoming requests - /// on the specified and . + /// Initializes a new instance of the class that listens for + /// incoming requests on the specified and . /// /// - /// An that contains a port number. + /// An that contains a port number. /// /// /// A that indicates providing a secure connection or not. /// (true indicates providing a secure connection.) /// /// - /// is 0 or less, or 65536 or greater. + /// is not between 1 and 65535. /// /// /// Pair of and is invalid. @@ -115,7 +114,7 @@ namespace WebSocketSharp.Server public HttpServer (int port, bool secure) { if (!port.IsPortNumber ()) - throw new ArgumentOutOfRangeException ("port", "Invalid port number: " + port); + throw new ArgumentOutOfRangeException ("port", "Must be between 1 and 65535: " + port); if ((port == 80 && secure) || (port == 443 && !secure)) throw new ArgumentException (String.Format ( @@ -143,15 +142,16 @@ namespace WebSocketSharp.Server } set { - if (_listening) + if (_state == ServerState.START || _state == ServerState.SHUTDOWN) { _logger.Error ( "The value of Certificate property cannot be changed because the server has already been started."); + return; } if (EndPointListener.CertificateExists (_port, _listener.CertificateFolderPath)) - _logger.Warn ("Server certificate associated with the port number already exists."); + _logger.Warn ("The server certificate associated with the port number already exists."); _listener.DefaultCertificate = value; } @@ -165,7 +165,7 @@ namespace WebSocketSharp.Server /// public bool IsListening { get { - return _listening; + return _state == ServerState.START; } } @@ -243,10 +243,11 @@ namespace WebSocketSharp.Server } set { - if (_listening) + if (_state == ServerState.START || _state == ServerState.SHUTDOWN) { _logger.Error ( "The value of RootPath property cannot be changed because the server has already been started."); + return; } @@ -323,13 +324,12 @@ namespace WebSocketSharp.Server { lock (_sync) { - if (_state != ServerState.START) + if (!IsListening) return; _state = ServerState.SHUTDOWN; } - _listening = false; _serviceHosts.Stop ( ((ushort) CloseStatusCode.SERVER_ERROR).ToByteArrayInternally (ByteOrder.BIG), true); _listener.Abort (); @@ -349,7 +349,6 @@ namespace WebSocketSharp.Server private void init () { _listener = new HttpListener (); - _listening = false; _logger = new Logger (); _serviceHosts = new WebSocketServiceHostManager (_logger); _state = ServerState.READY; @@ -366,59 +365,59 @@ namespace WebSocketSharp.Server private void processHttpRequest (HttpListenerContext context) { - var eventArgs = new HttpRequestEventArgs (context); + var args = new HttpRequestEventArgs (context); var method = context.Request.HttpMethod; if (method == "GET" && OnGet != null) { - OnGet (this, eventArgs); + OnGet (this, args); return; } if (method == "HEAD" && OnHead != null) { - OnHead (this, eventArgs); + OnHead (this, args); return; } if (method == "POST" && OnPost != null) { - OnPost (this, eventArgs); + OnPost (this, args); return; } if (method == "PUT" && OnPut != null) { - OnPut (this, eventArgs); + OnPut (this, args); return; } if (method == "DELETE" && OnDelete != null) { - OnDelete (this, eventArgs); + OnDelete (this, args); return; } if (method == "OPTIONS" && OnOptions != null) { - OnOptions (this, eventArgs); + OnOptions (this, args); return; } if (method == "TRACE" && OnTrace != null) { - OnTrace (this, eventArgs); + OnTrace (this, args); return; } if (method == "CONNECT" && OnConnect != null) { - OnConnect (this, eventArgs); + OnConnect (this, args); return; } if (method == "PATCH" && OnPatch != null) { - OnPatch (this, eventArgs); + OnPatch (this, args); return; } @@ -486,7 +485,7 @@ namespace WebSocketSharp.Server } } - if (_listening) + if (IsListening) abort (); } @@ -497,14 +496,10 @@ namespace WebSocketSharp.Server _receiveRequestThread.Start (); } - private void stopListener () + private void stopListener (int timeOut) { - if (!_listening) - return; - - _listening = false; _listener.Close (); - _receiveRequestThread.Join (5 * 1000); + _receiveRequestThread.Join (timeOut); } #endregion @@ -637,7 +632,6 @@ namespace WebSocketSharp.Server _serviceHosts.Start (); _listener.Start (); startReceiveRequestThread (); - _listening = true; _state = ServerState.START; } @@ -661,7 +655,7 @@ namespace WebSocketSharp.Server } _serviceHosts.Stop (new byte []{}, true); - stopListener (); + stopListener (5000); _state = ServerState.STOP; } @@ -687,7 +681,9 @@ namespace WebSocketSharp.Server if (msg != null) { - _logger.Error (String.Format ("{0}\nstate: {1}\ncode: {2}\nreason: {3}", msg, _state, code, reason)); + _logger.Error (String.Format ( + "{0}\nstate: {1}\ncode: {2}\nreason: {3}", msg, _state, code, reason)); + return; } @@ -695,7 +691,7 @@ namespace WebSocketSharp.Server } _serviceHosts.Stop (data, !code.IsReserved ()); - stopListener (); + stopListener (5000); _state = ServerState.STOP; } @@ -729,7 +725,7 @@ namespace WebSocketSharp.Server } _serviceHosts.Stop (data, !code.IsReserved ()); - stopListener (); + stopListener (5000); _state = ServerState.STOP; } diff --git a/websocket-sharp/Server/WebSocketServer.cs b/websocket-sharp/Server/WebSocketServer.cs index 5fe8a287..4f0aa372 100644 --- a/websocket-sharp/Server/WebSocketServer.cs +++ b/websocket-sharp/Server/WebSocketServer.cs @@ -38,7 +38,9 @@ using System; using System.Collections.Generic; using System.Net.Sockets; +using System.Security.Cryptography.X509Certificates; using System.Text; +using System.Threading; using WebSocketSharp.Net; using WebSocketSharp.Net.WebSockets; @@ -50,20 +52,29 @@ namespace WebSocketSharp.Server /// /// The WebSocketServer class provides the multi WebSocket service. /// - public class WebSocketServer : WebSocketServerBase + public class WebSocketServer { #region Private Fields + private System.Net.IPAddress _address; + private X509Certificate2 _cert; + private TcpListener _listener; + private Logger _logger; + private int _port; + private Thread _receiveRequestThread; + private bool _secure; private WebSocketServiceHostManager _serviceHosts; private volatile ServerState _state; private object _sync; + private Uri _uri; #endregion #region Public Constructors /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class that listens for + /// incoming requests on port 80. /// public WebSocketServer () : this (80) @@ -78,7 +89,7 @@ namespace WebSocketSharp.Server /// An that contains a port number. /// /// - /// is 0 or less, or 65536 or greater. + /// is not between 1 and 65535. /// public WebSocketServer (int port) : this (System.Net.IPAddress.Any, port) @@ -99,14 +110,24 @@ namespace WebSocketSharp.Server /// is invalid. /// public WebSocketServer (string url) - : base (url) { - if (BaseUri.AbsolutePath != "/") - throw new ArgumentException ("Must not contain the path component: " + url, "url"); + if (url == null) + throw new ArgumentNullException ("url"); - _serviceHosts = new WebSocketServiceHostManager (Log); - _state = ServerState.READY; - _sync = new object (); + string msg; + if (!tryCreateUri (url, out _uri, out msg)) + throw new ArgumentException (msg, "url"); + + var host = _uri.DnsSafeHost; + _address = host.ToIPAddress (); + if (_address == null || !_address.IsLocal ()) + throw new ArgumentException (String.Format ( + "The host part must be the local host name: {0}", host), "url"); + + _port = _uri.Port; + _secure = _uri.Scheme == "wss" ? true : false; + + init (); } /// @@ -121,7 +142,7 @@ namespace WebSocketSharp.Server /// (true indicates providing a secure connection.) /// /// - /// is 0 or less, or 65536 or greater. + /// is not between 1 and 65535. /// /// /// Pair of and is invalid. @@ -136,7 +157,7 @@ namespace WebSocketSharp.Server /// incoming connection attempts on the specified and . /// /// - /// A that contains a local IP address. + /// A that represents the local IP address. /// /// /// An that contains a port number. @@ -145,7 +166,10 @@ namespace WebSocketSharp.Server /// is . /// /// - /// is 0 or less, or 65536 or greater. + /// is not between 1 and 65535. + /// + /// + /// is not the local IP address. /// public WebSocketServer (System.Net.IPAddress address, int port) : this (address, port, port == 443 ? true : false) @@ -158,7 +182,7 @@ namespace WebSocketSharp.Server /// and . /// /// - /// A that contains a local IP address. + /// A that represents the local IP address. /// /// /// An that contains a port number. @@ -171,23 +195,104 @@ namespace WebSocketSharp.Server /// is . /// /// - /// is 0 or less, or 65536 or greater. + /// is not between 1 and 65535. /// /// - /// Pair of and is invalid. + /// + /// is not the local IP address. + /// + /// + /// -or- + /// + /// + /// Pair of and is invalid. + /// /// public WebSocketServer (System.Net.IPAddress address, int port, bool secure) - : base (address, port, "/", secure) { - _serviceHosts = new WebSocketServiceHostManager (Log); - _state = ServerState.READY; - _sync = new object (); + if (!address.IsLocal ()) + throw new ArgumentException (String.Format ( + "Must be the local IP address: {0}", address), "address"); + + if (!port.IsPortNumber ()) + throw new ArgumentOutOfRangeException ("port", "Must be between 1 and 65535: " + port); + + if ((port == 80 && secure) || (port == 443 && !secure)) + throw new ArgumentException (String.Format ( + "Invalid pair of 'port' and 'secure': {0}, {1}", port, secure)); + + _address = address; + _port = port; + _secure = secure; + _uri = "/".ToUri (); + + init (); } #endregion #region Public Properties + /// + /// Gets the local IP address on which to listen for incoming connection attempts. + /// + /// + /// A that represents the local IP address. + /// + public System.Net.IPAddress Address { + get { + return _address; + } + } + + /// + /// Gets or sets the certificate used to authenticate the server on the secure connection. + /// + /// + /// A used to authenticate the server. + /// + public X509Certificate2 Certificate { + get { + return _cert; + } + + set { + if (_state == ServerState.START || _state == ServerState.SHUTDOWN) + { + _logger.Error ( + "The value of Certificate property cannot be changed because the server has already been started."); + + return; + } + + _cert = value; + } + } + + /// + /// Gets a value indicating whether the server has been started. + /// + /// + /// true if the server has been started; otherwise, false. + /// + public bool IsListening { + get { + return _state == ServerState.START; + } + } + + /// + /// Gets a value indicating whether the server provides secure connection. + /// + /// + /// true if the server provides secure connection; otherwise, false. + /// + public bool IsSecure { + get { + return _secure; + } + } + /// /// Gets or sets a value indicating whether the server cleans up the inactive sessions periodically. /// @@ -206,7 +311,36 @@ namespace WebSocketSharp.Server } /// - /// Gets the functions for the WebSocket services that the server provides. + /// Gets the logging functions. + /// + /// + /// The default logging level is the . + /// If you want to change the current logging level, you set the Log.Level property + /// to one of the values which you want. + /// + /// + /// A that provides the logging functions. + /// + public Logger Log { + get { + return _logger; + } + } + + /// + /// Gets the port on which to listen for incoming connection attempts. + /// + /// + /// An that contains a port number. + /// + public int Port { + get { + return _port; + } + } + + /// + /// Gets the functions for the WebSocket services provided by the server. /// /// /// A that manages the WebSocket services. @@ -219,41 +353,29 @@ namespace WebSocketSharp.Server #endregion - #region Protected Methods + #region Private Methods - /// - /// Aborts receiving the WebSocket connection requests. - /// - /// - /// This method is called when an exception occurs while receiving the WebSocket connection requests. - /// - protected override void Abort () + private void abort () { lock (_sync) { - if (_state != ServerState.START) + if (!IsListening) return; _state = ServerState.SHUTDOWN; } - StopListener (); + _listener.Stop (); _serviceHosts.Stop ( ((ushort) CloseStatusCode.SERVER_ERROR).ToByteArrayInternally (ByteOrder.BIG), true); _state = ServerState.STOP; } - /// - /// Accepts a WebSocket connection request. - /// - /// - /// A that contains the WebSocket connection request objects. - /// - protected override void AcceptWebSocket (TcpListenerWebSocketContext context) + private void acceptWebSocket (TcpListenerWebSocketContext context) { var websocket = context.WebSocket; - websocket.Log = Log; + websocket.Log = _logger; var path = context.Path; WebSocketServiceHost host; @@ -263,12 +385,95 @@ namespace WebSocketSharp.Server return; } - if (BaseUri.IsAbsoluteUri) - websocket.Url = new Uri (BaseUri, path); + if (_uri.IsAbsoluteUri) + websocket.Url = new Uri (_uri, path); host.StartSession (context); } + private string checkIfCertExists () + { + return _secure && _cert == null + ? "The secure connection requires a server certificate." + : null; + } + + private void init () + { + _listener = new TcpListener (_address, _port); + _logger = new Logger (); + _serviceHosts = new WebSocketServiceHostManager (_logger); + _state = ServerState.READY; + _sync = new object (); + } + + private void processRequestAsync (TcpClient client) + { + WaitCallback callback = state => + { + try { + acceptWebSocket (client.GetWebSocketContext (_secure, _cert)); + } + catch (Exception ex) + { + _logger.Fatal (ex.ToString ()); + client.Close (); + } + }; + + ThreadPool.QueueUserWorkItem (callback); + } + + private void receiveRequest () + { + while (true) + { + try { + processRequestAsync (_listener.AcceptTcpClient ()); + } + catch (SocketException ex) { + _logger.Warn (String.Format ("Receiving has been stopped.\nreason: {0}.", ex.Message)); + break; + } + catch (Exception ex) { + _logger.Fatal (ex.ToString ()); + break; + } + } + + if (IsListening) + abort (); + } + + private void startReceiveRequestThread () + { + _receiveRequestThread = new Thread (new ThreadStart (receiveRequest)); + _receiveRequestThread.IsBackground = true; + _receiveRequestThread.Start (); + } + + private void stopListener (int timeOut) + { + _listener.Stop (); + _receiveRequestThread.Join (timeOut); + } + + private static bool tryCreateUri (string uriString, out Uri result, out string message) + { + if (!uriString.TryCreateWebSocketUri (out result, out message)) + return false; + + if (result.PathAndQuery != "/") + { + result = null; + message = "Must not contain the path or query component: " + uriString; + + return false; + } + + return true; + } + #endregion #region Public Methods @@ -325,11 +530,11 @@ namespace WebSocketSharp.Server if (msg != null) { - Log.Error (String.Format ("{0}\nservice path: {1}", msg, servicePath ?? "")); + _logger.Error (String.Format ("{0}\nservice path: {1}", msg, servicePath ?? "")); return; } - var host = new WebSocketServiceHost (servicePath, serviceConstructor, Log); + var host = new WebSocketServiceHost (servicePath, serviceConstructor, _logger); if (!KeepClean) host.KeepClean = false; @@ -354,7 +559,7 @@ namespace WebSocketSharp.Server var msg = servicePath.CheckIfValidServicePath (); if (msg != null) { - Log.Error (String.Format ("{0}\nservice path: {1}", msg, servicePath ?? "")); + _logger.Error (String.Format ("{0}\nservice path: {1}", msg, servicePath ?? "")); return false; } @@ -364,25 +569,20 @@ namespace WebSocketSharp.Server /// /// Starts to receive the WebSocket connection requests. /// - public override void Start () + public void Start () { lock (_sync) { - var msg = _state.CheckIfStopped (); + var msg = _state.CheckIfStopped () ?? checkIfCertExists (); if (msg != null) { - Log.Error (String.Format ("{0}\nstate: {1}", msg, _state)); + _logger.Error (String.Format ("{0}\nstate: {1}\nsecure: {2}", msg, _state, _secure)); return; } _serviceHosts.Start (); - - base.Start (); - if (!IsListening) - { - _serviceHosts.Stop (new byte []{}, false); - return; - } + _listener.Start (); + startReceiveRequestThread (); _state = ServerState.START; } @@ -391,21 +591,21 @@ namespace WebSocketSharp.Server /// /// Stops receiving the WebSocket connection requests. /// - public override void Stop () + public void Stop () { lock (_sync) { var msg = _state.CheckIfStarted (); if (msg != null) { - Log.Error (String.Format ("{0}\nstate: {1}", msg, _state)); + _logger.Error (String.Format ("{0}\nstate: {1}", msg, _state)); return; } _state = ServerState.SHUTDOWN; } - base.Stop (); + stopListener (5000); _serviceHosts.Stop (new byte []{}, true); _state = ServerState.STOP; @@ -432,14 +632,16 @@ namespace WebSocketSharp.Server if (msg != null) { - Log.Error (String.Format ("{0}\nstate: {1}\ncode: {2}\nreason: {3}", msg, _state, code, reason)); + _logger.Error (String.Format ( + "{0}\nstate: {1}\ncode: {2}\nreason: {3}", msg, _state, code, reason)); + return; } _state = ServerState.SHUTDOWN; } - base.Stop (); + stopListener (5000); _serviceHosts.Stop (data, !code.IsReserved ()); _state = ServerState.STOP; @@ -466,14 +668,14 @@ namespace WebSocketSharp.Server if (msg != null) { - Log.Error (String.Format ("{0}\nstate: {1}\nreason: {2}", msg, _state, reason)); + _logger.Error (String.Format ("{0}\nstate: {1}\nreason: {2}", msg, _state, reason)); return; } _state = ServerState.SHUTDOWN; } - base.Stop (); + stopListener (5000); _serviceHosts.Stop (data, !code.IsReserved ()); _state = ServerState.STOP; diff --git a/websocket-sharp/Server/WebSocketServerBase.cs b/websocket-sharp/Server/WebSocketServerBase.cs deleted file mode 100644 index 1901ba54..00000000 --- a/websocket-sharp/Server/WebSocketServerBase.cs +++ /dev/null @@ -1,464 +0,0 @@ -#region License -/* - * WebSocketServerBase.cs - * - * The MIT License - * - * Copyright (c) 2012-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; -using System.Diagnostics; -using System.Net; -using System.Net.Sockets; -using System.Security.Cryptography.X509Certificates; -using System.Threading; -using WebSocketSharp.Net.WebSockets; - -namespace WebSocketSharp.Server -{ - /// - /// Provides the basic functions of the server that receives the WebSocket connection requests. - /// - /// - /// The WebSocketServerBase class is an abstract class. - /// - public abstract class WebSocketServerBase - { - #region Private Fields - - private IPAddress _address; - private X509Certificate2 _cert; - private volatile bool _listening; - private Logger _logger; - private int _port; - private Thread _receiveRequestThread; - private bool _secure; - private bool _selfHost; - private TcpListener _listener; - private Uri _uri; - - #endregion - - #region Protected Constructors - - /// - /// Initializes a new instance of the class. - /// - /// - /// This constructor initializes a new instance of this class as non self hosted server. - /// - protected WebSocketServerBase () - : this (new Logger ()) - { - } - - /// - /// Initializes a new instance of the class - /// with the specified . - /// - /// - /// This constructor initializes a new instance of this class as non self hosted server. - /// - /// - /// A that provides the logging functions. - /// - protected WebSocketServerBase (Logger logger) - { - _logger = logger; - _selfHost = false; - } - - /// - /// Initializes a new instance of the class - /// that listens for incoming connection attempts on the specified WebSocket URL. - /// - /// - /// A that contains a WebSocket URL. - /// - /// - /// is . - /// - /// - /// is invalid. - /// - protected WebSocketServerBase (string url) - { - if (url == null) - throw new ArgumentNullException ("url"); - - Uri uri; - string msg; - if (!tryCreateUri (url, out uri, out msg)) - throw new ArgumentException (msg, "url"); - - init (uri); - } - - /// - /// Initializes a new instance of the class - /// that listens for incoming connection attempts on the specified , - /// , and . - /// - /// - /// A that contains a local IP address. - /// - /// - /// An that contains a port number. - /// - /// - /// A that contains an absolute path. - /// - /// - /// A that indicates providing a secure connection or not. - /// (true indicates providing a secure connection.) - /// - /// - /// Either or is . - /// - /// - /// is 0 or less, or 65536 or greater. - /// - /// - /// - /// is invalid. - /// - /// - /// -or- - /// - /// - /// Pair of and is invalid. - /// - /// - protected WebSocketServerBase (IPAddress address, int port, string servicePath, bool secure) - { - if (address == null) - throw new ArgumentNullException ("address"); - - if (servicePath == null) - throw new ArgumentNullException ("servicePath"); - - if (!port.IsPortNumber ()) - throw new ArgumentOutOfRangeException ("port", "Invalid port number: " + port); - - var msg = servicePath.CheckIfValidServicePath (); - if (msg != null) - throw new ArgumentException (msg, "servicePath"); - - if ((port == 80 && secure) || (port == 443 && !secure)) - throw new ArgumentException (String.Format ( - "Invalid pair of 'port' and 'secure': {0}, {1}", port, secure)); - - _address = address; - _port = port; - _uri = servicePath.ToUri (); - _secure = secure; - - init (); - } - - #endregion - - #region Protected Properties - - /// - /// Gets or sets the WebSocket URL on which to listen for incoming connection attempts. - /// - /// - /// A that contains a WebSocket URL. - /// - protected Uri BaseUri { - get { - return _uri; - } - - set { - _uri = value; - } - } - - #endregion - - #region Public Properties - - /// - /// Gets the local IP address on which to listen for incoming connection attempts. - /// - /// - /// A that contains a local IP address. - /// - public IPAddress Address { - get { - return _address; - } - } - - /// - /// Gets or sets the certificate used to authenticate the server on the secure connection. - /// - /// - /// A used to authenticate the server. - /// - public X509Certificate2 Certificate { - get { - return _cert; - } - - set { - if (_listening) - return; - - _cert = value; - } - } - - /// - /// Gets a value indicating whether the server has been started. - /// - /// - /// true if the server has been started; otherwise, false. - /// - public bool IsListening { - get { - return _listening; - } - } - - /// - /// Gets a value indicating whether the server provides secure connection. - /// - /// - /// true if the server provides secure connection; otherwise, false. - /// - public bool IsSecure { - get { - return _secure; - } - } - - /// - /// Gets a value indicating whether the server is self host. - /// - /// - /// true if the server is self host; otherwise, false. - /// - public bool IsSelfHost { - get { - return _selfHost; - } - } - - /// - /// Gets the logging functions. - /// - /// - /// The default logging level is the . - /// If you want to change the current logging level, you set the Log.Level property - /// to one of the values which you want. - /// - /// - /// A that provides the logging functions. - /// - public Logger Log { - get { - return _logger; - } - - internal set { - if (value == null) - return; - - _logger = value; - } - } - - /// - /// Gets the port on which to listen for incoming connection attempts. - /// - /// - /// An that contains a port number. - /// - public int Port { - get { - return _port; - } - } - - #endregion - - #region Private Methods - - private void init () - { - _listening = false; - _logger = new Logger (); - _selfHost = true; - _listener = new TcpListener (_address, _port); - } - - private void init (Uri uri) - { - var scheme = uri.Scheme; - var host = uri.DnsSafeHost; - var port = uri.Port; - var addrs = Dns.GetHostAddresses (host); - - _uri = uri; - _address = addrs [0]; - _port = port; - _secure = scheme == "wss" ? true : false; - - init (); - } - - private void processRequestAsync (TcpClient client) - { - WaitCallback callback = state => - { - try { - AcceptWebSocket (client.GetWebSocketContext (_secure, _cert)); - } - catch (Exception ex) - { - _logger.Fatal (ex.ToString ()); - client.Close (); - } - }; - - ThreadPool.QueueUserWorkItem (callback); - } - - private void receiveRequest () - { - while (true) - { - try { - processRequestAsync (_listener.AcceptTcpClient ()); - } - catch (SocketException ex) { - _logger.Warn (String.Format ("Receiving has been stopped.\nreason: {0}.", ex.Message)); - break; - } - catch (Exception ex) { - _logger.Fatal (ex.ToString ()); - break; - } - } - - if (_listening) - Abort (); - } - - private void startReceiveRequestThread () - { - _receiveRequestThread = new Thread (new ThreadStart (receiveRequest)); - _receiveRequestThread.IsBackground = true; - _receiveRequestThread.Start (); - } - - private static bool tryCreateUri (string uriString, out Uri result, out string message) - { - if (!uriString.TryCreateWebSocketUri (out result, out message)) - return false; - - if (!result.Query.IsNullOrEmpty ()) - { - result = null; - message = "Must not contain the query component: " + uriString; - - return false; - } - - return true; - } - - #endregion - - #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. - /// - /// - /// A that contains the WebSocket connection request objects. - /// - 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 - - /// - /// Starts to receive the WebSocket connection requests. - /// - public virtual void Start () - { - if (!_selfHost || _listening) - return; - - if (_secure && _cert == null) - { - _logger.Error ("The secure connection requires a server certificate."); - return; - } - - _listener.Start (); - startReceiveRequestThread (); - _listening = true; - } - - /// - /// Stops receiving the WebSocket connection requests. - /// - public virtual void Stop () - { - if (!_selfHost || !_listening) - return; - - _listening = false; - _listener.Stop (); - _receiveRequestThread.Join (5 * 1000); - } - - #endregion - } -} diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs index a143b3d7..c5b0d0ff 100644 --- a/websocket-sharp/WebSocket.cs +++ b/websocket-sharp/WebSocket.cs @@ -109,7 +109,6 @@ namespace WebSocketSharp _extensions = String.Empty; _forClose = new object (); _forSend = new object (); - _logger = new Logger (); _origin = String.Empty; _preAuth = false; _protocol = String.Empty; @@ -154,7 +153,7 @@ namespace WebSocketSharp /// is . /// /// - /// is not valid WebSocket URL. + /// is invalid. /// public WebSocket (string url, params string[] protocols) : this () @@ -162,16 +161,15 @@ namespace WebSocketSharp if (url == null) throw new ArgumentNullException ("url"); - Uri uri; string msg; - if (!url.TryCreateWebSocketUri (out uri, out msg)) + if (!url.TryCreateWebSocketUri (out _uri, out msg)) throw new ArgumentException (msg, "url"); - _uri = uri; _protocols = protocols.ToString (", "); + _secure = _uri.Scheme == "wss" ? true : false; _client = true; - _secure = uri.Scheme == "wss" ? true : false; _base64key = createBase64Key (); + _logger = new Logger (); } /// diff --git a/websocket-sharp/websocket-sharp.csproj b/websocket-sharp/websocket-sharp.csproj index 852461ee..e7245723 100644 --- a/websocket-sharp/websocket-sharp.csproj +++ b/websocket-sharp/websocket-sharp.csproj @@ -97,7 +97,6 @@ -