diff --git a/Example/Program.cs b/Example/Program.cs
index b60af931..ae8a2089 100644
--- a/Example/Program.cs
+++ b/Example/Program.cs
@@ -8,29 +8,29 @@ using System.Threading;
using WebSocketSharp;
using WebSocketSharp.Net;
-namespace Example
-{
- public struct NfMessage
- {
+namespace Example {
+
+ public struct NfMessage {
+
public string Summary;
public string Body;
public string Icon;
}
- public class ThreadState
- {
+ public class ThreadState {
+
public bool Enabled { get; set; }
public AutoResetEvent Notification { get; private set; }
public ThreadState()
{
- Enabled = true;
+ Enabled = true;
Notification = new AutoResetEvent(false);
}
}
- public class Program
- {
+ public class Program {
+
private static Queue _msgQ = Queue.Synchronized(new Queue());
private static void enNfMessage(string summary, string body, string icon)
@@ -38,8 +38,8 @@ namespace Example
var msg = new NfMessage
{
Summary = summary,
- Body = body,
- Icon = icon
+ Body = body,
+ Icon = icon
};
_msgQ.Enqueue(msg);
@@ -47,7 +47,7 @@ namespace Example
public static void Main(string[] args)
{
- ThreadState ts = new ThreadState();
+ var ts = new ThreadState();
WaitCallback notifyMsg = state =>
{
@@ -57,11 +57,9 @@ namespace Example
if (_msgQ.Count > 0)
{
- NfMessage msg = (NfMessage)_msgQ.Dequeue();
+ var msg = (NfMessage)_msgQ.Dequeue();
#if NOTIFY
- Notification nf = new Notification(msg.Summary,
- msg.Body,
- msg.Icon);
+ var nf = new Notification(msg.Summary, msg.Body, msg.Icon);
nf.AddHint("append", "allowed");
nf.Show();
#else
@@ -75,15 +73,16 @@ namespace Example
ThreadPool.QueueUserWorkItem(notifyMsg);
- 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("ws://localhost:4649"))
- //using (WebSocket ws = new WebSocket("ws://localhost:4649/Echo"))
- //using (WebSocket ws = new WebSocket("ws://localhost:4649/Echo?name=nobita"))
- //using (WebSocket ws = new WebSocket("ws://localhost:4649/エコー?name=のび太"))
- //using (WebSocket ws = new WebSocket("ws://localhost:4649/Chat"))
- //using (WebSocket ws = new WebSocket("ws://localhost:4649/Chat?name=nobita"))
- //using (WebSocket ws = new WebSocket("ws://localhost:4649/チャット?name=のび太"))
+ using (var ws = new WebSocket("ws://echo.websocket.org", "echo"))
+ //using (var ws = new WebSocket("wss://echo.websocket.org", "echo"))
+ //using (var ws = new WebSocket("ws://localhost:4649"))
+ //using (var ws = new WebSocket("ws://localhost:4649/Echo"))
+ //using (var ws = new WebSocket("wss://localhost:4649/Echo"))
+ //using (var ws = new WebSocket("ws://localhost:4649/Echo?name=nobita"))
+ //using (var ws = new WebSocket("ws://localhost:4649/エコー?name=のび太"))
+ //using (var ws = new WebSocket("ws://localhost:4649/Chat"))
+ //using (var ws = new WebSocket("ws://localhost:4649/Chat?name=nobita"))
+ //using (var ws = new WebSocket("ws://localhost:4649/チャット?name=のび太"))
{
ws.OnOpen += (sender, e) =>
{
@@ -111,11 +110,16 @@ namespace Example
"notification-message-im");
};
- //ws.Origin = "http://echo.websocket.org";
- //ws.Compression = CompressionMethod.DEFLATE;
#if DEBUG
ws.Log.Level = LogLevel.TRACE;
#endif
+ //ws.Compression = CompressionMethod.DEFLATE;
+ //ws.Origin = "http://echo.websocket.org";
+ //ws.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
+ //{
+ // ws.Log.Debug(String.Format("\n{0}\n{1}", certificate.Issuer, certificate.Subject));
+ // return true;
+ //};
//ws.SetCookie(new Cookie("nobita", "\"idiot, gunfighter\""));
//ws.SetCookie(new Cookie("dora", "tanuki"));
ws.Connect();
diff --git a/Example2/App.config b/Example2/App.config
index 84bc00fa..5a8a3e5d 100644
--- a/Example2/App.config
+++ b/Example2/App.config
@@ -1,6 +1,7 @@
-
+
+
diff --git a/Example2/Example2.csproj b/Example2/Example2.csproj
index 65bdb259..685a1ef6 100644
--- a/Example2/Example2.csproj
+++ b/Example2/Example2.csproj
@@ -49,6 +49,7 @@
+
diff --git a/Example2/Program.cs b/Example2/Program.cs
index 9bc5cb1a..7b56e27d 100644
--- a/Example2/Program.cs
+++ b/Example2/Program.cs
@@ -1,58 +1,67 @@
using System;
+using System.Configuration;
+using System.Security.Cryptography.X509Certificates;
using WebSocketSharp;
using WebSocketSharp.Server;
-namespace Example2
-{
- public class Program
- {
- public static void Main(string[] args)
+namespace Example2 {
+
+ public class Program {
+
+ public static void Main (string [] args)
{
/* Single service server
- //var wssv = new WebSocketServiceHost("ws://localhost:4649");
- var wssv = new WebSocketServiceHost("ws://localhost:4649/Echo");
- //var wssv = new WebSocketServiceHost("ws://localhost:4649/エコー");
- //var wssv = new WebSocketServiceHost(4649);
- //var wssv = new WebSocketServiceHost(4649, "/Echo");
- //var wssv = new WebSocketServiceHost(4649, "/エコー");
- //var wssv = new WebSocketServiceHost("ws://localhost:4649");
- //var wssv = new WebSocketServiceHost("ws://localhost:4649/Chat");
- //var wssv = new WebSocketServiceHost("ws://localhost:4649/チャット");
- //var wssv = new WebSocketServiceHost(4649);
- //var wssv = new WebSocketServiceHost(4649, "/Chat");
- //var wssv = new WebSocketServiceHost(4649, "/チャット");
- //wssv.Sweeping = false; // Stop the sweep inactive session timer.
+ var wssv = new WebSocketServiceHost ("ws://localhost:4649");
+ //var wssv = new WebSocketServiceHost ("ws://localhost:4649/Echo");
+ //var wssv = new WebSocketServiceHost ("ws://localhost:4649/エコー");
+ //var wssv = new WebSocketServiceHost (4649);
+ //var wssv = new WebSocketServiceHost (4649, "/Echo");
+ //var wssv = new WebSocketServiceHost (4649, "/エコー");
+ //var wssv = new WebSocketServiceHost ("ws://localhost:4649");
+ //var wssv = new WebSocketServiceHost ("ws://localhost:4649/Chat");
+ //var wssv = new WebSocketServiceHost ("ws://localhost:4649/チャット");
+ //var wssv = new WebSocketServiceHost (4649);
+ //var wssv = new WebSocketServiceHost (4649, "/Chat");
+ //var wssv = new WebSocketServiceHost (4649, "/チャット");
+ #if DEBUG
+ wssv.Log.Level = LogLevel.TRACE;
+ #endif
+ //wssv.Sweeping = false;
- wssv.Start();
- Console.WriteLine(
+ wssv.Start ();
+ Console.WriteLine (
"WebSocket Service Host (url: {0})\n listening on address: {1} port: {2}\n",
wssv.Uri, wssv.Address, wssv.Port);
*/
- // Multi services server
- var wssv = new WebSocketServer(4649);
- //var wssv = new WebSocketServer("ws://localhost:4649");
+ /* Multi services server */
+ var wssv = new WebSocketServer (4649);
+ //var wssv = new WebSocketServer (4649, true);
+ //var wssv = new WebSocketServer ("ws://localhost:4649");
+ //var wssv = new WebSocketServer ("wss://localhost:4649");
#if DEBUG
wssv.Log.Level = LogLevel.TRACE;
#endif
- //wssv.Sweeping = false; // Stop the sweep inactive session timer.
- wssv.AddWebSocketService("/Echo");
- wssv.AddWebSocketService("/Chat");
- //wssv.AddWebSocketService("/エコー");
- //wssv.AddWebSocketService("/チャット");
+ //var file = ConfigurationManager.AppSettings ["ServerCertFile"];
+ //var password = ConfigurationManager.AppSettings ["CertFilePassword"];
+ //wssv.Certificate = new X509Certificate2 (file, password);
+ //wssv.Sweeping = false;
+ wssv.AddWebSocketService ("/Echo");
+ wssv.AddWebSocketService ("/Chat");
+ //wssv.AddWebSocketService ("/エコー");
+ //wssv.AddWebSocketService ("/チャット");
- wssv.Start();
- Console.WriteLine(
+ wssv.Start ();
+ Console.WriteLine (
"WebSocket Server listening on port: {0} service path:", wssv.Port);
foreach (var path in wssv.ServicePaths)
- Console.WriteLine(" {0}", path);
- Console.WriteLine();
-
+ Console.WriteLine (" {0}", path);
- Console.WriteLine("Press any key to stop server...");
- Console.ReadLine();
+ Console.WriteLine ();
+ Console.WriteLine ("Press enter key to stop server...");
+ Console.ReadLine ();
- wssv.Stop();
+ wssv.Stop ();
}
}
}
diff --git a/README.md b/README.md
index d6149d21..ce51939a 100644
--- a/README.md
+++ b/README.md
@@ -71,7 +71,7 @@ ws.OnOpen += (sender, e) =>
};
```
-`e` has come across as `EventArgs.Empty`, so there is no operation on `e`.
+`e` has come across as `EventArgs.Empty`, so you don't use `e`.
##### WebSocket.OnMessage event #####
@@ -84,7 +84,11 @@ ws.OnMessage += (sender, e) =>
};
```
-`e.Type` (`WebSocketSharp.MessageEventArgs.Type`, the type of this property is `WebSocketSharp.Opcode`) indicates the **Frame type** of a WebSocket frame, so by checking this property, you determine which item you should operate.
+`e.Type` (`WebSocketSharp.MessageEventArgs.Type`, the type of this property is `WebSocketSharp.Opcode`) indicates the **Frame Type** of a WebSocket frame, so by checking this property, you determine which item you should use.
+
+If `e.Type` equals `Opcode.TEXT`, you use `e.Data` (`WebSocketSharp.MessageEventArgs.Data`, the type of this property is `string`) that contains the received data.
+
+If `e.Type` equals `Opcode.BINARY`, you use `e.RawData` (`WebSocketSharp.MessageEventArgs.RawData`, the type of this property is `byte[]`) that contains the received data.
```cs
if (e.Type == Opcode.TEXT)
@@ -100,10 +104,6 @@ if (e.Type == Opcode.BINARY)
}
```
-If `e.Type` equaled `Opcode.TEXT`, you would operate `e.Data` (`WebSocketSharp.MessageEventArgs.Data`, the type of this property is `string`).
-
-If `e.Type` equaled `Opcode.BINARY`, you would operate `e.RawData` (`WebSocketSharp.MessageEventArgs.RawData`, the type of this property is `byte[]`).
-
##### WebSocket.OnError event #####
A `WebSocket.OnError` event occurs when the `WebSocket` gets an error.
@@ -114,7 +114,7 @@ ws.OnError += (sender, e) =>
...
};
```
-`e.Message` (`WebSocketSharp.ErrorEventArgs.Message`, the type of this property is `string`) contains an error message, so you operate this.
+`e.Message` (`WebSocketSharp.ErrorEventArgs.Message`, the type of this property is `string`) contains an error message, so you use this.
##### WebSocket.OnClose event #####
@@ -127,7 +127,7 @@ ws.OnClose += (sender, e) =>
};
```
-`e.Code` (`WebSocketSharp.CloseEventArgs.Code`, the type of this property is `ushort`) contains a status code indicating the reason for closure and `e.Reason` (`WebSocketSharp.CloseEventArgs.Reason`, the type of this property is `string`) contains the reason for closure, so you operate these.
+`e.Code` (`WebSocketSharp.CloseEventArgs.Code`, the type of this property is `ushort`) contains a status code indicating the reason for closure and `e.Reason` (`WebSocketSharp.CloseEventArgs.Reason`, the type of this property is `string`) contains the reason for closure, so you use these.
#### Step 4 ####
@@ -157,7 +157,7 @@ Closing the WebSocket connection.
ws.Close(code, reason);
```
-If you wanted to close the WebSocket connection explicitly, you would use the `Close` method.
+If you want to close the WebSocket connection explicitly, you can use the `Close` method.
And the `Close` method is overloaded. The types of `code` are `WebSocketSharp.CloseStatusCode` and `ushort`, the type of `reason` is `string`.
@@ -176,7 +176,7 @@ namespace Example {
{
protected override void OnMessage(MessageEventArgs e)
{
- var msg = e.Data.ToLower().Equals("balus")
+ var msg = e.Data.ToLower() == "balus"
? "I've been balused already..."
: "I'm not available now.";
Send(msg);
@@ -266,7 +266,7 @@ You can add any WebSocket service with a specified path to the service to your `
The type of `T` inherits `WebSocketService` class, so you can use a class that was created in **Step 2**.
-If you created a instance of the `WebSocketServer` class without the port number, the `WebSocketServer` would set the port number to **80** automatically. So it is necessary to run with root permission.
+If you create a instance of the `WebSocketServer` class without the port number, the `WebSocketServer` set the port number to **80** automatically. So it is necessary to run with root permission.
$ sudo mono example2.exe
@@ -285,7 +285,7 @@ wssv.OnError += (sender, e) =>
};
```
-`e.Message` (`WebSocketSharp.ErrorEventArgs.Message`, the type of this property is `string`) contains an error message, so you operate this.
+`e.Message` (`WebSocketSharp.ErrorEventArgs.Message`, the type of this property is `string`) contains an error message, so you use this.
##### WebSocketServer.OnError event #####
@@ -320,21 +320,51 @@ httpsv.AddWebSocketService("/");
For more information, could you see **[Example3]**?
+### Secure Connection ###
+
+As a **WebSocket Client**, creating a instance of the `WebSocket` class with the WebSocket URL with the **wss** scheme.
+
+```cs
+using (var ws = new WebSocket("wss://example.com"))
+{
+ ...
+}
+```
+
+If you want to set the custom validation for the server certificate, you can use the `WebSocket.ServerCertificateValidationCallback` property.
+
+```cs
+ws.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
+{
+ // Do something to validate the server certificate.
+ return true; // The server certificate is valid.
+};
+```
+
+If you set this property to nothing, the validation does nothing with the server certificate, always returns valid.
+
+As a **WebSocket Server**, creating and setting a instance of the WebSocket server with some settings for the secure connection.
+
+```cs
+var wssv = new WebSocketServer(4649, true);
+wssv.Certificate = new X509Certificate2("/path/to/cert.pfx", "password for cert.pfx");
+```
+
### Logging ###
The `WebSocket` class includes own logging functions.
The `WebSocket.Log` property provides the logging functions.
-If you wanted to change the current logging level (the default is the `LogLevel.ERROR`), you would operate the `WebSocket.Log.Level` property.
+If you want to change the current logging level (the default is `LogLevel.ERROR`), you can use the `WebSocket.Log.Level` property.
```cs
ws.Log.Level = LogLevel.DEBUG;
```
-This setting means that the logging outputs with a less than the `LogLevel.DEBUG` are not outputted.
+This setting means that the logging outputs with a less than `LogLevel.DEBUG` are not outputted.
-And if you wanted to output a log, you would use some output methods. The following outputs a log with the `LogLevel.DEBUG`.
+And if you want to output a log, you can use some output methods. The following outputs a log with `LogLevel.DEBUG`.
```cs
ws.Log.Debug("This is a debug message.");
@@ -354,7 +384,7 @@ Examples of using **websocket-sharp**.
[Example1] connects to the [Audio Data delivery server] using the WebSocket ([Example1] is only implemented the chat feature, still unfinished).
-And [Example1] uses the [Json.NET].
+And [Example1] uses [Json.NET].
### Example2 ###
diff --git a/websocket-sharp/AssemblyInfo.cs b/websocket-sharp/AssemblyInfo.cs
index 4db7a594..c85deaa4 100644
--- a/websocket-sharp/AssemblyInfo.cs
+++ b/websocket-sharp/AssemblyInfo.cs
@@ -5,7 +5,7 @@ using System.Runtime.CompilerServices;
// Change them to the values specific to your project.
[assembly: AssemblyTitle("websocket-sharp")]
-[assembly: AssemblyDescription("A C# implementation of the WebSocket protocol client & server")]
+[assembly: AssemblyDescription("A C# implementation of the WebSocket protocol client and server")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("websocket-sharp.dll")]
diff --git a/websocket-sharp/Ext.cs b/websocket-sharp/Ext.cs
index c67192b8..07167252 100644
--- a/websocket-sharp/Ext.cs
+++ b/websocket-sharp/Ext.cs
@@ -45,6 +45,7 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Sockets;
+using System.Security.Cryptography.X509Certificates;
using System.Text;
using WebSocketSharp.Net;
using WebSocketSharp.Net.WebSockets;
@@ -282,6 +283,12 @@ namespace WebSocketSharp {
: null;
}
+ internal static TcpListenerWebSocketContext GetWebSocketContext(
+ this TcpClient client, bool secure, X509Certificate cert)
+ {
+ return new TcpListenerWebSocketContext(client, secure, cert);
+ }
+
//
// Determines whether the specified object is .
//
@@ -532,60 +539,6 @@ namespace WebSocketSharp {
#region Public Methods
- ///
- /// Accepts a WebSocket connection by the .
- ///
- ///
- /// A that contains a WebSocket connection.
- ///
- ///
- /// A that provides a TCP connection to accept a WebSocket connection.
- ///
- ///
- /// A that indicates a secure connection or not. (true indicates a secure connection.)
- ///
- ///
- /// is .
- ///
- public static TcpListenerWebSocketContext AcceptWebSocket(this TcpListener listener, bool secure)
- {
- if (listener == null)
- throw new ArgumentNullException("listener");
-
- var client = listener.AcceptTcpClient();
- return new TcpListenerWebSocketContext(client, secure);
- }
-
- ///
- /// Accepts a WebSocket connection asynchronously by the .
- ///
- ///
- /// A that provides a TCP connection to accept a WebSocket connection.
- ///
- ///
- /// A that indicates a secure connection or not. (true indicates a secure connection.)
- ///
- ///
- /// An Action<TcpListenerWebSocketContext> delegate that contains the method(s) that is called when an asynchronous operation completes.
- ///
- ///
- /// is .
- ///
- public static void AcceptWebSocketAsync(this TcpListener listener, bool secure, Action completed)
- {
- if (listener == null)
- throw new ArgumentNullException("listener");
-
- AsyncCallback callback = (ar) =>
- {
- var client = listener.EndAcceptTcpClient(ar);
- var context = new TcpListenerWebSocketContext(client, secure);
- completed(context);
- };
-
- listener.BeginAcceptTcpClient(callback, null);
- }
-
///
/// Determines whether the specified contains any of characters
/// in the specified array of .
diff --git a/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs b/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs
index 32cecfb8..7e174ca2 100644
--- a/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs
+++ b/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs
@@ -30,12 +30,13 @@ using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net.Sockets;
+using System.Security.Cryptography.X509Certificates;
using System.Security.Principal;
namespace WebSocketSharp.Net.WebSockets {
///
- /// Provides access to the WebSocket connection request objects received by the class.
+ /// Provides access to the WebSocket connection request objects received by the .
///
///
///
@@ -44,22 +45,22 @@ namespace WebSocketSharp.Net.WebSockets {
#region Private Fields
private CookieCollection _cookies;
- private TcpClient _tcpClient;
- private bool _isSecure;
+ private TcpClient _client;
private RequestHandshake _request;
+ private bool _secure;
+ private WsStream _stream;
private WebSocket _websocket;
- private WsStream _wsStream;
#endregion
#region Internal Constructors
- internal TcpListenerWebSocketContext(TcpClient tcpClient, bool secure)
+ internal TcpListenerWebSocketContext(TcpClient client, bool secure, X509Certificate cert)
{
- _tcpClient = tcpClient;
- _isSecure = secure;
- _wsStream = WsStream.CreateServerStream(tcpClient, secure);
- _request = RequestHandshake.Parse(_wsStream.ReadHandshake());
+ _client = client;
+ _secure = secure;
+ _stream = WsStream.CreateServerStream(client, secure, cert);
+ _request = RequestHandshake.Parse(_stream.ReadHandshake());
_websocket = new WebSocket(this);
}
@@ -69,7 +70,7 @@ namespace WebSocketSharp.Net.WebSockets {
internal WsStream Stream {
get {
- return _wsStream;
+ return _stream;
}
}
@@ -85,7 +86,7 @@ namespace WebSocketSharp.Net.WebSockets {
///
public override CookieCollection CookieCollection {
get {
- if (_cookies.IsNull())
+ if (_cookies == null)
_cookies = _request.Cookies;
return _cookies;
@@ -139,7 +140,7 @@ namespace WebSocketSharp.Net.WebSockets {
///
public override bool IsSecureConnection {
get {
- return _isSecure;
+ return _secure;
}
}
@@ -260,7 +261,7 @@ namespace WebSocketSharp.Net.WebSockets {
///
public virtual System.Net.IPEndPoint ServerEndPoint {
get {
- return (System.Net.IPEndPoint)_tcpClient.Client.LocalEndPoint;
+ return (System.Net.IPEndPoint)_client.Client.LocalEndPoint;
}
}
@@ -287,7 +288,7 @@ namespace WebSocketSharp.Net.WebSockets {
///
public virtual System.Net.IPEndPoint UserEndPoint {
get {
- return (System.Net.IPEndPoint)_tcpClient.Client.RemoteEndPoint;
+ return (System.Net.IPEndPoint)_client.Client.RemoteEndPoint;
}
}
@@ -309,8 +310,8 @@ namespace WebSocketSharp.Net.WebSockets {
internal void Close()
{
- _wsStream.Close();
- _tcpClient.Close();
+ _stream.Close();
+ _client.Close();
}
#endregion
diff --git a/websocket-sharp/Server/WebSocketServerBase.cs b/websocket-sharp/Server/WebSocketServerBase.cs
index 62fc50ee..c9f62d6d 100644
--- a/websocket-sharp/Server/WebSocketServerBase.cs
+++ b/websocket-sharp/Server/WebSocketServerBase.cs
@@ -30,6 +30,7 @@ using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
+using System.Security.Cryptography.X509Certificates;
using System.Threading;
using WebSocketSharp.Net.WebSockets;
@@ -45,15 +46,16 @@ namespace WebSocketSharp.Server {
#region Private Fields
- private IPAddress _address;
- private bool _listening;
- private Logger _logger;
- private int _port;
- private Thread _receiveRequestThread;
- private bool _secure;
- private bool _selfHost;
- private TcpListener _tcpListener;
- private Uri _uri;
+ private IPAddress _address;
+ private X509Certificate2 _cert;
+ private bool _listening;
+ private Logger _logger;
+ private int _port;
+ private Thread _receiveRequestThread;
+ private bool _secure;
+ private bool _selfHost;
+ private TcpListener _listener;
+ private Uri _uri;
#endregion
@@ -63,7 +65,7 @@ namespace WebSocketSharp.Server {
/// Initializes a new instance of the class.
///
///
- /// This constructor initializes a new instance of this class as non self host.
+ /// This constructor initializes a new instance of this class as non self hosted server.
///
protected WebSocketServerBase()
: this(new Logger())
@@ -75,7 +77,7 @@ namespace WebSocketSharp.Server {
/// with the specified .
///
///
- /// This constructor initializes a new instance of this class as non self host.
+ /// This constructor initializes a new instance of this class as non self hosted server.
///
///
/// A that provides the logging functions.
@@ -104,7 +106,7 @@ namespace WebSocketSharp.Server {
if (url.IsNull())
throw new ArgumentNullException("url");
- Uri uri;
+ Uri uri;
string msg;
if (!tryCreateUri(url, out uri, out msg))
throw new ArgumentException(msg, "url");
@@ -208,6 +210,25 @@ namespace WebSocketSharp.Server {
}
}
+ ///
+ /// 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.
///
@@ -303,7 +324,7 @@ namespace WebSocketSharp.Server {
_listening = false;
_logger = new Logger();
_selfHost = true;
- _tcpListener = new TcpListener(_address, _port);
+ _listener = new TcpListener(_address, _port);
}
private void init(Uri uri)
@@ -320,13 +341,13 @@ namespace WebSocketSharp.Server {
init();
}
- private void processRequestAsync(TcpListenerWebSocketContext context)
+ private void processRequestAsync(TcpClient client)
{
- WaitCallback callback = (state) =>
+ WaitCallback callback = state =>
{
try
{
- AcceptWebSocket(context);
+ AcceptWebSocket(client.GetWebSocketContext(_secure, _cert));
}
catch (Exception ex)
{
@@ -344,11 +365,11 @@ namespace WebSocketSharp.Server {
{
try
{
- processRequestAsync(_tcpListener.AcceptWebSocket(_secure));
+ processRequestAsync(_listener.AcceptTcpClient());
}
catch (SocketException)
{
- // TcpListener has been stopped.
+ _logger.Info("TcpListener has been stopped.");
break;
}
catch (Exception ex)
@@ -368,7 +389,7 @@ namespace WebSocketSharp.Server {
_receiveRequestThread.Start();
}
- private bool tryCreateUri(string uriString, out Uri result, out string message)
+ private static bool tryCreateUri(string uriString, out Uri result, out string message)
{
if (!uriString.TryCreateWebSocketUri(out result, out message))
return false;
@@ -422,7 +443,16 @@ namespace WebSocketSharp.Server {
if (!_selfHost || _listening)
return;
- _tcpListener.Start();
+ if (_secure && _cert == null)
+ {
+ var msg = "Secure connection requires a server certificate.";
+ _logger.Error(msg);
+ error(msg);
+
+ return;
+ }
+
+ _listener.Start();
startReceiveRequestThread();
_listening = true;
}
@@ -435,7 +465,7 @@ namespace WebSocketSharp.Server {
if (!_selfHost || !_listening)
return;
- _tcpListener.Stop();
+ _listener.Stop();
_receiveRequestThread.Join(5 * 1000);
_listening = false;
}
diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs
index 466590a9..4d7e1677 100644
--- a/websocket-sharp/WebSocket.cs
+++ b/websocket-sharp/WebSocket.cs
@@ -38,6 +38,7 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Sockets;
+using System.Net.Security;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
@@ -66,6 +67,8 @@ namespace WebSocketSharp {
#region Private Fields
private string _base64key;
+ private RemoteCertificateValidationCallback
+ _certValidationCallback;
private bool _client;
private Action _closeContext;
private CookieCollection _cookies;
@@ -162,9 +165,8 @@ namespace WebSocketSharp {
_uri = uri;
_protocols = protocols.ToString(", ");
_client = true;
- _secure = uri.Scheme == "wss"
- ? true
- : false;
+ _secure = uri.Scheme == "wss" ? true : false;
+ _base64key = createBase64Key();
}
///
@@ -226,6 +228,12 @@ namespace WebSocketSharp {
}
}
+ internal bool IsOpened {
+ get {
+ return _readyState == WsState.OPEN || _readyState == WsState.CLOSING;
+ }
+ }
+
#endregion
#region Public Properties
@@ -243,8 +251,14 @@ namespace WebSocketSharp {
}
set {
- if (isOpened(true))
+ if (IsOpened)
+ {
+ var msg = "The WebSocket connection has already been established.";
+ _logger.Error(msg);
+ error(msg);
+
return;
+ }
_compression = value;
}
@@ -363,19 +377,25 @@ namespace WebSocketSharp {
}
set {
- if (isOpened(true))
- return;
-
- if (value.IsNullOrEmpty())
+ string msg = null;
+ if (IsOpened)
+ {
+ msg = "The WebSocket connection has already been established.";
+ }
+ else if (value.IsNullOrEmpty())
{
_origin = String.Empty;
return;
}
-
- var origin = new Uri(value);
- if (!origin.IsAbsoluteUri || origin.Segments.Length > 1)
+ else
+ {
+ var origin = new Uri(value);
+ if (!origin.IsAbsoluteUri || origin.Segments.Length > 1)
+ msg = "The syntax of value of Origin must be '://[:]'.";
+ }
+
+ if (msg != null)
{
- var msg = "The syntax of value of Origin must be '://[:]'.";
_logger.Error(msg);
error(msg);
@@ -410,6 +430,27 @@ namespace WebSocketSharp {
}
}
+ ///
+ /// Gets or sets the callback used to validate the certificate supplied by the server.
+ ///
+ ///
+ /// If the value of this property is , the validation does nothing
+ /// with the server certificate, always returns valid.
+ ///
+ ///
+ /// A delegate that references the method(s)
+ /// used to validate the server certificate. The default is .
+ ///
+ public RemoteCertificateValidationCallback ServerCertificateValidationCallback {
+ get {
+ return _certValidationCallback;
+ }
+
+ set {
+ _certValidationCallback = value;
+ }
+ }
+
///
/// Gets the WebSocket URL to connect.
///
@@ -777,7 +818,7 @@ namespace WebSocketSharp {
// As client
private bool doHandshake()
{
- init();
+ setWsStream();
return processResponseHandshake(sendRequestHandshake());
}
@@ -799,24 +840,13 @@ namespace WebSocketSharp {
return CompressionMethod.NONE;
}
- // As client
- private void init()
- {
- _base64key = createBase64Key();
-
- var host = _uri.DnsSafeHost;
- var port = _uri.Port;
- _tcpClient = new TcpClient(host, port);
- _wsStream = WsStream.CreateClientStream(_tcpClient, host, _secure);
- }
-
// As server
private void init(WebSocketContext context)
{
_context = context;
- _uri = context.Path.ToUri();
- _secure = context.IsSecureConnection;
- _client = false;
+ _uri = context.Path.ToUri();
+ _secure = context.IsSecureConnection;
+ _client = false;
}
private static bool isCompressionExtension(string value)
@@ -832,21 +862,6 @@ namespace WebSocketSharp {
: false;
}
- private bool isOpened(bool errorIfOpened)
- {
- if (_readyState != WsState.OPEN && _readyState != WsState.CLOSING)
- return false;
-
- if (errorIfOpened)
- {
- var msg = "The WebSocket connection has been established already.";
- _logger.Error(msg);
- error(msg);
- }
-
- return true;
- }
-
// As server
private bool isValidHostHeader()
{
@@ -1351,6 +1366,15 @@ namespace WebSocketSharp {
send(res);
}
+ // As client
+ private void setWsStream()
+ {
+ var host = _uri.DnsSafeHost;
+ var port = _uri.Port;
+ _tcpClient = new TcpClient(host, port);
+ _wsStream = WsStream.CreateClientStream(_tcpClient, _secure, host, _certValidationCallback);
+ }
+
private void startReceiving()
{
_exitReceiving = new AutoResetEvent(false);
@@ -1480,8 +1504,14 @@ namespace WebSocketSharp {
///
public void Connect()
{
- if (isOpened(true))
+ if (IsOpened)
+ {
+ var msg = "The WebSocket connection has already been established.";
+ _logger.Error(msg);
+ error(msg);
+
return;
+ }
try
{
@@ -1690,12 +1720,14 @@ namespace WebSocketSharp {
///
public void SetCookie(Cookie cookie)
{
- if (isOpened(true))
- return;
+ var msg = IsOpened
+ ? "The WebSocket connection has already been established."
+ : cookie == null
+ ? "'cookie' must not be null."
+ : null;
- if (cookie == null)
+ if (msg != null)
{
- var msg = "'cookie' must not be null.";
_logger.Error(msg);
error(msg);
@@ -1723,24 +1755,28 @@ namespace WebSocketSharp {
///
public void SetCredentials(string userName, string password, bool preAuth)
{
- if (isOpened(true))
- return;
-
- if (userName == null)
+ string msg = null;
+ if (IsOpened)
+ {
+ msg = "The WebSocket connection has already been established.";
+ }
+ else if (userName == null)
{
_credentials = null;
_preAuth = false;
return;
}
+ else
+ {
+ msg = userName.Length > 0 && (userName.Contains(':') || !userName.IsText())
+ ? "'userName' contains an invalid character."
+ : !password.IsNullOrEmpty() && !password.IsText()
+ ? "'password' contains an invalid character."
+ : null;
+ }
- var msg = userName.Length > 0 && (userName.Contains(':') || !userName.IsText())
- ? "'userName' contains an invalid character."
- : !password.IsNullOrEmpty() && !password.IsText()
- ? "'password' contains an invalid character."
- : String.Empty;
-
- if (msg.Length > 0)
+ if (msg != null)
{
_logger.Error(msg);
error(msg);
diff --git a/websocket-sharp/WsStream.cs b/websocket-sharp/WsStream.cs
index 585ea176..7e872fb5 100644
--- a/websocket-sharp/WsStream.cs
+++ b/websocket-sharp/WsStream.cs
@@ -28,7 +28,6 @@
using System;
using System.Collections.Generic;
-using System.Configuration;
using System.IO;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
@@ -119,18 +118,20 @@ namespace WebSocketSharp {
#region Internal Methods
- internal static WsStream CreateClientStream(TcpClient tcpClient, string host, bool secure)
+ internal static WsStream CreateClientStream(
+ TcpClient client,
+ bool secure,
+ string host,
+ System.Net.Security.RemoteCertificateValidationCallback validationCallback
+ )
{
- var netStream = tcpClient.GetStream();
+ var netStream = client.GetStream();
if (secure)
{
- System.Net.Security.RemoteCertificateValidationCallback callback = (sender, certificate, chain, sslPolicyErrors) =>
- {
- // FIXME: Always returns true
- return true;
- };
+ if (validationCallback == null)
+ validationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
- var sslStream = new SslStream(netStream, false, callback);
+ var sslStream = new SslStream(netStream, false, validationCallback);
sslStream.AuthenticateAsClient(host);
return new WsStream(sslStream);
@@ -139,14 +140,13 @@ namespace WebSocketSharp {
return new WsStream(netStream);
}
- internal static WsStream CreateServerStream(TcpClient tcpClient, bool secure)
+ internal static WsStream CreateServerStream(TcpClient client, bool secure, X509Certificate cert)
{
- var netStream = tcpClient.GetStream();
+ var netStream = client.GetStream();
if (secure)
{
var sslStream = new SslStream(netStream, false);
- var certPath = ConfigurationManager.AppSettings["ServerCertPath"];
- sslStream.AuthenticateAsServer(new X509Certificate2(certPath));
+ sslStream.AuthenticateAsServer(cert);
return new WsStream(sslStream);
}