Fix due to the added WebSocketServer class in WebSocketServer.cs

This commit is contained in:
sta 2012-09-24 15:01:25 +09:00
parent ab86ce8af8
commit b9859e08c0
52 changed files with 679 additions and 263 deletions

Binary file not shown.

View File

@ -76,6 +76,8 @@ namespace Example
using (WebSocket ws = new WebSocket("ws://echo.websocket.org", "echo")) using (WebSocket ws = new WebSocket("ws://echo.websocket.org", "echo"))
//using (WebSocket ws = new WebSocket("wss://echo.websocket.org", "echo")) //using (WebSocket ws = new WebSocket("wss://echo.websocket.org", "echo"))
//using (WebSocket ws = new WebSocket("ws://localhost:4649")) //using (WebSocket ws = new WebSocket("ws://localhost:4649"))
//using (WebSocket ws = new WebSocket("ws://localhost:4649/Echo"))
//using (WebSocket ws = new WebSocket("ws://localhost:4649/Chat"))
{ {
ws.OnOpen += (sender, e) => ws.OnOpen += (sender, e) =>
{ {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -7,14 +7,27 @@ namespace Example2
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
/* Single service server
var wssv = new WebSocketServer<Echo>("ws://localhost:4649"); var wssv = new WebSocketServer<Echo>("ws://localhost:4649");
//var wssv = new WebSocketServer<Chat>("ws://localhost:4649");
//var wssv = new WebSocketServer<Echo>(4649); //var wssv = new WebSocketServer<Echo>(4649);
//var wssv = new WebSocketServer<Chat>("ws://localhost:4649");
//var wssv = new WebSocketServer<Chat>(4649);
wssv.Start(); wssv.Start();
Console.WriteLine( Console.WriteLine(
"WebSocket Server (url: {0})\n listening on address: {1} port: {2}\n", "WebSocket Server (url: {0})\n listening on address: {1} port: {2}\n",
wssv.Uri, wssv.Address, wssv.Port); wssv.Uri, wssv.Address, wssv.Port);
*/
// Multi services server
var wssv = new WebSocketServer(4649);
wssv.AddService<Echo>("/Echo");
wssv.AddService<Chat>("/Chat");
wssv.Start();
Console.WriteLine(
"WebSocket Server listening on port: {0}\n", wssv.Port);
Console.WriteLine("Press any key to stop server..."); Console.WriteLine("Press any key to stop server...");
Console.ReadLine(); Console.ReadLine();

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -147,7 +147,7 @@ Required namespace.
using WebSocketSharp.Server; using WebSocketSharp.Server;
``` ```
`WebSocketServer<T>` class and `WebSocketService` class exist in `WebSocketSharp.Server` namespace. `WebSocketServer`, `WebSocketServer<T>` and `WebSocketService` classes exist in `WebSocketSharp.Server` namespace.
#### Step 2 #### #### Step 2 ####
@ -191,15 +191,25 @@ In addition, if you override `onOpen`, `onError` and `onClose` methods, each of
#### Step 3 #### #### Step 3 ####
Creating a instance of `WebSocketServer<T>` class. Creating a instance of `WebSocketServer<T>` class if you want single WebSocket service server.
```cs ```cs
var wssv = new WebSocketServer<Echo>("ws://example.com:4649"); var wssv = new WebSocketServer<Echo>("ws://example.com:4649");
``` ```
Creating a instance of `WebSocketServer` class if you want multi WebSocket service server.
```cs
var wssv = new WebSocketServer(4649);
wssv.AddService<Echo>("/Echo");
wssv.AddService<Chat>("/Chat");
```
You can add to your `WebSocketServer` any WebSocket service and a matching path to that service by using `WebSocketServer.AddService<T>` method.
Type of `T` inherits `WebSocketService` class, so you can use a class that was created in **Step 2**. Type of `T` inherits `WebSocketService` class, so you can use a class that was created in **Step 2**.
If you set WebSocket url without port number, `WebSocketServer<T>` set **80** or **443** to port number automatically. If you create a instance of WebSocket Server without port number, WebSocket Server set **80** or **443** to port number automatically.
So it is necessary to run with root permission. So it is necessary to run with root permission.
$ sudo mono example2.exe $ sudo mono example2.exe
@ -272,6 +282,8 @@ Examples of using **websocket-sharp**.
[Example3] starts the HTTP server that the connection can be upgraded to the WebSocket connection. [Example3] starts the HTTP server that the connection can be upgraded to the WebSocket connection.
Please access http://localhost:4649 to do WebSocket Echo Test with your web browser after [Example3] running.
## Supported WebSocket Protocol ## ## Supported WebSocket Protocol ##
**websocket-sharp** supports **[RFC 6455]**. **websocket-sharp** supports **[RFC 6455]**.

View File

@ -37,13 +37,20 @@ using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Sockets;
using System.Text; using System.Text;
using WebSocketSharp.Net; using WebSocketSharp.Net;
using WebSocketSharp.Net.Sockets;
namespace WebSocketSharp namespace WebSocketSharp
{ {
public static class Ext public static class Ext
{ {
public static TcpListenerWebSocketContext AcceptWebSocket(this TcpClient client)
{
return new TcpListenerWebSocketContext(client);
}
public static void Emit( public static void Emit(
this EventHandler eventHandler, object sender, EventArgs e) this EventHandler eventHandler, object sender, EventArgs e)
{ {
@ -126,7 +133,7 @@ namespace WebSocketSharp
// Derived from System.Uri.IsPredefinedScheme method // Derived from System.Uri.IsPredefinedScheme method
public static bool IsPredefinedScheme(this string scheme) public static bool IsPredefinedScheme(this string scheme)
{ {
if (scheme == null && scheme.Length < 3) if (scheme == null && scheme.Length < 2)
return false; return false;
char c = scheme[0]; char c = scheme[0];
@ -136,7 +143,10 @@ namespace WebSocketSharp
if (c == 'f') if (c == 'f')
return (scheme == "file" || scheme == "ftp"); return (scheme == "file" || scheme == "ftp");
if (c == 'w')
return (scheme == "ws" || scheme == "wss");
if (c == 'n') if (c == 'n')
{ {
c = scheme[1]; c = scheme[1];
@ -156,6 +166,19 @@ namespace WebSocketSharp
return false; return false;
} }
// Derived from System.Uri.MaybeUri method
public static bool MaybeUri(this string uriString)
{
int p = uriString.IndexOf(':');
if (p == -1)
return false;
if (p >= 10)
return false;
return uriString.Substring(0, p).IsPredefinedScheme();
}
public static bool NotEqualsDo( public static bool NotEqualsDo(
this string expected, this string expected,
string actual, string actual,
@ -173,19 +196,6 @@ namespace WebSocketSharp
return false; return false;
} }
// Derived from System.Uri.MaybeUri method
public static bool MaybeUri(this string uriString)
{
int p = uriString.IndexOf(':');
if (p == -1)
return false;
if (p >= 10)
return false;
return uriString.Substring(0, p).IsPredefinedScheme();
}
public static byte[] ReadBytes<TStream>(this TStream stream, ulong length, int bufferLength) public static byte[] ReadBytes<TStream>(this TStream stream, ulong length, int bufferLength)
where TStream : System.IO.Stream where TStream : System.IO.Stream
{ {

View File

@ -33,12 +33,14 @@ namespace WebSocketSharp
{ {
public interface IWsStream : IDisposable public interface IWsStream : IDisposable
{ {
void Close(); void Close();
int Read(byte[] buffer, int offset, int size); int Read(byte[] buffer, int offset, int size);
int ReadByte(); int ReadByte();
WsFrame ReadFrame(); WsFrame ReadFrame();
void Write(byte[] buffer, int offset, int count); string[] ReadHandshake();
void WriteByte(byte value); void Write(byte[] buffer, int offset, int count);
void WriteFrame(WsFrame frame); void WriteByte(byte value);
void WriteFrame(WsFrame frame);
void WriteHandshake(Handshake handshake);
} }
} }

View File

@ -29,6 +29,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.IO;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Principal; using System.Security.Principal;
@ -39,10 +40,12 @@ namespace WebSocketSharp.Net {
{ {
private HttpListenerContext _context; private HttpListenerContext _context;
private WebSocket _socket; private WebSocket _socket;
private IWsStream _stream;
internal HttpListenerWebSocketContext(string path, HttpListenerContext context) internal HttpListenerWebSocketContext(string path, HttpListenerContext context)
{ {
_context = context; _context = context;
_stream = WebSocket.CreateServerStream(context);
_socket = new WebSocket(path.ToUri(), this); _socket = new WebSocket(path.ToUri(), this);
} }
@ -50,6 +53,10 @@ namespace WebSocketSharp.Net {
get { return _context; } get { return _context; }
} }
internal IWsStream Stream {
get { return _stream; }
}
public override CookieCollection CookieCollection { public override CookieCollection CookieCollection {
get { return _context.Request.Cookies; } get { return _context.Request.Cookies; }
} }

View File

@ -0,0 +1,120 @@
#region MIT License
/**
* TcpListenerWebSocketContext.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.Collections.Generic;
using System.Collections.Specialized;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Principal;
namespace WebSocketSharp.Net.Sockets {
public class TcpListenerWebSocketContext : WebSocketContext
{
private TcpClient _client;
private bool _isSecure;
private RequestHandshake _request;
private WebSocket _socket;
private IWsStream _stream;
internal TcpListenerWebSocketContext(TcpClient client)
{
_client = client;
init();
}
internal TcpClient Client {
get { return _client; }
}
internal IWsStream Stream {
get { return _stream; }
}
public override CookieCollection CookieCollection {
get { throw new NotImplementedException(); }
}
public override NameValueCollection Headers {
get { return _request.Headers; }
}
public override bool IsAuthenticated {
get { throw new NotImplementedException(); }
}
public override bool IsSecureConnection {
get { return _isSecure; }
}
public override bool IsLocal {
get { throw new NotImplementedException(); }
}
public override string Origin {
get { return Headers["Origin"]; }
}
public override Uri RequestUri {
get { return _request.RequestUri; }
}
public override string SecWebSocketKey {
get { return Headers["Sec-WebSocket-Key"]; }
}
public override IEnumerable<string> SecWebSocketProtocols {
get { return Headers.GetValues("Sec-WebSocket-Protocol"); }
}
public override string SecWebSocketVersion {
get { return Headers["Sec-WebSocket-Version"]; }
}
public override IPrincipal User {
get { throw new NotImplementedException(); }
}
public override WebSocket WebSocket {
get { return _socket; }
}
private void init()
{
_stream = WebSocket.CreateServerStream(_client);
_request = RequestHandshake.Parse(_stream.ReadHandshake());
var port = ((IPEndPoint)_client.Client.LocalEndPoint).Port;
_isSecure = port == 443 ? true : false;
_socket = new WebSocket(this);
}
}
}

View File

@ -35,6 +35,36 @@ namespace WebSocketSharp {
public class ResponseHandshake : Handshake public class ResponseHandshake : Handshake
{ {
#region Public Static Fields
public static ResponseHandshake BadRequest;
public static ResponseHandshake NotImplemented;
#endregion
#region Static Constructor
static ResponseHandshake()
{
var badRequest = new ResponseHandshake {
Reason = "Bad Request",
StatusCode = ((int)HttpStatusCode.BadRequest).ToString()
};
badRequest.Headers.Clear();
badRequest.AddHeader("Connection", "Close");
BadRequest = badRequest;
var notImplemented = new ResponseHandshake {
Reason = "Not Implemented",
StatusCode = ((int)HttpStatusCode.NotImplemented).ToString()
};
notImplemented.Headers.Clear();
notImplemented.AddHeader("Connection", "Close");
NotImplemented = notImplemented;
}
#endregion
#region Public Constructor #region Public Constructor
public ResponseHandshake() public ResponseHandshake()

View File

@ -31,25 +31,84 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading;
using WebSocketSharp.Frame; using WebSocketSharp.Frame;
using WebSocketSharp.Net.Sockets;
namespace WebSocketSharp.Server { namespace WebSocketSharp.Server {
public class WebSocketServer<T> : IWebSocketServer public class WebSocketServer : WebSocketServerBase
{
#region Field
private Dictionary<string, IWebSocketServer> _servers;
#endregion
#region Public Constructors
public WebSocketServer()
: this(80)
{
}
public WebSocketServer(int port)
: base(IPAddress.Any, port)
{
_servers = new Dictionary<string, IWebSocketServer>();
}
#endregion
#region Protected Method
protected override void bindSocket(TcpClient client)
{
var context = client.AcceptWebSocket();
var path = context.RequestUri.ToString();
if (!_servers.ContainsKey(path))
{
var stream = context.Stream;
var res = ResponseHandshake.NotImplemented;
stream.WriteHandshake(res);
stream.Close();
client.Close();
return;
}
var socket = context.WebSocket;
var server = _servers[path];
server.BindWebSocket(socket);
}
#endregion
#region Public Methods
public void AddService<T>(string path)
where T : WebSocketService, new()
{
var server = new WebSocketServer<T>();
_servers.Add(path, server);
}
public override void Stop()
{
base.Stop();
foreach (var server in _servers.Values)
server.Stop();
}
#endregion
}
public class WebSocketServer<T> : WebSocketServerBase, IWebSocketServer
where T : WebSocketService, new() where T : WebSocketService, new()
{ {
#region Fields #region Fields
private Thread _acceptClientThread;
private IPAddress _address;
private bool _isSelfHost;
private int _port;
private Dictionary<string, WebSocketService> _services; private Dictionary<string, WebSocketService> _services;
private TcpListener _tcpListener;
private Uri _uri; private Uri _uri;
#endregion #endregion
@ -58,8 +117,7 @@ namespace WebSocketSharp.Server {
internal WebSocketServer() internal WebSocketServer()
{ {
_services = new Dictionary<string, WebSocketService>(); init();
_isSelfHost = false;
} }
#endregion #endregion
@ -67,16 +125,10 @@ namespace WebSocketSharp.Server {
#region Public Constructors #region Public Constructors
public WebSocketServer(string url) public WebSocketServer(string url)
: this() : base(url)
{ {
var uri = new Uri(url); _uri = url.ToUri();
init();
string msg;
if (!isValidUri(uri, out msg))
throw new ArgumentException(msg, "url");
_tcpListener = new TcpListener(_address, _port);
_isSelfHost = true;
} }
public WebSocketServer(int port) public WebSocketServer(int port)
@ -85,7 +137,7 @@ namespace WebSocketSharp.Server {
} }
public WebSocketServer(int port, string path) public WebSocketServer(int port, string path)
: this() : base(IPAddress.Any, port)
{ {
var uri = path.ToUri(); var uri = path.ToUri();
if (uri.IsAbsoluteUri) if (uri.IsAbsoluteUri)
@ -94,31 +146,13 @@ namespace WebSocketSharp.Server {
throw new ArgumentException(msg, "path"); throw new ArgumentException(msg, "path");
} }
_uri = uri; _uri = uri;
_address = IPAddress.Any; init();
_port = port <= 0 ? 80 : port;
_tcpListener = new TcpListener(_address, _port);
_isSelfHost = true;
} }
#endregion #endregion
#region Properties #region Property
public IPAddress Address
{
get { return _address; }
}
public bool IsSelfHost {
get { return _isSelfHost; }
}
public int Port
{
get { return _port; }
}
public Uri Uri public Uri Uri
{ {
@ -127,104 +161,21 @@ namespace WebSocketSharp.Server {
#endregion #endregion
#region Events #region Private Method
public event EventHandler<ErrorEventArgs> OnError; private void init()
{
_services = new Dictionary<string, WebSocketService>();
}
#endregion #endregion
#region Private Methods #region Protected Method
private void acceptClient() protected override void bindSocket(TcpClient client)
{ {
while (true) var socket = new WebSocket(_uri, client);
{ BindWebSocket(socket);
try {
var client = _tcpListener.AcceptTcpClient();
startService(client);
}
catch (SocketException)
{
// TcpListener has been stopped.
break;
}
catch (Exception ex)
{
error(ex.Message);
break;
}
}
}
private void error(string message)
{
#if DEBUG
var callerFrame = new StackFrame(1);
var caller = callerFrame.GetMethod();
Console.WriteLine("WSSV: Error@{0}: {1}", caller.Name, message);
#endif
OnError.Emit(this, new ErrorEventArgs(message));
}
private bool isValidUri(Uri uri, out string message)
{
var scheme = uri.Scheme;
var port = uri.Port;
var host = uri.DnsSafeHost;
var ips = Dns.GetHostAddresses(host);
if (scheme != "ws" && scheme != "wss")
{
message = "Unsupported WebSocket URI scheme: " + scheme;
return false;
}
if ((scheme == "wss" && port != 443) ||
(scheme != "wss" && port == 443))
{
message = String.Format(
"Invalid pair of WebSocket URI scheme and port: {0}, {1}", scheme, port);
return false;
}
if (ips.Length == 0)
{
message = "Invalid WebSocket URI host: " + host;
return false;
}
if (port <= 0)
port = scheme == "ws" ? 80 : 443;
_uri = uri;
_address = ips[0];
_port = port;
message = String.Empty;
return true;
}
private void startAcceptClientThread()
{
_acceptClientThread = new Thread(new ThreadStart(acceptClient));
_acceptClientThread.IsBackground = true;
_acceptClientThread.Start();
}
private void startService(TcpClient client)
{
WaitCallback startServiceCb = (state) =>
{
try {
var socket = new WebSocket(_uri, client);
BindWebSocket(socket);
}
catch (Exception ex)
{
error(ex.Message);
}
};
ThreadPool.QueueUserWorkItem(startServiceCb);
} }
#endregion #endregion
@ -238,23 +189,9 @@ namespace WebSocketSharp.Server {
service.Start(); service.Start();
} }
public void Start() public override void Stop()
{ {
if (!_isSelfHost) base.Stop();
return;
_tcpListener.Start();
startAcceptClientThread();
}
public void Stop()
{
if (_isSelfHost)
{
_tcpListener.Stop();
_acceptClientThread.Join(5 * 1000);
}
StopServices(); StopServices();
} }

View File

@ -0,0 +1,233 @@
#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 _isSelfHost;
private int _port;
private TcpListener _tcpListener;
#endregion
#region Constructors
protected WebSocketServerBase()
{
_isSelfHost = false;
}
protected WebSocketServerBase(string url)
{
string msg;
if (!isValidUri(url, out msg))
throw new ArgumentException(msg, "url");
init();
}
protected WebSocketServerBase(IPAddress address, int port)
{
_port = port <= 0 ? 80 : port;
_address = address;
init();
}
#endregion
#region Property
public IPAddress Address {
get { return _address; }
}
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();
acceptSocket(client);
}
catch (SocketException)
{
// TcpListener has been stopped.
break;
}
catch (Exception ex)
{
error(ex.Message);
break;
}
}
}
private void acceptSocket(TcpClient client)
{
WaitCallback acceptSocketCb = (state) =>
{
try
{
bindSocket(client);
}
catch (Exception ex)
{
error(ex.Message);
}
};
ThreadPool.QueueUserWorkItem(acceptSocketCb);
}
private void error(string message)
{
#if DEBUG
var callerFrame = new StackFrame(1);
var caller = callerFrame.GetMethod();
Console.WriteLine("WSSV: Error@{0}: {1}", caller.Name, message);
#endif
OnError.Emit(this, new ErrorEventArgs(message));
}
private void init()
{
_tcpListener = new TcpListener(_address, _port);
_isSelfHost = true;
}
private bool isValidUri(string url, out string message)
{
var uri = url.ToUri();
if (!uri.IsAbsoluteUri)
{
message = "Not absolute uri: " + url;
return false;
}
var scheme = uri.Scheme;
var port = uri.Port;
var host = uri.DnsSafeHost;
var ips = Dns.GetHostAddresses(host);
if (scheme != "ws" && scheme != "wss")
{
message = "Unsupported WebSocket URI scheme: " + scheme;
return false;
}
if ((scheme == "wss" && port != 443) ||
(scheme != "wss" && port == 443))
{
message = String.Format(
"Invalid pair of WebSocket URI scheme and port: {0}, {1}", scheme, port);
return false;
}
if (ips.Length == 0)
{
message = "Invalid WebSocket URI host: " + host;
return false;
}
if (port <= 0)
port = scheme == "ws" ? 80 : 443;
_address = ips[0];
_port = port;
message = String.Empty;
return true;
}
private void startAcceptClientThread()
{
_acceptClientThread = new Thread(new ThreadStart(acceptClient));
_acceptClientThread.IsBackground = true;
_acceptClientThread.Start();
}
#endregion
#region Protected Method
protected abstract void bindSocket(TcpClient client);
#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
}
}

View File

@ -48,6 +48,7 @@ using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using WebSocketSharp.Frame; using WebSocketSharp.Frame;
using WebSocketSharp.Net; using WebSocketSharp.Net;
using WebSocketSharp.Net.Sockets;
namespace WebSocketSharp namespace WebSocketSharp
{ {
@ -62,27 +63,28 @@ namespace WebSocketSharp
#region Private Fields #region Private Fields
private string _base64key; private string _base64key;
private string _binaryType; private WebSocketSharp.Net.HttpListenerContext _baseContext;
private HttpListenerWebSocketContext _context; private string _binaryType;
private IPEndPoint _endPoint; private WebSocketContext _context;
private AutoResetEvent _exitMessageLoop; private IPEndPoint _endPoint;
private string _extensions; private AutoResetEvent _exitMessageLoop;
private Object _forClose; private string _extensions;
private Object _forSend; private Object _forClose;
private int _fragmentLen; private Object _forSend;
private bool _isClient; private int _fragmentLen;
private bool _isSecure; private bool _isClient;
private NetworkStream _netStream; private bool _isSecure;
private string _protocol; private NetworkStream _netStream;
private string _protocols; private string _protocol;
private volatile WsState _readyState; private string _protocols;
private AutoResetEvent _receivedPong; private volatile WsState _readyState;
private SslStream _sslStream; private AutoResetEvent _receivedPong;
private TcpClient _tcpClient; private SslStream _sslStream;
private Uri _uri; private TcpClient _tcpClient;
private SynchronizedCollection<WsFrame> _unTransmittedBuffer; private Uri _uri;
private IWsStream _wsStream; private SynchronizedCollection<WsFrame> _unTransmittedBuffer;
private IWsStream _wsStream;
#endregion #endregion
@ -105,13 +107,28 @@ namespace WebSocketSharp
#region Internal Constructor #region Internal Constructor
internal WebSocket(TcpListenerWebSocketContext context)
: this()
{
_uri = context.RequestUri;
_context = context;
_tcpClient = context.Client;
_wsStream = context.Stream;
_endPoint = (IPEndPoint)_tcpClient.Client.LocalEndPoint;
_isClient = false;
_isSecure = context.IsSecureConnection;
}
internal WebSocket(Uri uri, HttpListenerWebSocketContext context) internal WebSocket(Uri uri, HttpListenerWebSocketContext context)
: this() : this()
{ {
_uri = uri; _uri = uri;
_context = context; _context = context;
_isClient = false; _baseContext = context.BaseContext;
_isSecure = _context.IsSecureConnection; _wsStream = context.Stream;
_endPoint = _baseContext.Connection.LocalEndPoint;
_isClient = false;
_isSecure = context.IsSecureConnection;
} }
internal WebSocket(Uri uri, TcpClient tcpClient) internal WebSocket(Uri uri, TcpClient tcpClient)
@ -325,11 +342,11 @@ namespace WebSocketSharp
private void closeConnection() private void closeConnection()
{ {
if (_context != null) if (_baseContext != null)
{ {
_context.BaseContext.Response.Close(); _baseContext.Response.Close();
_wsStream = null; _wsStream = null;
_context = null; _baseContext = null;
} }
if (_wsStream != null) if (_wsStream != null)
@ -363,13 +380,10 @@ namespace WebSocketSharp
private void createClientStream() private void createClientStream()
{ {
var host = _uri.DnsSafeHost; var host = _uri.DnsSafeHost;
var port = _uri.Port; var port = _uri.Port;
if (port <= 0) if (port <= 0)
{ port = IsSecure ? 443 : 80;
port = 80;
if (IsSecure)
port = 443;
}
_tcpClient = new TcpClient(host, port); _tcpClient = new TcpClient(host, port);
_netStream = _tcpClient.GetStream(); _netStream = _tcpClient.GetStream();
@ -378,7 +392,7 @@ namespace WebSocketSharp
{ {
RemoteCertificateValidationCallback validation = (sender, certificate, chain, sslPolicyErrors) => RemoteCertificateValidationCallback validation = (sender, certificate, chain, sslPolicyErrors) =>
{ {
// Temporary implementation // FIXME: Always returns true
return true; return true;
}; };
@ -449,44 +463,20 @@ namespace WebSocketSharp
private void createServerStream() private void createServerStream()
{ {
if (_context != null) if (_wsStream != null)
{
_wsStream = createServerStreamFromContext();
return; return;
}
if (_tcpClient != null) if (_tcpClient != null)
{ {
_wsStream = createServerStreamFromTcpClient(); _wsStream = CreateServerStream(_tcpClient);
return; return;
} }
}
private IWsStream createServerStreamFromContext() if (_baseContext != null)
{
var stream = _context.BaseContext.Connection.Stream;
if (IsSecure)
return new WsStream<SslStream>((SslStream)stream);
return new WsStream<NetworkStream>((NetworkStream)stream);
}
private IWsStream createServerStreamFromTcpClient()
{
_netStream = _tcpClient.GetStream();
if (IsSecure)
{ {
_sslStream = new SslStream(_netStream); _wsStream = CreateServerStream(_baseContext);
return;
var certPath = ConfigurationManager.AppSettings["ServerCertPath"];
_sslStream.AuthenticateAsServer(new X509Certificate(certPath));
return new WsStream<SslStream>(_sslStream);
} }
return new WsStream<NetworkStream>(_netStream);
} }
private void doHandshake() private void doHandshake()
@ -695,20 +685,7 @@ namespace WebSocketSharp
private string[] readHandshake() private string[] readHandshake()
{ {
var buffer = new List<byte>(); return _wsStream.ReadHandshake();
while (true)
{
if (_wsStream.ReadByte().EqualsAndSaveTo('\r', buffer) &&
_wsStream.ReadByte().EqualsAndSaveTo('\n', buffer) &&
_wsStream.ReadByte().EqualsAndSaveTo('\r', buffer) &&
_wsStream.ReadByte().EqualsAndSaveTo('\n', buffer))
break;
}
return Encoding.UTF8.GetString(buffer.ToArray())
.Replace("\r\n", "\n").Replace("\n\n", "\n").TrimEnd('\n')
.Split('\n');
} }
private MessageEventArgs receive() private MessageEventArgs receive()
@ -992,7 +969,7 @@ namespace WebSocketSharp
Console.WriteLine("WS: Info@sendOpeningHandshake: Opening handshake from client:\n"); Console.WriteLine("WS: Info@sendOpeningHandshake: Opening handshake from client:\n");
Console.WriteLine(req.ToString()); Console.WriteLine(req.ToString());
#endif #endif
_wsStream.Write(req.ToBytes(), 0, req.ToBytes().Length); _wsStream.WriteHandshake(req);
var res = ResponseHandshake.Parse(readHandshake()); var res = ResponseHandshake.Parse(readHandshake());
#if DEBUG #if DEBUG
@ -1009,20 +986,14 @@ namespace WebSocketSharp
Console.WriteLine("WS: Info@sendResponseHandshake: Response handshake from server:\n"); Console.WriteLine("WS: Info@sendResponseHandshake: Response handshake from server:\n");
Console.WriteLine(res.ToString()); Console.WriteLine(res.ToString());
#endif #endif
_wsStream.Write(res.ToBytes(), 0, res.ToBytes().Length); _wsStream.WriteHandshake(res);
} }
private void sendResponseHandshakeForInvalid() private void sendResponseHandshakeForInvalid()
{ {
var code = (int)WebSocketSharp.Net.HttpStatusCode.BadRequest; var res = ResponseHandshake.BadRequest;
var res = new ResponseHandshake {
Reason = "Bad Request",
StatusCode = code.ToString()
};
res.Headers.Clear();
res.AddHeader("Sec-WebSocket-Version", _version); res.AddHeader("Sec-WebSocket-Version", _version);
_wsStream.WriteHandshake(res);
_wsStream.Write(res.ToBytes(), 0, res.ToBytes().Length);
} }
private void startMessageThread() private void startMessageThread()
@ -1040,6 +1011,39 @@ namespace WebSocketSharp
#endregion #endregion
#region Internal Static Methods
internal static IWsStream CreateServerStream(TcpClient client)
{
var netStream = client.GetStream();
var port = ((IPEndPoint)client.Client.LocalEndPoint).Port;
if (port == 443)
{
var sslStream = new SslStream(netStream);
var certPath = ConfigurationManager.AppSettings["ServerCertPath"];
sslStream.AuthenticateAsServer(new X509Certificate2(certPath));
return new WsStream<SslStream>(sslStream);
}
return new WsStream<NetworkStream>(netStream);
}
internal static IWsStream CreateServerStream(WebSocketSharp.Net.HttpListenerContext context)
{
var conn = context.Connection;
var stream = conn.Stream;
if (conn.IsSecure)
return new WsStream<SslStream>((SslStream)stream);
return new WsStream<NetworkStream>((NetworkStream)stream);
}
#endregion
#region Public Methods #region Public Methods
public void Close() public void Close()

View File

@ -32,6 +32,7 @@ using System.IO;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Reflection; using System.Reflection;
using System.Text;
using WebSocketSharp.Frame; using WebSocketSharp.Frame;
namespace WebSocketSharp namespace WebSocketSharp
@ -39,10 +40,16 @@ namespace WebSocketSharp
public class WsStream<TStream> : IWsStream public class WsStream<TStream> : IWsStream
where TStream : Stream where TStream : Stream
{ {
#region Fields
private TStream _innerStream; private TStream _innerStream;
private Object _forRead; private Object _forRead;
private Object _forWrite; private Object _forWrite;
#endregion
#region Constructor
public WsStream(TStream innerStream) public WsStream(TStream innerStream)
{ {
Type streamType = typeof(TStream); Type streamType = typeof(TStream);
@ -62,6 +69,10 @@ namespace WebSocketSharp
_forWrite = new object(); _forWrite = new object();
} }
#endregion
#region Public Methods
public void Close() public void Close()
{ {
_innerStream.Close(); _innerStream.Close();
@ -102,6 +113,27 @@ namespace WebSocketSharp
} }
} }
public string[] ReadHandshake()
{
lock (_forRead)
{
var buffer = new List<byte>();
while (true)
{
if (ReadByte().EqualsAndSaveTo('\r', buffer) &&
ReadByte().EqualsAndSaveTo('\n', buffer) &&
ReadByte().EqualsAndSaveTo('\r', buffer) &&
ReadByte().EqualsAndSaveTo('\n', buffer))
break;
}
return Encoding.UTF8.GetString(buffer.ToArray())
.Replace("\r\n", "\n").Replace("\n\n", "\n").TrimEnd('\n')
.Split('\n');
}
}
public void Write(byte[] buffer, int offset, int count) public void Write(byte[] buffer, int offset, int count)
{ {
lock (_forWrite) lock (_forWrite)
@ -126,5 +158,16 @@ namespace WebSocketSharp
_innerStream.Write(buffer, 0, buffer.Length); _innerStream.Write(buffer, 0, buffer.Length);
} }
} }
public void WriteHandshake(Handshake handshake)
{
lock (_forWrite)
{
var buffer = handshake.ToBytes();
_innerStream.Write(buffer, 0, buffer.Length);
}
}
#endregion
} }
} }

View File

@ -109,11 +109,14 @@
<Compile Include="Net\HttpVersion.cs" /> <Compile Include="Net\HttpVersion.cs" />
<Compile Include="Net\HttpStatusCode.cs" /> <Compile Include="Net\HttpStatusCode.cs" />
<Compile Include="Server\IWebSocketServer.cs" /> <Compile Include="Server\IWebSocketServer.cs" />
<Compile Include="Net\Sockets\TcpListenerWebSocketContext.cs" />
<Compile Include="Server\WebSocketServerBase.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>
<Folder Include="Frame\" /> <Folder Include="Frame\" />
<Folder Include="Server\" /> <Folder Include="Server\" />
<Folder Include="Net\" /> <Folder Include="Net\" />
<Folder Include="Net\Sockets\" />
</ItemGroup> </ItemGroup>
</Project> </Project>

Binary file not shown.