Fix due to the added WebSocketServer class in WebSocketServer.cs
This commit is contained in:
@@ -37,13 +37,20 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using WebSocketSharp.Net;
|
||||
using WebSocketSharp.Net.Sockets;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
public static class Ext
|
||||
{
|
||||
public static TcpListenerWebSocketContext AcceptWebSocket(this TcpClient client)
|
||||
{
|
||||
return new TcpListenerWebSocketContext(client);
|
||||
}
|
||||
|
||||
public static void Emit(
|
||||
this EventHandler eventHandler, object sender, EventArgs e)
|
||||
{
|
||||
@@ -126,7 +133,7 @@ namespace WebSocketSharp
|
||||
// Derived from System.Uri.IsPredefinedScheme method
|
||||
public static bool IsPredefinedScheme(this string scheme)
|
||||
{
|
||||
if (scheme == null && scheme.Length < 3)
|
||||
if (scheme == null && scheme.Length < 2)
|
||||
return false;
|
||||
|
||||
char c = scheme[0];
|
||||
@@ -136,7 +143,10 @@ namespace WebSocketSharp
|
||||
|
||||
if (c == 'f')
|
||||
return (scheme == "file" || scheme == "ftp");
|
||||
|
||||
|
||||
if (c == 'w')
|
||||
return (scheme == "ws" || scheme == "wss");
|
||||
|
||||
if (c == 'n')
|
||||
{
|
||||
c = scheme[1];
|
||||
@@ -156,6 +166,19 @@ namespace WebSocketSharp
|
||||
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(
|
||||
this string expected,
|
||||
string actual,
|
||||
@@ -173,19 +196,6 @@ namespace WebSocketSharp
|
||||
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)
|
||||
where TStream : System.IO.Stream
|
||||
{
|
||||
|
@@ -33,12 +33,14 @@ namespace WebSocketSharp
|
||||
{
|
||||
public interface IWsStream : IDisposable
|
||||
{
|
||||
void Close();
|
||||
int Read(byte[] buffer, int offset, int size);
|
||||
int ReadByte();
|
||||
WsFrame ReadFrame();
|
||||
void Write(byte[] buffer, int offset, int count);
|
||||
void WriteByte(byte value);
|
||||
void WriteFrame(WsFrame frame);
|
||||
void Close();
|
||||
int Read(byte[] buffer, int offset, int size);
|
||||
int ReadByte();
|
||||
WsFrame ReadFrame();
|
||||
string[] ReadHandshake();
|
||||
void Write(byte[] buffer, int offset, int count);
|
||||
void WriteByte(byte value);
|
||||
void WriteFrame(WsFrame frame);
|
||||
void WriteHandshake(Handshake handshake);
|
||||
}
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Net.Security;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Principal;
|
||||
@@ -39,10 +40,12 @@ namespace WebSocketSharp.Net {
|
||||
{
|
||||
private HttpListenerContext _context;
|
||||
private WebSocket _socket;
|
||||
private IWsStream _stream;
|
||||
|
||||
internal HttpListenerWebSocketContext(string path, HttpListenerContext context)
|
||||
{
|
||||
_context = context;
|
||||
_stream = WebSocket.CreateServerStream(context);
|
||||
_socket = new WebSocket(path.ToUri(), this);
|
||||
}
|
||||
|
||||
@@ -50,6 +53,10 @@ namespace WebSocketSharp.Net {
|
||||
get { return _context; }
|
||||
}
|
||||
|
||||
internal IWsStream Stream {
|
||||
get { return _stream; }
|
||||
}
|
||||
|
||||
public override CookieCollection CookieCollection {
|
||||
get { return _context.Request.Cookies; }
|
||||
}
|
||||
|
120
websocket-sharp/Net/Sockets/TcpListenerWebSocketContext.cs
Normal file
120
websocket-sharp/Net/Sockets/TcpListenerWebSocketContext.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -35,6 +35,36 @@ namespace WebSocketSharp {
|
||||
|
||||
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
|
||||
|
||||
public ResponseHandshake()
|
||||
|
@@ -31,25 +31,84 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using WebSocketSharp.Frame;
|
||||
using WebSocketSharp.Net.Sockets;
|
||||
|
||||
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()
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private Thread _acceptClientThread;
|
||||
private IPAddress _address;
|
||||
private bool _isSelfHost;
|
||||
private int _port;
|
||||
private Dictionary<string, WebSocketService> _services;
|
||||
private TcpListener _tcpListener;
|
||||
private Uri _uri;
|
||||
|
||||
#endregion
|
||||
@@ -58,8 +117,7 @@ namespace WebSocketSharp.Server {
|
||||
|
||||
internal WebSocketServer()
|
||||
{
|
||||
_services = new Dictionary<string, WebSocketService>();
|
||||
_isSelfHost = false;
|
||||
init();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -67,16 +125,10 @@ namespace WebSocketSharp.Server {
|
||||
#region Public Constructors
|
||||
|
||||
public WebSocketServer(string url)
|
||||
: this()
|
||||
: base(url)
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
|
||||
string msg;
|
||||
if (!isValidUri(uri, out msg))
|
||||
throw new ArgumentException(msg, "url");
|
||||
|
||||
_tcpListener = new TcpListener(_address, _port);
|
||||
_isSelfHost = true;
|
||||
_uri = url.ToUri();
|
||||
init();
|
||||
}
|
||||
|
||||
public WebSocketServer(int port)
|
||||
@@ -85,7 +137,7 @@ namespace WebSocketSharp.Server {
|
||||
}
|
||||
|
||||
public WebSocketServer(int port, string path)
|
||||
: this()
|
||||
: base(IPAddress.Any, port)
|
||||
{
|
||||
var uri = path.ToUri();
|
||||
if (uri.IsAbsoluteUri)
|
||||
@@ -94,31 +146,13 @@ namespace WebSocketSharp.Server {
|
||||
throw new ArgumentException(msg, "path");
|
||||
}
|
||||
|
||||
_uri = uri;
|
||||
_address = IPAddress.Any;
|
||||
_port = port <= 0 ? 80 : port;
|
||||
|
||||
_tcpListener = new TcpListener(_address, _port);
|
||||
_isSelfHost = true;
|
||||
_uri = uri;
|
||||
init();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public IPAddress Address
|
||||
{
|
||||
get { return _address; }
|
||||
}
|
||||
|
||||
public bool IsSelfHost {
|
||||
get { return _isSelfHost; }
|
||||
}
|
||||
|
||||
public int Port
|
||||
{
|
||||
get { return _port; }
|
||||
}
|
||||
#region Property
|
||||
|
||||
public Uri Uri
|
||||
{
|
||||
@@ -127,104 +161,21 @@ namespace WebSocketSharp.Server {
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
#region Private Method
|
||||
|
||||
public event EventHandler<ErrorEventArgs> OnError;
|
||||
private void init()
|
||||
{
|
||||
_services = new Dictionary<string, WebSocketService>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
#region Protected Method
|
||||
|
||||
private void acceptClient()
|
||||
protected override void bindSocket(TcpClient client)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
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);
|
||||
var socket = new WebSocket(_uri, client);
|
||||
BindWebSocket(socket);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -238,23 +189,9 @@ namespace WebSocketSharp.Server {
|
||||
service.Start();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
public override void Stop()
|
||||
{
|
||||
if (!_isSelfHost)
|
||||
return;
|
||||
|
||||
_tcpListener.Start();
|
||||
startAcceptClientThread();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (_isSelfHost)
|
||||
{
|
||||
_tcpListener.Stop();
|
||||
_acceptClientThread.Join(5 * 1000);
|
||||
}
|
||||
|
||||
base.Stop();
|
||||
StopServices();
|
||||
}
|
||||
|
||||
|
233
websocket-sharp/Server/WebSocketServerBase.cs
Normal file
233
websocket-sharp/Server/WebSocketServerBase.cs
Normal 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
|
||||
}
|
||||
}
|
@@ -48,6 +48,7 @@ using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using WebSocketSharp.Frame;
|
||||
using WebSocketSharp.Net;
|
||||
using WebSocketSharp.Net.Sockets;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
@@ -62,27 +63,28 @@ namespace WebSocketSharp
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private string _base64key;
|
||||
private string _binaryType;
|
||||
private HttpListenerWebSocketContext _context;
|
||||
private IPEndPoint _endPoint;
|
||||
private AutoResetEvent _exitMessageLoop;
|
||||
private string _extensions;
|
||||
private Object _forClose;
|
||||
private Object _forSend;
|
||||
private int _fragmentLen;
|
||||
private bool _isClient;
|
||||
private bool _isSecure;
|
||||
private NetworkStream _netStream;
|
||||
private string _protocol;
|
||||
private string _protocols;
|
||||
private volatile WsState _readyState;
|
||||
private AutoResetEvent _receivedPong;
|
||||
private SslStream _sslStream;
|
||||
private TcpClient _tcpClient;
|
||||
private Uri _uri;
|
||||
private SynchronizedCollection<WsFrame> _unTransmittedBuffer;
|
||||
private IWsStream _wsStream;
|
||||
private string _base64key;
|
||||
private WebSocketSharp.Net.HttpListenerContext _baseContext;
|
||||
private string _binaryType;
|
||||
private WebSocketContext _context;
|
||||
private IPEndPoint _endPoint;
|
||||
private AutoResetEvent _exitMessageLoop;
|
||||
private string _extensions;
|
||||
private Object _forClose;
|
||||
private Object _forSend;
|
||||
private int _fragmentLen;
|
||||
private bool _isClient;
|
||||
private bool _isSecure;
|
||||
private NetworkStream _netStream;
|
||||
private string _protocol;
|
||||
private string _protocols;
|
||||
private volatile WsState _readyState;
|
||||
private AutoResetEvent _receivedPong;
|
||||
private SslStream _sslStream;
|
||||
private TcpClient _tcpClient;
|
||||
private Uri _uri;
|
||||
private SynchronizedCollection<WsFrame> _unTransmittedBuffer;
|
||||
private IWsStream _wsStream;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -105,13 +107,28 @@ namespace WebSocketSharp
|
||||
|
||||
#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)
|
||||
: this()
|
||||
{
|
||||
_uri = uri;
|
||||
_context = context;
|
||||
_isClient = false;
|
||||
_isSecure = _context.IsSecureConnection;
|
||||
_uri = uri;
|
||||
_context = context;
|
||||
_baseContext = context.BaseContext;
|
||||
_wsStream = context.Stream;
|
||||
_endPoint = _baseContext.Connection.LocalEndPoint;
|
||||
_isClient = false;
|
||||
_isSecure = context.IsSecureConnection;
|
||||
}
|
||||
|
||||
internal WebSocket(Uri uri, TcpClient tcpClient)
|
||||
@@ -325,11 +342,11 @@ namespace WebSocketSharp
|
||||
|
||||
private void closeConnection()
|
||||
{
|
||||
if (_context != null)
|
||||
if (_baseContext != null)
|
||||
{
|
||||
_context.BaseContext.Response.Close();
|
||||
_wsStream = null;
|
||||
_context = null;
|
||||
_baseContext.Response.Close();
|
||||
_wsStream = null;
|
||||
_baseContext = null;
|
||||
}
|
||||
|
||||
if (_wsStream != null)
|
||||
@@ -363,13 +380,10 @@ namespace WebSocketSharp
|
||||
private void createClientStream()
|
||||
{
|
||||
var host = _uri.DnsSafeHost;
|
||||
|
||||
var port = _uri.Port;
|
||||
if (port <= 0)
|
||||
{
|
||||
port = 80;
|
||||
if (IsSecure)
|
||||
port = 443;
|
||||
}
|
||||
port = IsSecure ? 443 : 80;
|
||||
|
||||
_tcpClient = new TcpClient(host, port);
|
||||
_netStream = _tcpClient.GetStream();
|
||||
@@ -378,7 +392,7 @@ namespace WebSocketSharp
|
||||
{
|
||||
RemoteCertificateValidationCallback validation = (sender, certificate, chain, sslPolicyErrors) =>
|
||||
{
|
||||
// Temporary implementation
|
||||
// FIXME: Always returns true
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -449,44 +463,20 @@ namespace WebSocketSharp
|
||||
|
||||
private void createServerStream()
|
||||
{
|
||||
if (_context != null)
|
||||
{
|
||||
_wsStream = createServerStreamFromContext();
|
||||
if (_wsStream != null)
|
||||
return;
|
||||
}
|
||||
|
||||
if (_tcpClient != null)
|
||||
{
|
||||
_wsStream = createServerStreamFromTcpClient();
|
||||
_wsStream = CreateServerStream(_tcpClient);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private IWsStream createServerStreamFromContext()
|
||||
{
|
||||
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)
|
||||
if (_baseContext != null)
|
||||
{
|
||||
_sslStream = new SslStream(_netStream);
|
||||
|
||||
var certPath = ConfigurationManager.AppSettings["ServerCertPath"];
|
||||
_sslStream.AuthenticateAsServer(new X509Certificate(certPath));
|
||||
|
||||
return new WsStream<SslStream>(_sslStream);
|
||||
_wsStream = CreateServerStream(_baseContext);
|
||||
return;
|
||||
}
|
||||
|
||||
return new WsStream<NetworkStream>(_netStream);
|
||||
}
|
||||
|
||||
private void doHandshake()
|
||||
@@ -695,20 +685,7 @@ namespace WebSocketSharp
|
||||
|
||||
private string[] readHandshake()
|
||||
{
|
||||
var buffer = new List<byte>();
|
||||
|
||||
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');
|
||||
return _wsStream.ReadHandshake();
|
||||
}
|
||||
|
||||
private MessageEventArgs receive()
|
||||
@@ -992,7 +969,7 @@ namespace WebSocketSharp
|
||||
Console.WriteLine("WS: Info@sendOpeningHandshake: Opening handshake from client:\n");
|
||||
Console.WriteLine(req.ToString());
|
||||
#endif
|
||||
_wsStream.Write(req.ToBytes(), 0, req.ToBytes().Length);
|
||||
_wsStream.WriteHandshake(req);
|
||||
|
||||
var res = ResponseHandshake.Parse(readHandshake());
|
||||
#if DEBUG
|
||||
@@ -1009,20 +986,14 @@ namespace WebSocketSharp
|
||||
Console.WriteLine("WS: Info@sendResponseHandshake: Response handshake from server:\n");
|
||||
Console.WriteLine(res.ToString());
|
||||
#endif
|
||||
_wsStream.Write(res.ToBytes(), 0, res.ToBytes().Length);
|
||||
_wsStream.WriteHandshake(res);
|
||||
}
|
||||
|
||||
private void sendResponseHandshakeForInvalid()
|
||||
{
|
||||
var code = (int)WebSocketSharp.Net.HttpStatusCode.BadRequest;
|
||||
var res = new ResponseHandshake {
|
||||
Reason = "Bad Request",
|
||||
StatusCode = code.ToString()
|
||||
};
|
||||
res.Headers.Clear();
|
||||
var res = ResponseHandshake.BadRequest;
|
||||
res.AddHeader("Sec-WebSocket-Version", _version);
|
||||
|
||||
_wsStream.Write(res.ToBytes(), 0, res.ToBytes().Length);
|
||||
_wsStream.WriteHandshake(res);
|
||||
}
|
||||
|
||||
private void startMessageThread()
|
||||
@@ -1040,6 +1011,39 @@ namespace WebSocketSharp
|
||||
|
||||
#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
|
||||
|
||||
public void Close()
|
||||
|
@@ -32,6 +32,7 @@ using System.IO;
|
||||
using System.Net.Security;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using WebSocketSharp.Frame;
|
||||
|
||||
namespace WebSocketSharp
|
||||
@@ -39,10 +40,16 @@ namespace WebSocketSharp
|
||||
public class WsStream<TStream> : IWsStream
|
||||
where TStream : Stream
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private TStream _innerStream;
|
||||
private Object _forRead;
|
||||
private Object _forWrite;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public WsStream(TStream innerStream)
|
||||
{
|
||||
Type streamType = typeof(TStream);
|
||||
@@ -62,6 +69,10 @@ namespace WebSocketSharp
|
||||
_forWrite = new object();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void 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)
|
||||
{
|
||||
lock (_forWrite)
|
||||
@@ -126,5 +158,16 @@ namespace WebSocketSharp
|
||||
_innerStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteHandshake(Handshake handshake)
|
||||
{
|
||||
lock (_forWrite)
|
||||
{
|
||||
var buffer = handshake.ToBytes();
|
||||
_innerStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -109,11 +109,14 @@
|
||||
<Compile Include="Net\HttpVersion.cs" />
|
||||
<Compile Include="Net\HttpStatusCode.cs" />
|
||||
<Compile Include="Server\IWebSocketServer.cs" />
|
||||
<Compile Include="Net\Sockets\TcpListenerWebSocketContext.cs" />
|
||||
<Compile Include="Server\WebSocketServerBase.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
<Folder Include="Frame\" />
|
||||
<Folder Include="Server\" />
|
||||
<Folder Include="Net\" />
|
||||
<Folder Include="Net\Sockets\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Binary file not shown.
Reference in New Issue
Block a user