From 31419fef0392d3938d8157ea267a4ebf4f0a44f5 Mon Sep 17 00:00:00 2001 From: 1iveowl Date: Fri, 14 Jul 2017 08:22:02 +0200 Subject: [PATCH 1/5] Update .gitignore --- .gitignore | 84 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index de42c58d..940794e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.suo @@ -15,12 +17,12 @@ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ -[Xx]64/ -[Xx]86/ -[Bb]uild/ +x64/ +x86/ bld/ [Bb]in/ [Oo]bj/ +[Ll]og/ # Visual Studio 2015 cache/options directory .vs/ @@ -40,9 +42,11 @@ TestResult.xml [Rr]eleasePS/ dlldata.c -# DNX +# .NET Core project.lock.json +project.fragment.lock.json artifacts/ +**/Properties/launchSettings.json *_i.c *_p.c @@ -81,6 +85,7 @@ ipch/ *.sdf *.cachefile *.VC.db +*.VC.VC.opendb # Visual Studio profiler *.psess @@ -108,6 +113,10 @@ _TeamCity* # DotCover is a Code Coverage Tool *.dotCover +# Visual Studio code coverage results +*.coverage +*.coveragexml + # NCrunch _NCrunch_* .*crunch*.local.xml @@ -139,13 +148,16 @@ publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml - -# TODO: Un-comment the next line if you do not want to checkin -# your web deploy settings because they may include unencrypted -# passwords -#*.pubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml *.publishproj +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore @@ -154,7 +166,7 @@ publish/ !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files +# NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets @@ -166,12 +178,11 @@ csx/ ecf/ rcf/ -# Microsoft Azure ApplicationInsights config file -ApplicationInsights.config - -# Windows Store app package directory +# Windows Store app package directories and files AppPackages/ BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt # Visual Studio cache files # files ending in .cache can be ignored @@ -181,16 +192,19 @@ BundleArtifacts/ # Others ClientBin/ -[Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview +*.jfm *.pfx *.publishsettings -node_modules/ orleans.codegen.cs +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + # RIA/Silverlight projects Generated_Code/ @@ -205,6 +219,7 @@ UpgradeLog*.htm # SQL Server files *.mdf *.ldf +*.ndf # Business Intelligence projects *.rdl.data @@ -219,6 +234,10 @@ FakesAssemblies/ # Node.js Tools for Visual Studio .ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ # Visual Studio 6 build log *.plg @@ -226,6 +245,9 @@ FakesAssemblies/ # Visual Studio 6 workspace options file *.opt +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts @@ -234,13 +256,33 @@ FakesAssemblies/ **/*.Server/ModelManifest.xml _Pvt_Extensions -# LightSwitch generated files -GeneratedArtifacts/ -ModelManifest.xml - # Paket dependency manager .paket/paket.exe +paket-files/ # FAKE - F# Make .fake/ -nuget.exe \ No newline at end of file + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs From b3e11d47b794fa476d0ab39cfc5a095ee0aa43c6 Mon Sep 17 00:00:00 2001 From: 1iveowl Date: Fri, 14 Jul 2017 08:22:11 +0200 Subject: [PATCH 2/5] Build fix --- .gitignore | 84 ++++++++++++++++++++++++++++++++++++------------- Build/build.ps1 | 14 +++++++++ 2 files changed, 77 insertions(+), 21 deletions(-) create mode 100644 Build/build.ps1 diff --git a/.gitignore b/.gitignore index de42c58d..940794e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.suo @@ -15,12 +17,12 @@ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ -[Xx]64/ -[Xx]86/ -[Bb]uild/ +x64/ +x86/ bld/ [Bb]in/ [Oo]bj/ +[Ll]og/ # Visual Studio 2015 cache/options directory .vs/ @@ -40,9 +42,11 @@ TestResult.xml [Rr]eleasePS/ dlldata.c -# DNX +# .NET Core project.lock.json +project.fragment.lock.json artifacts/ +**/Properties/launchSettings.json *_i.c *_p.c @@ -81,6 +85,7 @@ ipch/ *.sdf *.cachefile *.VC.db +*.VC.VC.opendb # Visual Studio profiler *.psess @@ -108,6 +113,10 @@ _TeamCity* # DotCover is a Code Coverage Tool *.dotCover +# Visual Studio code coverage results +*.coverage +*.coveragexml + # NCrunch _NCrunch_* .*crunch*.local.xml @@ -139,13 +148,16 @@ publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml - -# TODO: Un-comment the next line if you do not want to checkin -# your web deploy settings because they may include unencrypted -# passwords -#*.pubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml *.publishproj +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore @@ -154,7 +166,7 @@ publish/ !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files +# NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets @@ -166,12 +178,11 @@ csx/ ecf/ rcf/ -# Microsoft Azure ApplicationInsights config file -ApplicationInsights.config - -# Windows Store app package directory +# Windows Store app package directories and files AppPackages/ BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt # Visual Studio cache files # files ending in .cache can be ignored @@ -181,16 +192,19 @@ BundleArtifacts/ # Others ClientBin/ -[Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview +*.jfm *.pfx *.publishsettings -node_modules/ orleans.codegen.cs +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + # RIA/Silverlight projects Generated_Code/ @@ -205,6 +219,7 @@ UpgradeLog*.htm # SQL Server files *.mdf *.ldf +*.ndf # Business Intelligence projects *.rdl.data @@ -219,6 +234,10 @@ FakesAssemblies/ # Node.js Tools for Visual Studio .ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ # Visual Studio 6 build log *.plg @@ -226,6 +245,9 @@ FakesAssemblies/ # Visual Studio 6 workspace options file *.opt +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts @@ -234,13 +256,33 @@ FakesAssemblies/ **/*.Server/ModelManifest.xml _Pvt_Extensions -# LightSwitch generated files -GeneratedArtifacts/ -ModelManifest.xml - # Paket dependency manager .paket/paket.exe +paket-files/ # FAKE - F# Make .fake/ -nuget.exe \ No newline at end of file + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs diff --git a/Build/build.ps1 b/Build/build.ps1 new file mode 100644 index 00000000..322a2c87 --- /dev/null +++ b/Build/build.ps1 @@ -0,0 +1,14 @@ +param([string]$version) + +if ([string]::IsNullOrEmpty($version)) {$version = "0.0.1"} + +$msbuild = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\MSBuild.exe" +&$msbuild ..\Frameworks\MQTTnet.NetFramework\MQTTnet.NetFramework.csproj /t:Build /p:Configuration="Release" +&$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" +&$msbuild ..\Frameworks\MQTTnet.UniversalWindows\MQTTnet.UniversalWindows.csproj /t:Build /p:Configuration="Release" + + + +Remove-Item .\NuGet -Force -Recurse +New-Item -ItemType Directory -Force -Path .\NuGet +NuGet.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $version \ No newline at end of file From 9c5e5b5e10178df80ba68de13fa614cdf6af388f Mon Sep 17 00:00:00 2001 From: 1iveowl Date: Fri, 14 Jul 2017 08:22:41 +0200 Subject: [PATCH 3/5] build fix --- MQTTnet.sln | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MQTTnet.sln b/MQTTnet.sln index 17e73d06..f6a4ad03 100644 --- a/MQTTnet.sln +++ b/MQTTnet.sln @@ -17,8 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Core", "MQTTnet.Cor EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{002203AF-2565-4C0D-95ED-027FDEFE0C35}" ProjectSection(SolutionItems) = preProject - build.ps1 = build.ps1 - MQTTnet.nuspec = MQTTnet.nuspec + Build\build.ps1 = Build\build.ps1 + Build\MQTTnet.nuspec = Build\MQTTnet.nuspec EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.TestApp.NetFramework", "Tests\MQTTnet.TestApp.NetFramework\MQTTnet.TestApp.NetFramework.csproj", "{D9D74F33-6943-49B2-B765-7BD589082098}" From 1fb0944e2bc4eb68a6794e851926999a4ad195ea Mon Sep 17 00:00:00 2001 From: 1iveowl Date: Fri, 14 Jul 2017 08:26:03 +0200 Subject: [PATCH 4/5] Folder fix --- .../Implementations/MqttServerAdapter.cs | 117 ----------------- .../Implementations/MqttTcpChannel.cs | 122 ------------------ .../MQTTnet.NetStandard/MqttClientFactory.cs | 18 --- .../MQTTnet.NetStandard/MqttServerFactory.cs | 18 --- .../MQTTnet.Netstandard.csproj | 21 --- 5 files changed, 296 deletions(-) delete mode 100644 Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs delete mode 100644 Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs delete mode 100644 Frameworks/MQTTnet.NetStandard/MqttClientFactory.cs delete mode 100644 Frameworks/MQTTnet.NetStandard/MqttServerFactory.cs delete mode 100644 Frameworks/MQTTnet.Netstandard/MQTTnet.Netstandard.csproj diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs deleted file mode 100644 index 0203134a..00000000 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.Net; -using System.Net.Security; -using System.Net.Sockets; -using System.Security.Authentication; -using System.Security.Cryptography.X509Certificates; -using System.Threading; -using System.Threading.Tasks; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Serializer; -using MQTTnet.Core.Server; - -namespace MQTTnet.Implementations -{ - public class MqttServerAdapter : IMqttServerAdapter, IDisposable - { - private CancellationTokenSource _cancellationTokenSource; - private Socket _defaultEndpointSocket; - private Socket _tlsEndpointSocket; - private X509Certificate2 _tlsCertificate; - - private bool _isRunning; - - public event EventHandler ClientConnected; - - public void Start(MqttServerOptions options) - { - if (_isRunning) throw new InvalidOperationException("Server is already started."); - _isRunning = true; - - _cancellationTokenSource = new CancellationTokenSource(); - - if (options.DefaultEndpointOptions.IsEnabled) - { - _defaultEndpointSocket = new Socket(SocketType.Stream, ProtocolType.Tcp); - _defaultEndpointSocket.Bind(new IPEndPoint(IPAddress.Any, options.GetDefaultEndpointPort())); - _defaultEndpointSocket.Listen(options.ConnectionBacklog); - - Task.Run(() => AcceptDefaultEndpointConnectionsAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token); - } - - if (options.TlsEndpointOptions.IsEnabled) - { - if (options.TlsEndpointOptions.Certificate == null) - { - throw new ArgumentException("TLS certificate is not set."); - } - - _tlsCertificate = new X509Certificate2(options.TlsEndpointOptions.Certificate); - - _tlsEndpointSocket = new Socket(SocketType.Stream, ProtocolType.Tcp); - _tlsEndpointSocket.Bind(new IPEndPoint(IPAddress.Any, options.GetTlsEndpointPort())); - _tlsEndpointSocket.Listen(options.ConnectionBacklog); - - Task.Run(() => AcceptTlsEndpointConnectionsAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token); - } - } - - public void Stop() - { - _isRunning = false; - - _cancellationTokenSource?.Dispose(); - _cancellationTokenSource = null; - - _defaultEndpointSocket?.Dispose(); - _defaultEndpointSocket = null; - - _tlsEndpointSocket?.Dispose(); - _tlsEndpointSocket = null; - } - - public void Dispose() - { - Stop(); - } - - private async Task AcceptDefaultEndpointConnectionsAsync(CancellationToken cancellationToken) - { - while (!cancellationToken.IsCancellationRequested) - { - try - { - var clientSocket = await _defaultEndpointSocket.AcceptAsync(); - var clientAdapter = new MqttChannelCommunicationAdapter(new MqttTcpChannel(clientSocket, null), new DefaultMqttV311PacketSerializer()); - ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(clientSocket.RemoteEndPoint.ToString(), clientAdapter)); - } - catch (Exception exception) - { - MqttTrace.Error(nameof(MqttServerAdapter), exception, "Error while acceping connection at default endpoint."); - } - } - } - - private async Task AcceptTlsEndpointConnectionsAsync(CancellationToken cancellationToken) - { - while (!cancellationToken.IsCancellationRequested) - { - try - { - var clientSocket = await _defaultEndpointSocket.AcceptAsync(); - - var sslStream = new SslStream(new NetworkStream(clientSocket)); - await sslStream.AuthenticateAsServerAsync(_tlsCertificate, false, SslProtocols.Tls12, false); - - var clientAdapter = new MqttChannelCommunicationAdapter(new MqttTcpChannel(clientSocket, sslStream), new DefaultMqttV311PacketSerializer()); - ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(clientSocket.RemoteEndPoint.ToString(), clientAdapter)); - } - catch (Exception exception) - { - MqttTrace.Error(nameof(MqttServerAdapter), exception, "Error while acceping connection at TLS endpoint."); - } - } - } - } -} \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs deleted file mode 100644 index e78cd987..00000000 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -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.Implementations -{ - public sealed class MqttTcpChannel : IMqttCommunicationChannel, IDisposable - { - private readonly Socket _socket; - private SslStream _sslStream; - - public MqttTcpChannel() - { - _socket = new Socket(SocketType.Stream, ProtocolType.Tcp); - } - - public MqttTcpChannel(Socket socket, SslStream sslStream) - { - _socket = socket ?? throw new ArgumentNullException(nameof(socket)); - _sslStream = sslStream; - } - - public async Task ConnectAsync(MqttClientOptions options) - { - if (options == null) throw new ArgumentNullException(nameof(options)); - try - { - await _socket.ConnectAsync(options.Server, options.GetPort()); - - if (options.TlsOptions.UseTls) - { - _sslStream = new SslStream(new NetworkStream(_socket, true)); - await _sslStream.AuthenticateAsClientAsync(options.Server, LoadCertificates(options), SslProtocols.Tls12, options.TlsOptions.CheckCertificateRevocation); - } - } - catch (SocketException exception) - { - throw new MqttCommunicationException(exception); - } - } - - public Task DisconnectAsync() - { - try - { - _sslStream.Dispose(); - _socket.Dispose(); - return Task.FromResult(0); - } - catch (SocketException exception) - { - throw new MqttCommunicationException(exception); - } - } - - public Task WriteAsync(byte[] buffer) - { - if (buffer == null) throw new ArgumentNullException(nameof(buffer)); - - try - { - if (_sslStream != null) - { - return _sslStream.WriteAsync(buffer, 0, buffer.Length); - } - - return _socket.SendAsync(new ArraySegment(buffer), SocketFlags.None); - } - catch (SocketException exception) - { - throw new MqttCommunicationException(exception); - } - } - - public Task ReadAsync(byte[] buffer) - { - if (buffer == null) throw new ArgumentNullException(nameof(buffer)); - - try - { - if (_sslStream != null) - { - return _sslStream.ReadAsync(buffer, 0, buffer.Length); - } - - return _socket.ReceiveAsync(new ArraySegment(buffer), SocketFlags.None); - } - catch (SocketException exception) - { - throw new MqttCommunicationException(exception); - } - } - - public void Dispose() - { - _socket?.Dispose(); - _sslStream?.Dispose(); - } - - private static X509CertificateCollection LoadCertificates(MqttClientOptions options) - { - var certificates = new X509CertificateCollection(); - if (options.TlsOptions.Certificates == null) - { - return certificates; - } - - foreach (var certificate in options.TlsOptions.Certificates) - { - certificates.Add(new X509Certificate(certificate)); - } - - return certificates; - } - } -} \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/MqttClientFactory.cs b/Frameworks/MQTTnet.NetStandard/MqttClientFactory.cs deleted file mode 100644 index ac6f611a..00000000 --- a/Frameworks/MQTTnet.NetStandard/MqttClientFactory.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Client; -using MQTTnet.Core.Serializer; -using MQTTnet.Implementations; - -namespace MQTTnet -{ - public class MqttClientFactory - { - public MqttClient CreateMqttClient(MqttClientOptions options) - { - if (options == null) throw new ArgumentNullException(nameof(options)); - - return new MqttClient(options, new MqttChannelCommunicationAdapter(new MqttTcpChannel(), new DefaultMqttV311PacketSerializer())); - } - } -} diff --git a/Frameworks/MQTTnet.NetStandard/MqttServerFactory.cs b/Frameworks/MQTTnet.NetStandard/MqttServerFactory.cs deleted file mode 100644 index eb7441c3..00000000 --- a/Frameworks/MQTTnet.NetStandard/MqttServerFactory.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Server; -using MQTTnet.Implementations; - -namespace MQTTnet -{ - public class MqttServerFactory - { - public MqttServer CreateMqttServer(MqttServerOptions options) - { - if (options == null) throw new ArgumentNullException(nameof(options)); - - return new MqttServer(options, new List { new MqttServerAdapter() }); - } - } -} diff --git a/Frameworks/MQTTnet.Netstandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.Netstandard/MQTTnet.Netstandard.csproj deleted file mode 100644 index 10ffeed9..00000000 --- a/Frameworks/MQTTnet.Netstandard/MQTTnet.Netstandard.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - netstandard1.3 - MQTTnet - MQTTnet - - - - - - - - - - - - - - - \ No newline at end of file From 3722bc9ae6409c5c9158ea51f286a77631530876 Mon Sep 17 00:00:00 2001 From: 1iveowl Date: Fri, 14 Jul 2017 08:26:25 +0200 Subject: [PATCH 5/5] Folder fix --- .../Implementations/MqttServerAdapter.cs | 117 +++++++++++++++++ .../Implementations/MqttTcpChannel.cs | 122 ++++++++++++++++++ .../MQTTnet.Netstandard.csproj | 21 +++ .../MQTTnet.NetStandard/MqttClientFactory.cs | 18 +++ .../MQTTnet.NetStandard/MqttServerFactory.cs | 18 +++ 5 files changed, 296 insertions(+) create mode 100644 Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs create mode 100644 Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs create mode 100644 Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj create mode 100644 Frameworks/MQTTnet.NetStandard/MqttClientFactory.cs create mode 100644 Frameworks/MQTTnet.NetStandard/MqttServerFactory.cs diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs new file mode 100644 index 00000000..0203134a --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs @@ -0,0 +1,117 @@ +using System; +using System.Net; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using MQTTnet.Core.Adapter; +using MQTTnet.Core.Diagnostics; +using MQTTnet.Core.Serializer; +using MQTTnet.Core.Server; + +namespace MQTTnet.Implementations +{ + public class MqttServerAdapter : IMqttServerAdapter, IDisposable + { + private CancellationTokenSource _cancellationTokenSource; + private Socket _defaultEndpointSocket; + private Socket _tlsEndpointSocket; + private X509Certificate2 _tlsCertificate; + + private bool _isRunning; + + public event EventHandler ClientConnected; + + public void Start(MqttServerOptions options) + { + if (_isRunning) throw new InvalidOperationException("Server is already started."); + _isRunning = true; + + _cancellationTokenSource = new CancellationTokenSource(); + + if (options.DefaultEndpointOptions.IsEnabled) + { + _defaultEndpointSocket = new Socket(SocketType.Stream, ProtocolType.Tcp); + _defaultEndpointSocket.Bind(new IPEndPoint(IPAddress.Any, options.GetDefaultEndpointPort())); + _defaultEndpointSocket.Listen(options.ConnectionBacklog); + + Task.Run(() => AcceptDefaultEndpointConnectionsAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token); + } + + if (options.TlsEndpointOptions.IsEnabled) + { + if (options.TlsEndpointOptions.Certificate == null) + { + throw new ArgumentException("TLS certificate is not set."); + } + + _tlsCertificate = new X509Certificate2(options.TlsEndpointOptions.Certificate); + + _tlsEndpointSocket = new Socket(SocketType.Stream, ProtocolType.Tcp); + _tlsEndpointSocket.Bind(new IPEndPoint(IPAddress.Any, options.GetTlsEndpointPort())); + _tlsEndpointSocket.Listen(options.ConnectionBacklog); + + Task.Run(() => AcceptTlsEndpointConnectionsAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token); + } + } + + public void Stop() + { + _isRunning = false; + + _cancellationTokenSource?.Dispose(); + _cancellationTokenSource = null; + + _defaultEndpointSocket?.Dispose(); + _defaultEndpointSocket = null; + + _tlsEndpointSocket?.Dispose(); + _tlsEndpointSocket = null; + } + + public void Dispose() + { + Stop(); + } + + private async Task AcceptDefaultEndpointConnectionsAsync(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + try + { + var clientSocket = await _defaultEndpointSocket.AcceptAsync(); + var clientAdapter = new MqttChannelCommunicationAdapter(new MqttTcpChannel(clientSocket, null), new DefaultMqttV311PacketSerializer()); + ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(clientSocket.RemoteEndPoint.ToString(), clientAdapter)); + } + catch (Exception exception) + { + MqttTrace.Error(nameof(MqttServerAdapter), exception, "Error while acceping connection at default endpoint."); + } + } + } + + private async Task AcceptTlsEndpointConnectionsAsync(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + try + { + var clientSocket = await _defaultEndpointSocket.AcceptAsync(); + + var sslStream = new SslStream(new NetworkStream(clientSocket)); + await sslStream.AuthenticateAsServerAsync(_tlsCertificate, false, SslProtocols.Tls12, false); + + var clientAdapter = new MqttChannelCommunicationAdapter(new MqttTcpChannel(clientSocket, sslStream), new DefaultMqttV311PacketSerializer()); + ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(clientSocket.RemoteEndPoint.ToString(), clientAdapter)); + } + catch (Exception exception) + { + MqttTrace.Error(nameof(MqttServerAdapter), exception, "Error while acceping connection at TLS endpoint."); + } + } + } + } +} \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs new file mode 100644 index 00000000..e78cd987 --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs @@ -0,0 +1,122 @@ +using System; +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.Implementations +{ + public sealed class MqttTcpChannel : IMqttCommunicationChannel, IDisposable + { + private readonly Socket _socket; + private SslStream _sslStream; + + public MqttTcpChannel() + { + _socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + } + + public MqttTcpChannel(Socket socket, SslStream sslStream) + { + _socket = socket ?? throw new ArgumentNullException(nameof(socket)); + _sslStream = sslStream; + } + + public async Task ConnectAsync(MqttClientOptions options) + { + if (options == null) throw new ArgumentNullException(nameof(options)); + try + { + await _socket.ConnectAsync(options.Server, options.GetPort()); + + if (options.TlsOptions.UseTls) + { + _sslStream = new SslStream(new NetworkStream(_socket, true)); + await _sslStream.AuthenticateAsClientAsync(options.Server, LoadCertificates(options), SslProtocols.Tls12, options.TlsOptions.CheckCertificateRevocation); + } + } + catch (SocketException exception) + { + throw new MqttCommunicationException(exception); + } + } + + public Task DisconnectAsync() + { + try + { + _sslStream.Dispose(); + _socket.Dispose(); + return Task.FromResult(0); + } + catch (SocketException exception) + { + throw new MqttCommunicationException(exception); + } + } + + public Task WriteAsync(byte[] buffer) + { + if (buffer == null) throw new ArgumentNullException(nameof(buffer)); + + try + { + if (_sslStream != null) + { + return _sslStream.WriteAsync(buffer, 0, buffer.Length); + } + + return _socket.SendAsync(new ArraySegment(buffer), SocketFlags.None); + } + catch (SocketException exception) + { + throw new MqttCommunicationException(exception); + } + } + + public Task ReadAsync(byte[] buffer) + { + if (buffer == null) throw new ArgumentNullException(nameof(buffer)); + + try + { + if (_sslStream != null) + { + return _sslStream.ReadAsync(buffer, 0, buffer.Length); + } + + return _socket.ReceiveAsync(new ArraySegment(buffer), SocketFlags.None); + } + catch (SocketException exception) + { + throw new MqttCommunicationException(exception); + } + } + + public void Dispose() + { + _socket?.Dispose(); + _sslStream?.Dispose(); + } + + private static X509CertificateCollection LoadCertificates(MqttClientOptions options) + { + var certificates = new X509CertificateCollection(); + if (options.TlsOptions.Certificates == null) + { + return certificates; + } + + foreach (var certificate in options.TlsOptions.Certificates) + { + certificates.Add(new X509Certificate(certificate)); + } + + return certificates; + } + } +} \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj new file mode 100644 index 00000000..10ffeed9 --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -0,0 +1,21 @@ + + + + netstandard1.3 + MQTTnet + MQTTnet + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/MqttClientFactory.cs b/Frameworks/MQTTnet.NetStandard/MqttClientFactory.cs new file mode 100644 index 00000000..ac6f611a --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/MqttClientFactory.cs @@ -0,0 +1,18 @@ +using System; +using MQTTnet.Core.Adapter; +using MQTTnet.Core.Client; +using MQTTnet.Core.Serializer; +using MQTTnet.Implementations; + +namespace MQTTnet +{ + public class MqttClientFactory + { + public MqttClient CreateMqttClient(MqttClientOptions options) + { + if (options == null) throw new ArgumentNullException(nameof(options)); + + return new MqttClient(options, new MqttChannelCommunicationAdapter(new MqttTcpChannel(), new DefaultMqttV311PacketSerializer())); + } + } +} diff --git a/Frameworks/MQTTnet.NetStandard/MqttServerFactory.cs b/Frameworks/MQTTnet.NetStandard/MqttServerFactory.cs new file mode 100644 index 00000000..eb7441c3 --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/MqttServerFactory.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using MQTTnet.Core.Adapter; +using MQTTnet.Core.Server; +using MQTTnet.Implementations; + +namespace MQTTnet +{ + public class MqttServerFactory + { + public MqttServer CreateMqttServer(MqttServerOptions options) + { + if (options == null) throw new ArgumentNullException(nameof(options)); + + return new MqttServer(options, new List { new MqttServerAdapter() }); + } + } +}