| #region MIT License | 
| /** | 
|  * WebSocketServerBase.cs | 
|  * | 
|  * The MIT License | 
|  * | 
|  * Copyright (c) 2012 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.Threading; | 
|   | 
| namespace WebSocketSharp.Server | 
| { | 
|     public abstract class WebSocketServerBase | 
|     { | 
|         #region Fields | 
|   | 
|         private Thread _acceptClientThread; | 
|         private IPAddress _address; | 
|         private bool _isSecure; | 
|         private bool _isSelfHost; | 
|         private int _port; | 
|         private TcpListener _tcpListener; | 
|         private Uri _uri; | 
|   | 
|         #endregion | 
|   | 
|         #region Constructors | 
|   | 
|         protected WebSocketServerBase() | 
|         { | 
|             _isSelfHost = false; | 
|         } | 
|   | 
|         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); | 
|         } | 
|   | 
|         protected WebSocketServerBase(IPAddress address, int port, string absPath, bool secure) | 
|         { | 
|             if (address == null) | 
|                 throw new ArgumentNullException("address"); | 
|   | 
|             if (absPath == null) | 
|                 throw new ArgumentNullException("absPath"); | 
|   | 
|             string msg; | 
|             if (!Ext.IsValidAbsolutePath(absPath, out msg)) | 
|                 throw new ArgumentException(msg, "absPath"); | 
|   | 
|             if ((port == 80 && secure) || | 
|                 (port == 443 && !secure)) | 
|             { | 
|                 msg = String.Format( | 
|                   "Invalid pair of 'port' and 'secure': {0}, {1}", port, secure); | 
|                 throw new ArgumentException(msg); | 
|             } | 
|   | 
|             _address = address; | 
|             _port = port > 0 | 
|                       ? port | 
|                       : secure ? 443 : 80; | 
|             _uri = Ext.ToUri(absPath); | 
|             _isSecure = secure; | 
|   | 
|             init(); | 
|         } | 
|   | 
|         #endregion | 
|   | 
|         #region Protected Property | 
|   | 
|         protected Uri BaseUri | 
|         { | 
|             get | 
|             { | 
|                 return _uri; | 
|             } | 
|   | 
|             set | 
|             { | 
|                 _uri = value; | 
|             } | 
|         } | 
|   | 
|         #endregion | 
|   | 
|         #region Public Properties | 
|   | 
|         public IPAddress Address | 
|         { | 
|             get | 
|             { | 
|                 return _address; | 
|             } | 
|         } | 
|   | 
|         public bool IsSecure | 
|         { | 
|             get | 
|             { | 
|                 return _isSecure; | 
|             } | 
|         } | 
|   | 
|         public bool IsSelfHost | 
|         { | 
|             get | 
|             { | 
|                 return _isSelfHost; | 
|             } | 
|         } | 
|   | 
|         public int Port | 
|         { | 
|             get | 
|             { | 
|                 return _port; | 
|             } | 
|         } | 
|   | 
|         #endregion | 
|   | 
|         #region Events | 
|   | 
|         public event EventHandler<ErrorEventArgs> OnError; | 
|   | 
|         #endregion | 
|   | 
|         #region Private Methods | 
|   | 
|         private void acceptClient() | 
|         { | 
|             while (true) | 
|             { | 
|                 try | 
|                 { | 
|                     var client = _tcpListener.AcceptTcpClient(); | 
|                     acceptSocketAsync(client); | 
|                 } | 
|                 catch (SocketException) | 
|                 { | 
|                     // TcpListener has been stopped. | 
|                     break; | 
|                 } | 
|                 catch (Exception ex) | 
|                 { | 
|                     onError(ex.Message); | 
|                     break; | 
|                 } | 
|             } | 
|         } | 
|   | 
|         private void acceptSocketAsync(TcpClient client) | 
|         { | 
|             WaitCallback acceptSocketCb = (state) => | 
|             { | 
|                 try | 
|                 { | 
|                     AcceptWebSocket(client); | 
|                 } | 
|                 catch (Exception ex) | 
|                 { | 
|                     onError(ex.Message); | 
|                 } | 
|             }; | 
|   | 
|             ThreadPool.QueueUserWorkItem(acceptSocketCb); | 
|         } | 
|   | 
|         private void init() | 
|         { | 
|             _tcpListener = new TcpListener(_address, _port); | 
|             _isSelfHost = true; | 
|         } | 
|   | 
|         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]; | 
|             _isSecure = scheme == "wss" ? true : false; | 
|             _port = port > 0 | 
|                         ? port | 
|                         : _isSecure ? 443 : 80; | 
|   | 
|             init(); | 
|         } | 
|   | 
|         private void onError(string message) | 
|         { | 
| #if DEBUG | 
|             var callerFrame = new StackFrame(1); | 
|             var caller = callerFrame.GetMethod(); | 
|             Console.WriteLine("WSSV: Error@{0}: {1}", caller.Name, message); | 
| #endif | 
|             Ext.Emit(OnError, this, new ErrorEventArgs(message)); | 
|         } | 
|   | 
|         private void startAcceptClientThread() | 
|         { | 
|             _acceptClientThread = new Thread(new ThreadStart(acceptClient)); | 
|             _acceptClientThread.IsBackground = true; | 
|             _acceptClientThread.Start(); | 
|         } | 
|   | 
|         private bool tryCreateUri(string uriString, out Uri result, out string message) | 
|         { | 
|             if (!Ext.TryCreateWebSocketUri(uriString, out result, out message)) | 
|                 return false; | 
|   | 
|             if (!Ext.IsNullOrEmpty(result.Query)) | 
|             { | 
|                 result = null; | 
|                 message = "Must not contain the query component: " + uriString; | 
|                 return false; | 
|             } | 
|   | 
|             return true; | 
|         } | 
|   | 
|         #endregion | 
|   | 
|         #region Protected Methods | 
|   | 
|         protected abstract void AcceptWebSocket(TcpClient client); | 
|   | 
|         protected virtual void Error(string message) | 
|         { | 
|             onError(message); | 
|         } | 
|   | 
|         #endregion | 
|   | 
|         #region Public Methods | 
|   | 
|         public virtual void Start() | 
|         { | 
|             if (!_isSelfHost) | 
|                 return; | 
|   | 
|             _tcpListener.Start(); | 
|             startAcceptClientThread(); | 
|         } | 
|   | 
|         public virtual void Stop() | 
|         { | 
|             if (!_isSelfHost) | 
|                 return; | 
|   | 
|             _tcpListener.Stop(); | 
|             _acceptClientThread.Join(5 * 1000); | 
|         } | 
|   | 
|         #endregion | 
|     } | 
| } |