From 2db289a6585aa92cd1d89816d1488076f5d83047 Mon Sep 17 00:00:00 2001 From: Zazzmatazz Date: Fri, 2 Jun 2017 09:19:47 -0400 Subject: [PATCH 1/3] Added TLS1.2 support to client and server. Added MqttClientSslChannel and MqttServerSslChannel which both utilize an SSL stream. Added options to both MqttCLientOptions and MqttServerOptions. I was unable to update the code in MQTTnet.UniversalWindows due to my lack of Windows 10. --- .../MQTTnet.NetCoreApp/MqttClientFactory.cs | 7 +- .../MqttClientSslChannel.cs | 122 +++++++++++++++++ .../MQTTnet.NetCoreApp/MqttServerFactory.cs | 4 +- .../MqttServerSslChannel.cs | 123 ++++++++++++++++++ .../MqttSslServerAdapter.cs | 64 +++++++++ .../MQTTnet.NetFramework.csproj | 3 + .../MQTTnet.NetFramework/MqttClientFactory.cs | 9 +- .../MqttClientSslChannel.cs | 122 +++++++++++++++++ .../MQTTnet.NetFramework/MqttServerFactory.cs | 6 +- .../MqttServerSslChannel.cs | 123 ++++++++++++++++++ .../MqttSslServerAdapter.cs | 64 +++++++++ MQTTnet.Core/Client/MqttClientOptions.cs | 19 +++ MQTTnet.Core/Server/MqttServerOptions.cs | 7 + 13 files changed, 667 insertions(+), 6 deletions(-) create mode 100644 Frameworks/MQTTnet.NetCoreApp/MqttClientSslChannel.cs create mode 100644 Frameworks/MQTTnet.NetCoreApp/MqttServerSslChannel.cs create mode 100644 Frameworks/MQTTnet.NetCoreApp/MqttSslServerAdapter.cs create mode 100644 Frameworks/MQTTnet.NetFramework/MqttClientSslChannel.cs create mode 100644 Frameworks/MQTTnet.NetFramework/MqttServerSslChannel.cs create mode 100644 Frameworks/MQTTnet.NetFramework/MqttSslServerAdapter.cs diff --git a/Frameworks/MQTTnet.NetCoreApp/MqttClientFactory.cs b/Frameworks/MQTTnet.NetCoreApp/MqttClientFactory.cs index 4da24a1..62b6569 100644 --- a/Frameworks/MQTTnet.NetCoreApp/MqttClientFactory.cs +++ b/Frameworks/MQTTnet.NetCoreApp/MqttClientFactory.cs @@ -1,5 +1,6 @@ using System; using MQTTnet.Core.Adapter; +using MQTTnet.Core.Channel; using MQTTnet.Core.Client; using MQTTnet.Core.Serializer; @@ -11,7 +12,11 @@ namespace MQTTnet { if (options == null) throw new ArgumentNullException(nameof(options)); - return new MqttClient(options, new MqttChannelCommunicationAdapter(new MqttTcpChannel(), new DefaultMqttV311PacketSerializer())); + return new MqttClient(options, + // The cast to IMqttCommunicationChannel is required... Roslyn is too stupid to + // figure out how to cast back to the base type + new MqttChannelCommunicationAdapter(options.UseSSL ? new MqttClientSslChannel() : (IMqttCommunicationChannel) new MqttTcpChannel(), + new DefaultMqttV311PacketSerializer())); } } } diff --git a/Frameworks/MQTTnet.NetCoreApp/MqttClientSslChannel.cs b/Frameworks/MQTTnet.NetCoreApp/MqttClientSslChannel.cs new file mode 100644 index 0000000..26b12fb --- /dev/null +++ b/Frameworks/MQTTnet.NetCoreApp/MqttClientSslChannel.cs @@ -0,0 +1,122 @@ +using System; +using System.IO; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Authentication; +using System.Threading.Tasks; +using MQTTnet.Core.Channel; +using MQTTnet.Core.Client; +using MQTTnet.Core.Exceptions; + +namespace MQTTnet +{ + /// + /// Describes an SSL channel to an MQTT server. + /// + public class MqttClientSslChannel : IMqttCommunicationChannel, IDisposable + { + private readonly Socket _socket; + private SslStream _sslStream; + + /// + /// Creates a new . + /// + public MqttClientSslChannel() + { + _socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + } + + /// + /// Creates a new with a predefined . + /// + /// + public MqttClientSslChannel(Socket socket) + { + _socket = socket ?? throw new ArgumentNullException(nameof(socket)); + } + + /// + /// Asynchronously connects to the host described in the . + /// + /// The describing the connection. + public async Task ConnectAsync(MqttClientOptions options) + { + try + { + await _socket.ConnectAsync(options.Server, options.Port); + + NetworkStream ns = new NetworkStream(_socket, true); + _sslStream = new SslStream(ns); + + await _sslStream.AuthenticateAsClientAsync(options.Server, null, SslProtocols.Tls12, false); + + } + catch (SocketException exception) + { + throw new MqttCommunicationException(exception); + } + } + + /// + /// Asynchronously disconnects the client from the server. + /// + public Task DisconnectAsync() + { + try + { + _socket.Dispose(); + return Task.FromResult(0); + } + catch (SocketException exception) + { + throw new MqttCommunicationException(exception); + } + } + + /// + /// Asynchronously writes a sequence of bytes to the socket. + /// + /// The buffer to write data from. + public async Task WriteAsync(byte[] buffer) + { + if (buffer == null) + throw new ArgumentNullException(nameof(buffer)); + + try + { + await _sslStream.WriteAsync(buffer, 0, buffer.Length); + } + catch (Exception ex) + when (ex is SocketException || ex is IOException) + { + throw new MqttCommunicationException(ex); + } + } + + /// + /// Asynchronously reads a sequence of bytes from the socket. + /// + /// The buffer to write the data into. + public async Task ReadAsync(byte[] buffer) + { + try + { + await _sslStream.ReadAsync(buffer, 0, buffer.Length); + } + catch (Exception ex) + when (ex is SocketException || ex is IOException) + { + throw new MqttCommunicationException(ex); + } + } + + /// + /// Releases all resources used by the . + /// + public void Dispose() + { + _sslStream?.Dispose(); + _socket?.Dispose(); + } + } +} \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetCoreApp/MqttServerFactory.cs b/Frameworks/MQTTnet.NetCoreApp/MqttServerFactory.cs index a725426..5098ea2 100644 --- a/Frameworks/MQTTnet.NetCoreApp/MqttServerFactory.cs +++ b/Frameworks/MQTTnet.NetCoreApp/MqttServerFactory.cs @@ -1,4 +1,5 @@ using System; +using MQTTnet.Core.Adapter; using MQTTnet.Core.Server; namespace MQTTnet @@ -9,7 +10,8 @@ namespace MQTTnet { if (options == null) throw new ArgumentNullException(nameof(options)); - return new MqttServer(options, new MqttServerAdapter()); + // The cast to IMqttServerAdapter is required... stupidly... + return new MqttServer(options, options.UseSSL ? (IMqttServerAdapter)new MqttSslServerAdapter() : new MqttServerAdapter()); } } } diff --git a/Frameworks/MQTTnet.NetCoreApp/MqttServerSslChannel.cs b/Frameworks/MQTTnet.NetCoreApp/MqttServerSslChannel.cs new file mode 100644 index 0000000..c4c5713 --- /dev/null +++ b/Frameworks/MQTTnet.NetCoreApp/MqttServerSslChannel.cs @@ -0,0 +1,123 @@ +using System; +using System.IO; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; +using MQTTnet.Core.Channel; +using MQTTnet.Core.Client; +using MQTTnet.Core.Exceptions; + +namespace MQTTnet +{ + /// + /// Describes an SSL channel to a client. + /// + public class MqttServerSslChannel : IMqttCommunicationChannel, IDisposable + { + private readonly Socket _socket; + private readonly SslStream _sslStream; + private readonly X509Certificate2 _cert; + + /// + /// Creates a new with a predefined . + /// + /// The client socket. + /// The X509 certificate used to authenticate as a server. + public MqttServerSslChannel(Socket socket, X509Certificate2 cert) + { + _socket = socket ?? throw new ArgumentNullException(nameof(socket)); + _cert = cert ?? throw new ArgumentNullException(nameof(cert)); + + if (_socket.Connected) + { + NetworkStream ns = new NetworkStream(_socket, true); + _sslStream = new SslStream(ns); + } + } + + public async Task Authenticate() + { + await _sslStream.AuthenticateAsServerAsync(_cert, false, SslProtocols.Tls12, false); + } + + /// + /// Asynchronously connects to the client described in the . + /// + /// The describing the connection. + public async Task ConnectAsync(MqttClientOptions options) + { + try + { + await _socket.ConnectAsync(options.Server, options.Port); + } + catch (SocketException exception) + { + throw new MqttCommunicationException(exception); + } + } + + /// + /// Asynchronously disconnects the client from the server. + /// + public Task DisconnectAsync() + { + try + { + _socket.Dispose(); + return Task.FromResult(0); + } + catch (SocketException exception) + { + throw new MqttCommunicationException(exception); + } + } + + /// + /// Asynchronously writes a sequence of bytes to the socket. + /// + /// The buffer to write data from. + public async Task WriteAsync(byte[] buffer) + { + if (buffer == null) + throw new ArgumentNullException(nameof(buffer)); + + try + { + await _sslStream.WriteAsync(buffer, 0, buffer.Length); + } + catch (Exception ex) + when (ex is SocketException || ex is IOException) + { + throw new MqttCommunicationException(ex); + } + } + + /// + /// Asynchronously reads a sequence of bytes from the socket. + /// + /// The buffer to write the data into. + public async Task ReadAsync(byte[] buffer) + { + try + { + await _sslStream.ReadAsync(buffer, 0, buffer.Length); + } + catch (Exception ex) + when (ex is SocketException || ex is IOException) + { + throw new MqttCommunicationException(ex); + } + } + + /// + /// Releases all resources used by the . + /// + public void Dispose() + { + _sslStream?.Dispose(); + _socket?.Dispose(); + } + } +} \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetCoreApp/MqttSslServerAdapter.cs b/Frameworks/MQTTnet.NetCoreApp/MqttSslServerAdapter.cs new file mode 100644 index 0000000..58b0a3b --- /dev/null +++ b/Frameworks/MQTTnet.NetCoreApp/MqttSslServerAdapter.cs @@ -0,0 +1,64 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using MQTTnet.Core.Adapter; +using MQTTnet.Core.Serializer; +using MQTTnet.Core.Server; + +namespace MQTTnet +{ + public class MqttSslServerAdapter : IMqttServerAdapter, IDisposable + { + private CancellationTokenSource _cancellationTokenSource; + private Socket _socket; + private X509Certificate2 _x590Certificate2; + + public event EventHandler ClientConnected; + + public void Start(MqttServerOptions options) + { + if (_socket != null) throw new InvalidOperationException("Server is already started."); + + _cancellationTokenSource = new CancellationTokenSource(); + + _socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + _socket.Bind(new IPEndPoint(IPAddress.Any, options.Port)); + _socket.Listen(options.ConnectionBacklog); + + Task.Run(async () => await AcceptConnectionsAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token); + + _x590Certificate2 = new X509Certificate2(options.CertificatePath); + } + + public void Stop() + { + _cancellationTokenSource?.Dispose(); + _cancellationTokenSource = null; + + _socket?.Dispose(); + _socket = null; + } + + public void Dispose() + { + Stop(); + } + + private async Task AcceptConnectionsAsync(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + var clientSocket = await _socket.AcceptAsync(); + + MqttServerSslChannel mssc = new MqttServerSslChannel(clientSocket, _x590Certificate2); + await mssc.Authenticate(); + + var clientAdapter = new MqttChannelCommunicationAdapter(mssc, new DefaultMqttV311PacketSerializer()); + ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(clientSocket.RemoteEndPoint.ToString(), clientAdapter)); + } + } + } +} \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetFramework/MQTTnet.NetFramework.csproj b/Frameworks/MQTTnet.NetFramework/MQTTnet.NetFramework.csproj index 0c63762..314c158 100644 --- a/Frameworks/MQTTnet.NetFramework/MQTTnet.NetFramework.csproj +++ b/Frameworks/MQTTnet.NetFramework/MQTTnet.NetFramework.csproj @@ -103,6 +103,9 @@ + + + diff --git a/Frameworks/MQTTnet.NetFramework/MqttClientFactory.cs b/Frameworks/MQTTnet.NetFramework/MqttClientFactory.cs index 4da24a1..048112f 100644 --- a/Frameworks/MQTTnet.NetFramework/MqttClientFactory.cs +++ b/Frameworks/MQTTnet.NetFramework/MqttClientFactory.cs @@ -1,5 +1,6 @@ using System; using MQTTnet.Core.Adapter; +using MQTTnet.Core.Channel; using MQTTnet.Core.Client; using MQTTnet.Core.Serializer; @@ -10,8 +11,12 @@ namespace MQTTnet public MqttClient CreateMqttClient(MqttClientOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); - - return new MqttClient(options, new MqttChannelCommunicationAdapter(new MqttTcpChannel(), new DefaultMqttV311PacketSerializer())); + + return new MqttClient(options, + // The cast to IMqttCommunicationChannel is required... Roslyn is too stupid to + // figure out how to cast back to the base type + new MqttChannelCommunicationAdapter(options.UseSSL ? new MqttClientSslChannel() : (IMqttCommunicationChannel)new MqttTcpChannel(), + new DefaultMqttV311PacketSerializer())); } } } diff --git a/Frameworks/MQTTnet.NetFramework/MqttClientSslChannel.cs b/Frameworks/MQTTnet.NetFramework/MqttClientSslChannel.cs new file mode 100644 index 0000000..8adf14b --- /dev/null +++ b/Frameworks/MQTTnet.NetFramework/MqttClientSslChannel.cs @@ -0,0 +1,122 @@ +using System; +using System.IO; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Authentication; +using System.Threading.Tasks; +using MQTTnet.Core.Channel; +using MQTTnet.Core.Client; +using MQTTnet.Core.Exceptions; + +namespace MQTTnet +{ + /// + /// Describes an SSL channel to an MQTT server. + /// + public class MqttClientSslChannel : IMqttCommunicationChannel, IDisposable + { + private readonly Socket _socket; + private SslStream _sslStream; + + /// + /// Creates a new . + /// + public MqttClientSslChannel() + { + _socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + } + + /// + /// Creates a new with a predefined . + /// + /// + public MqttClientSslChannel(Socket socket) + { + _socket = socket ?? throw new ArgumentNullException(nameof(socket)); + } + + /// + /// Asynchronously connects to the host described in the . + /// + /// The describing the connection. + public async Task ConnectAsync(MqttClientOptions options) + { + try + { + await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, options.Server, options.Port, + null); + + NetworkStream ns = new NetworkStream(_socket, true); + _sslStream = new SslStream(ns); + + await _sslStream.AuthenticateAsClientAsync(options.Server, null, SslProtocols.Tls12, false); + + } + catch (SocketException exception) + { + throw new MqttCommunicationException(exception); + } + } + + /// + /// Asynchronously disconnects the client from the server. + /// + public async Task DisconnectAsync() + { + try + { + await Task.Factory.FromAsync(_socket.BeginDisconnect, _socket.EndDisconnect, true, null); + } + catch (SocketException exception) + { + throw new MqttCommunicationException(exception); + } + } + + /// + /// Asynchronously writes a sequence of bytes to the socket. + /// + /// The buffer to write data from. + public async Task WriteAsync(byte[] buffer) + { + if (buffer == null) + throw new ArgumentNullException(nameof(buffer)); + + try + { + await _sslStream.WriteAsync(buffer, 0, buffer.Length); + } + catch (Exception ex) + when (ex is SocketException || ex is IOException) + { + throw new MqttCommunicationException(ex); + } + } + + /// + /// Asynchronously reads a sequence of bytes from the socket. + /// + /// The buffer to write the data into. + public async Task ReadAsync(byte[] buffer) + { + try + { + await _sslStream.ReadAsync(buffer, 0, buffer.Length); + } + catch (Exception ex) + when (ex is SocketException || ex is IOException) + { + throw new MqttCommunicationException(ex); + } + } + + /// + /// Releases all resources used by the . + /// + public void Dispose() + { + _sslStream?.Dispose(); + _socket?.Dispose(); + } + } +} \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetFramework/MqttServerFactory.cs b/Frameworks/MQTTnet.NetFramework/MqttServerFactory.cs index a725426..a26fbdb 100644 --- a/Frameworks/MQTTnet.NetFramework/MqttServerFactory.cs +++ b/Frameworks/MQTTnet.NetFramework/MqttServerFactory.cs @@ -1,4 +1,5 @@ using System; +using MQTTnet.Core.Adapter; using MQTTnet.Core.Server; namespace MQTTnet @@ -8,8 +9,9 @@ namespace MQTTnet public MqttServer CreateMqttServer(MqttServerOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); - - return new MqttServer(options, new MqttServerAdapter()); + + // The cast to IMqttServerAdapter is required... stupidly... + return new MqttServer(options, options.UseSSL ? (IMqttServerAdapter) new MqttSslServerAdapter() : new MqttServerAdapter()); } } } diff --git a/Frameworks/MQTTnet.NetFramework/MqttServerSslChannel.cs b/Frameworks/MQTTnet.NetFramework/MqttServerSslChannel.cs new file mode 100644 index 0000000..2f01462 --- /dev/null +++ b/Frameworks/MQTTnet.NetFramework/MqttServerSslChannel.cs @@ -0,0 +1,123 @@ +using System; +using System.IO; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; +using MQTTnet.Core.Channel; +using MQTTnet.Core.Client; +using MQTTnet.Core.Exceptions; + +namespace MQTTnet +{ + /// + /// Describes an SSL channel to a client. + /// + public class MqttServerSslChannel : IMqttCommunicationChannel, IDisposable + { + private readonly Socket _socket; + private SslStream _sslStream; + private X509Certificate2 _cert; + + /// + /// Creates a new with a predefined . + /// + /// The client socket. + /// The X509 certificate used to authenticate as a server. + public MqttServerSslChannel(Socket socket, X509Certificate2 cert) + { + _socket = socket ?? throw new ArgumentNullException(nameof(socket)); + _cert = cert ?? throw new ArgumentNullException(nameof(cert)); + + if (_socket.Connected) + { + NetworkStream ns = new NetworkStream(_socket, true); + _sslStream = new SslStream(ns); + } + } + + public async Task Authenticate() + { + await _sslStream.AuthenticateAsServerAsync(_cert, false, SslProtocols.Tls12, false); + } + + /// + /// Asynchronously connects to the client described in the . + /// + /// The describing the connection. + public async Task ConnectAsync(MqttClientOptions options) + { + try + { + await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, options.Server, options.Port, + null); + } + catch (SocketException exception) + { + throw new MqttCommunicationException(exception); + } + } + + /// + /// Asynchronously disconnects the client from the server. + /// + public async Task DisconnectAsync() + { + try + { + await Task.Factory.FromAsync(_socket.BeginDisconnect, _socket.EndDisconnect, true, null); + } + catch (SocketException exception) + { + throw new MqttCommunicationException(exception); + } + } + + /// + /// Asynchronously writes a sequence of bytes to the socket. + /// + /// The buffer to write data from. + public async Task WriteAsync(byte[] buffer) + { + if (buffer == null) + throw new ArgumentNullException(nameof(buffer)); + + try + { + await _sslStream.WriteAsync(buffer, 0, buffer.Length); + } + catch (Exception ex) + when (ex is SocketException || ex is IOException) + { + throw new MqttCommunicationException(ex); + } + } + + /// + /// Asynchronously reads a sequence of bytes from the socket. + /// + /// The buffer to write the data into. + public async Task ReadAsync(byte[] buffer) + { + try + { + await _sslStream.ReadAsync(buffer, 0, buffer.Length); + } + catch (Exception ex) + when (ex is SocketException || ex is IOException) + { + throw new MqttCommunicationException(ex); + } + } + + /// + /// Releases all resources used by the . + /// + public void Dispose() + { + _sslStream?.Dispose(); + _socket?.Dispose(); + } + } +} \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetFramework/MqttSslServerAdapter.cs b/Frameworks/MQTTnet.NetFramework/MqttSslServerAdapter.cs new file mode 100644 index 0000000..f02c74b --- /dev/null +++ b/Frameworks/MQTTnet.NetFramework/MqttSslServerAdapter.cs @@ -0,0 +1,64 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using MQTTnet.Core.Adapter; +using MQTTnet.Core.Serializer; +using MQTTnet.Core.Server; + +namespace MQTTnet +{ + public class MqttSslServerAdapter : IMqttServerAdapter, IDisposable + { + private CancellationTokenSource _cancellationTokenSource; + private Socket _socket; + private X509Certificate2 _x590Certificate2; + + public event EventHandler ClientConnected; + + public void Start(MqttServerOptions options) + { + if (_socket != null) throw new InvalidOperationException("Server is already started."); + + _cancellationTokenSource = new CancellationTokenSource(); + + _socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + _socket.Bind(new IPEndPoint(IPAddress.Any, options.Port)); + _socket.Listen(options.ConnectionBacklog); + + Task.Run(async () => await AcceptConnectionsAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token); + + _x590Certificate2 = new X509Certificate2(options.CertificatePath); + } + + public void Stop() + { + _cancellationTokenSource?.Dispose(); + _cancellationTokenSource = null; + + _socket?.Dispose(); + _socket = null; + } + + public void Dispose() + { + Stop(); + } + + private async Task AcceptConnectionsAsync(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + var clientSocket = await Task.Factory.FromAsync(_socket.BeginAccept, _socket.EndAccept, null); + + MqttServerSslChannel mssc = new MqttServerSslChannel(clientSocket, _x590Certificate2); + await mssc.Authenticate(); + + var clientAdapter = new MqttChannelCommunicationAdapter(mssc, new DefaultMqttV311PacketSerializer()); + ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(clientSocket.RemoteEndPoint.ToString(), clientAdapter)); + } + } + } +} \ No newline at end of file diff --git a/MQTTnet.Core/Client/MqttClientOptions.cs b/MQTTnet.Core/Client/MqttClientOptions.cs index 830fef5..d306bfe 100644 --- a/MQTTnet.Core/Client/MqttClientOptions.cs +++ b/MQTTnet.Core/Client/MqttClientOptions.cs @@ -19,5 +19,24 @@ namespace MQTTnet.Core.Client public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(5); public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10); + + /// + /// Use SSL to communicate with the MQTT server. + /// + /// Setting this value to true will also set to 8883 if its value was 1883 (not set). + public bool UseSSL + { + get => _useSSL; + set + { + // Automatically set the port to the MQTT SSL port (8883) if it wasn't set already + if (value && Port == 1883) + Port = 8883; + + _useSSL = value; + } + } + + private bool _useSSL; } } diff --git a/MQTTnet.Core/Server/MqttServerOptions.cs b/MQTTnet.Core/Server/MqttServerOptions.cs index 0ce2309..0638700 100644 --- a/MQTTnet.Core/Server/MqttServerOptions.cs +++ b/MQTTnet.Core/Server/MqttServerOptions.cs @@ -13,5 +13,12 @@ namespace MQTTnet.Core.Server public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10); public Func ConnectionValidator { get; set; } + + public bool UseSSL = false; + + /// + /// The path to the X509 SSL certificate. + /// + public string CertificatePath = string.Empty; } } From 5c1eceb8a9d58c5ae01c1b3faae474c477b73a0c Mon Sep 17 00:00:00 2001 From: Zazzmatazz Date: Fri, 2 Jun 2017 16:20:48 -0400 Subject: [PATCH 2/3] Updated task methods. Instead of awaiting most tasks, changed to simply returning the tasks. --- .../MqttClientSslChannel.cs | 8 +++--- .../MqttServerSslChannel.cs | 26 +++++++++---------- .../MQTTnet.NetCoreApp/MqttTcpChannel.cs | 16 ++++++------ .../MQTTnet.NetFramework/MqttClientFactory.cs | 2 -- .../MqttClientSslChannel.cs | 13 +++++----- .../MqttServerSslChannel.cs | 26 +++++++++---------- .../MQTTnet.NetFramework/MqttTcpChannel.cs | 16 ++++++------ 7 files changed, 52 insertions(+), 55 deletions(-) diff --git a/Frameworks/MQTTnet.NetCoreApp/MqttClientSslChannel.cs b/Frameworks/MQTTnet.NetCoreApp/MqttClientSslChannel.cs index 26b12fb..7f3feb6 100644 --- a/Frameworks/MQTTnet.NetCoreApp/MqttClientSslChannel.cs +++ b/Frameworks/MQTTnet.NetCoreApp/MqttClientSslChannel.cs @@ -77,14 +77,14 @@ namespace MQTTnet /// Asynchronously writes a sequence of bytes to the socket. /// /// The buffer to write data from. - public async Task WriteAsync(byte[] buffer) + public Task WriteAsync(byte[] buffer) { if (buffer == null) throw new ArgumentNullException(nameof(buffer)); try { - await _sslStream.WriteAsync(buffer, 0, buffer.Length); + return _sslStream.WriteAsync(buffer, 0, buffer.Length); } catch (Exception ex) when (ex is SocketException || ex is IOException) @@ -97,11 +97,11 @@ namespace MQTTnet /// Asynchronously reads a sequence of bytes from the socket. /// /// The buffer to write the data into. - public async Task ReadAsync(byte[] buffer) + public Task ReadAsync(byte[] buffer) { try { - await _sslStream.ReadAsync(buffer, 0, buffer.Length); + return _sslStream.ReadAsync(buffer, 0, buffer.Length); } catch (Exception ex) when (ex is SocketException || ex is IOException) diff --git a/Frameworks/MQTTnet.NetCoreApp/MqttServerSslChannel.cs b/Frameworks/MQTTnet.NetCoreApp/MqttServerSslChannel.cs index c4c5713..b55771c 100644 --- a/Frameworks/MQTTnet.NetCoreApp/MqttServerSslChannel.cs +++ b/Frameworks/MQTTnet.NetCoreApp/MqttServerSslChannel.cs @@ -30,27 +30,27 @@ namespace MQTTnet _socket = socket ?? throw new ArgumentNullException(nameof(socket)); _cert = cert ?? throw new ArgumentNullException(nameof(cert)); - if (_socket.Connected) - { - NetworkStream ns = new NetworkStream(_socket, true); - _sslStream = new SslStream(ns); - } + if (!_socket.Connected) + return; + + NetworkStream ns = new NetworkStream(_socket, true); + _sslStream = new SslStream(ns); } - public async Task Authenticate() + public Task Authenticate() { - await _sslStream.AuthenticateAsServerAsync(_cert, false, SslProtocols.Tls12, false); + return _sslStream.AuthenticateAsServerAsync(_cert, false, SslProtocols.Tls12, false); } /// /// Asynchronously connects to the client described in the . /// /// The describing the connection. - public async Task ConnectAsync(MqttClientOptions options) + public Task ConnectAsync(MqttClientOptions options) { try { - await _socket.ConnectAsync(options.Server, options.Port); + return _socket.ConnectAsync(options.Server, options.Port); } catch (SocketException exception) { @@ -78,14 +78,14 @@ namespace MQTTnet /// Asynchronously writes a sequence of bytes to the socket. /// /// The buffer to write data from. - public async Task WriteAsync(byte[] buffer) + public Task WriteAsync(byte[] buffer) { if (buffer == null) throw new ArgumentNullException(nameof(buffer)); try { - await _sslStream.WriteAsync(buffer, 0, buffer.Length); + return _sslStream.WriteAsync(buffer, 0, buffer.Length); } catch (Exception ex) when (ex is SocketException || ex is IOException) @@ -98,11 +98,11 @@ namespace MQTTnet /// Asynchronously reads a sequence of bytes from the socket. /// /// The buffer to write the data into. - public async Task ReadAsync(byte[] buffer) + public Task ReadAsync(byte[] buffer) { try { - await _sslStream.ReadAsync(buffer, 0, buffer.Length); + return _sslStream.ReadAsync(buffer, 0, buffer.Length); } catch (Exception ex) when (ex is SocketException || ex is IOException) diff --git a/Frameworks/MQTTnet.NetCoreApp/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetCoreApp/MqttTcpChannel.cs index 139037c..e32c27f 100644 --- a/Frameworks/MQTTnet.NetCoreApp/MqttTcpChannel.cs +++ b/Frameworks/MQTTnet.NetCoreApp/MqttTcpChannel.cs @@ -21,11 +21,11 @@ namespace MQTTnet _socket = socket ?? throw new ArgumentNullException(nameof(socket)); } - public async Task ConnectAsync(MqttClientOptions options) + public Task ConnectAsync(MqttClientOptions options) { try { - await _socket.ConnectAsync(options.Server, options.Port); + return _socket.ConnectAsync(options.Server, options.Port); } catch (SocketException exception) { @@ -33,12 +33,12 @@ namespace MQTTnet } } - public async Task DisconnectAsync() + public Task DisconnectAsync() { try { _socket.Dispose(); - await Task.FromResult(0); + return Task.FromResult(0); } catch (SocketException exception) { @@ -46,13 +46,13 @@ namespace MQTTnet } } - public async Task WriteAsync(byte[] buffer) + public Task WriteAsync(byte[] buffer) { if (buffer == null) throw new ArgumentNullException(nameof(buffer)); try { - await _socket.SendAsync(new ArraySegment(buffer), SocketFlags.None); + return _socket.SendAsync(new ArraySegment(buffer), SocketFlags.None); } catch (SocketException exception) { @@ -60,12 +60,12 @@ namespace MQTTnet } } - public async Task ReadAsync(byte[] buffer) + public Task ReadAsync(byte[] buffer) { try { var buffer2 = new ArraySegment(buffer); - await _socket.ReceiveAsync(buffer2, SocketFlags.None); + return _socket.ReceiveAsync(buffer2, SocketFlags.None); } catch (SocketException exception) { diff --git a/Frameworks/MQTTnet.NetFramework/MqttClientFactory.cs b/Frameworks/MQTTnet.NetFramework/MqttClientFactory.cs index 048112f..54e06c4 100644 --- a/Frameworks/MQTTnet.NetFramework/MqttClientFactory.cs +++ b/Frameworks/MQTTnet.NetFramework/MqttClientFactory.cs @@ -13,8 +13,6 @@ namespace MQTTnet if (options == null) throw new ArgumentNullException(nameof(options)); return new MqttClient(options, - // The cast to IMqttCommunicationChannel is required... Roslyn is too stupid to - // figure out how to cast back to the base type new MqttChannelCommunicationAdapter(options.UseSSL ? new MqttClientSslChannel() : (IMqttCommunicationChannel)new MqttTcpChannel(), new DefaultMqttV311PacketSerializer())); } diff --git a/Frameworks/MQTTnet.NetFramework/MqttClientSslChannel.cs b/Frameworks/MQTTnet.NetFramework/MqttClientSslChannel.cs index 8adf14b..7fe9ca3 100644 --- a/Frameworks/MQTTnet.NetFramework/MqttClientSslChannel.cs +++ b/Frameworks/MQTTnet.NetFramework/MqttClientSslChannel.cs @@ -50,7 +50,6 @@ namespace MQTTnet _sslStream = new SslStream(ns); await _sslStream.AuthenticateAsClientAsync(options.Server, null, SslProtocols.Tls12, false); - } catch (SocketException exception) { @@ -61,11 +60,11 @@ namespace MQTTnet /// /// Asynchronously disconnects the client from the server. /// - public async Task DisconnectAsync() + public Task DisconnectAsync() { try { - await Task.Factory.FromAsync(_socket.BeginDisconnect, _socket.EndDisconnect, true, null); + return Task.Factory.FromAsync(_socket.BeginDisconnect, _socket.EndDisconnect, true, null); } catch (SocketException exception) { @@ -77,14 +76,14 @@ namespace MQTTnet /// Asynchronously writes a sequence of bytes to the socket. /// /// The buffer to write data from. - public async Task WriteAsync(byte[] buffer) + public Task WriteAsync(byte[] buffer) { if (buffer == null) throw new ArgumentNullException(nameof(buffer)); try { - await _sslStream.WriteAsync(buffer, 0, buffer.Length); + return _sslStream.WriteAsync(buffer, 0, buffer.Length); } catch (Exception ex) when (ex is SocketException || ex is IOException) @@ -97,11 +96,11 @@ namespace MQTTnet /// Asynchronously reads a sequence of bytes from the socket. /// /// The buffer to write the data into. - public async Task ReadAsync(byte[] buffer) + public Task ReadAsync(byte[] buffer) { try { - await _sslStream.ReadAsync(buffer, 0, buffer.Length); + return _sslStream.ReadAsync(buffer, 0, buffer.Length); } catch (Exception ex) when (ex is SocketException || ex is IOException) diff --git a/Frameworks/MQTTnet.NetFramework/MqttServerSslChannel.cs b/Frameworks/MQTTnet.NetFramework/MqttServerSslChannel.cs index 2f01462..699948d 100644 --- a/Frameworks/MQTTnet.NetFramework/MqttServerSslChannel.cs +++ b/Frameworks/MQTTnet.NetFramework/MqttServerSslChannel.cs @@ -30,11 +30,11 @@ namespace MQTTnet _socket = socket ?? throw new ArgumentNullException(nameof(socket)); _cert = cert ?? throw new ArgumentNullException(nameof(cert)); - if (_socket.Connected) - { - NetworkStream ns = new NetworkStream(_socket, true); - _sslStream = new SslStream(ns); - } + if (!_socket.Connected) + return; + + NetworkStream ns = new NetworkStream(_socket, true); + _sslStream = new SslStream(ns); } public async Task Authenticate() @@ -46,11 +46,11 @@ namespace MQTTnet /// Asynchronously connects to the client described in the . /// /// The describing the connection. - public async Task ConnectAsync(MqttClientOptions options) + public Task ConnectAsync(MqttClientOptions options) { try { - await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, options.Server, options.Port, + return Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, options.Server, options.Port, null); } catch (SocketException exception) @@ -62,11 +62,11 @@ namespace MQTTnet /// /// Asynchronously disconnects the client from the server. /// - public async Task DisconnectAsync() + public Task DisconnectAsync() { try { - await Task.Factory.FromAsync(_socket.BeginDisconnect, _socket.EndDisconnect, true, null); + return Task.Factory.FromAsync(_socket.BeginDisconnect, _socket.EndDisconnect, true, null); } catch (SocketException exception) { @@ -78,14 +78,14 @@ namespace MQTTnet /// Asynchronously writes a sequence of bytes to the socket. /// /// The buffer to write data from. - public async Task WriteAsync(byte[] buffer) + public Task WriteAsync(byte[] buffer) { if (buffer == null) throw new ArgumentNullException(nameof(buffer)); try { - await _sslStream.WriteAsync(buffer, 0, buffer.Length); + return _sslStream.WriteAsync(buffer, 0, buffer.Length); } catch (Exception ex) when (ex is SocketException || ex is IOException) @@ -98,11 +98,11 @@ namespace MQTTnet /// Asynchronously reads a sequence of bytes from the socket. /// /// The buffer to write the data into. - public async Task ReadAsync(byte[] buffer) + public Task ReadAsync(byte[] buffer) { try { - await _sslStream.ReadAsync(buffer, 0, buffer.Length); + return _sslStream.ReadAsync(buffer, 0, buffer.Length); } catch (Exception ex) when (ex is SocketException || ex is IOException) diff --git a/Frameworks/MQTTnet.NetFramework/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetFramework/MqttTcpChannel.cs index c690bcb..80c76cf 100644 --- a/Frameworks/MQTTnet.NetFramework/MqttTcpChannel.cs +++ b/Frameworks/MQTTnet.NetFramework/MqttTcpChannel.cs @@ -21,11 +21,11 @@ namespace MQTTnet _socket = socket ?? throw new ArgumentNullException(nameof(socket)); } - public async Task ConnectAsync(MqttClientOptions options) + public Task ConnectAsync(MqttClientOptions options) { try { - await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, options.Server, options.Port, null); + return Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, options.Server, options.Port, null); } catch (SocketException exception) { @@ -33,11 +33,11 @@ namespace MQTTnet } } - public async Task DisconnectAsync() + public Task DisconnectAsync() { try { - await Task.Factory.FromAsync(_socket.BeginDisconnect, _socket.EndDisconnect, true, null); + return Task.Factory.FromAsync(_socket.BeginDisconnect, _socket.EndDisconnect, true, null); } catch (SocketException exception) { @@ -45,13 +45,13 @@ namespace MQTTnet } } - public async Task WriteAsync(byte[] buffer) + public Task WriteAsync(byte[] buffer) { if (buffer == null) throw new ArgumentNullException(nameof(buffer)); try { - await Task.Factory.FromAsync( + return Task.Factory.FromAsync( // ReSharper disable once AssignNullToNotNullAttribute _socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, null, null), _socket.EndSend); @@ -62,11 +62,11 @@ namespace MQTTnet } } - public async Task ReadAsync(byte[] buffer) + public Task ReadAsync(byte[] buffer) { try { - await Task.Factory.FromAsync( + return Task.Factory.FromAsync( // ReSharper disable once AssignNullToNotNullAttribute _socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, null, null), _socket.EndReceive); From 8a65850f1a295ea90939165e209e5f1ecc5658e2 Mon Sep 17 00:00:00 2001 From: Zazzmatazz Date: Fri, 2 Jun 2017 16:22:37 -0400 Subject: [PATCH 3/3] Removed some %^&#ing $@#! comments. Gosh darnit. --- Frameworks/MQTTnet.NetCoreApp/MqttClientFactory.cs | 2 -- Frameworks/MQTTnet.NetCoreApp/MqttServerFactory.cs | 3 +-- Frameworks/MQTTnet.NetFramework/MqttServerFactory.cs | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Frameworks/MQTTnet.NetCoreApp/MqttClientFactory.cs b/Frameworks/MQTTnet.NetCoreApp/MqttClientFactory.cs index 62b6569..10ff3fa 100644 --- a/Frameworks/MQTTnet.NetCoreApp/MqttClientFactory.cs +++ b/Frameworks/MQTTnet.NetCoreApp/MqttClientFactory.cs @@ -13,8 +13,6 @@ namespace MQTTnet if (options == null) throw new ArgumentNullException(nameof(options)); return new MqttClient(options, - // The cast to IMqttCommunicationChannel is required... Roslyn is too stupid to - // figure out how to cast back to the base type new MqttChannelCommunicationAdapter(options.UseSSL ? new MqttClientSslChannel() : (IMqttCommunicationChannel) new MqttTcpChannel(), new DefaultMqttV311PacketSerializer())); } diff --git a/Frameworks/MQTTnet.NetCoreApp/MqttServerFactory.cs b/Frameworks/MQTTnet.NetCoreApp/MqttServerFactory.cs index 5098ea2..bc5ef2f 100644 --- a/Frameworks/MQTTnet.NetCoreApp/MqttServerFactory.cs +++ b/Frameworks/MQTTnet.NetCoreApp/MqttServerFactory.cs @@ -9,8 +9,7 @@ namespace MQTTnet public MqttServer CreateMqttServer(MqttServerOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); - - // The cast to IMqttServerAdapter is required... stupidly... + return new MqttServer(options, options.UseSSL ? (IMqttServerAdapter)new MqttSslServerAdapter() : new MqttServerAdapter()); } } diff --git a/Frameworks/MQTTnet.NetFramework/MqttServerFactory.cs b/Frameworks/MQTTnet.NetFramework/MqttServerFactory.cs index a26fbdb..71e57af 100644 --- a/Frameworks/MQTTnet.NetFramework/MqttServerFactory.cs +++ b/Frameworks/MQTTnet.NetFramework/MqttServerFactory.cs @@ -10,7 +10,6 @@ namespace MQTTnet { if (options == null) throw new ArgumentNullException(nameof(options)); - // The cast to IMqttServerAdapter is required... stupidly... return new MqttServer(options, options.UseSSL ? (IMqttServerAdapter) new MqttSslServerAdapter() : new MqttServerAdapter()); } }