From 4a7ff9e9ed1404230971700137065c58a2a871bb Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sun, 11 Aug 2019 21:45:41 +0200 Subject: [PATCH 01/17] Add TLS certificate password support for MQTTnet.Server. --- .../Configuration/CertificateSettingsModel.cs | 35 +++++++++++++++++++ .../Configuration/TcpEndpointModel.cs | 23 ++---------- .../MQTTnet.Server/Mqtt/MqttServerService.cs | 22 +++++++++--- Source/MQTTnet.Server/appsettings.json | 7 ++-- 4 files changed, 60 insertions(+), 27 deletions(-) create mode 100644 Source/MQTTnet.Server/Configuration/CertificateSettingsModel.cs diff --git a/Source/MQTTnet.Server/Configuration/CertificateSettingsModel.cs b/Source/MQTTnet.Server/Configuration/CertificateSettingsModel.cs new file mode 100644 index 0000000..89eb48b --- /dev/null +++ b/Source/MQTTnet.Server/Configuration/CertificateSettingsModel.cs @@ -0,0 +1,35 @@ +using System.IO; + +namespace MQTTnet.Server.Configuration +{ + public class CertificateSettingsModel + { + /// + /// Path to certificate. + /// + public string Path { get; set; } + + /// + /// Password of certificate. + /// + public string Password { get; set; } + + /// + /// Read certificate file. + /// + public byte[] ReadCertificate() + { + if (string.IsNullOrEmpty(Path) || string.IsNullOrWhiteSpace(Path)) + { + throw new FileNotFoundException("No path set"); + } + + if (!File.Exists(Path)) + { + throw new FileNotFoundException($"Could not find Certificate in path: {Path}"); + } + + return File.ReadAllBytes(Path); + } + } +} diff --git a/Source/MQTTnet.Server/Configuration/TcpEndpointModel.cs b/Source/MQTTnet.Server/Configuration/TcpEndpointModel.cs index 8221390..8693268 100644 --- a/Source/MQTTnet.Server/Configuration/TcpEndpointModel.cs +++ b/Source/MQTTnet.Server/Configuration/TcpEndpointModel.cs @@ -9,9 +9,9 @@ namespace MQTTnet.Server.Configuration public class TcpEndPointModel { /// - /// Path to Certificate + /// Certificate settings. /// - public string CertificatePath { get; set; } + public CertificateSettingsModel Certificate { get; set; } /// /// Enabled / Disable @@ -33,25 +33,6 @@ namespace MQTTnet.Server.Configuration /// public int Port { get; set; } = 1883; - /// - /// Read Certificate file - /// - /// - public byte[] ReadCertificate() - { - if (string.IsNullOrEmpty(CertificatePath) || string.IsNullOrWhiteSpace(CertificatePath)) - { - throw new FileNotFoundException("No path set"); - } - - if (!File.Exists(CertificatePath)) - { - throw new FileNotFoundException($"Could not find Certificate in path: {CertificatePath}"); - } - - return File.ReadAllBytes(CertificatePath); - } - /// /// Read IPv4 /// diff --git a/Source/MQTTnet.Server/Mqtt/MqttServerService.cs b/Source/MQTTnet.Server/Mqtt/MqttServerService.cs index efb0010..b8c463f 100644 --- a/Source/MQTTnet.Server/Mqtt/MqttServerService.cs +++ b/Source/MQTTnet.Server/Mqtt/MqttServerService.cs @@ -47,7 +47,7 @@ namespace MQTTnet.Server.Mqtt MqttSubscriptionInterceptor mqttSubscriptionInterceptor, MqttApplicationMessageInterceptor mqttApplicationMessageInterceptor, MqttServerStorage mqttServerStorage, - PythonScriptHostService pythonScriptHostService, + PythonScriptHostService pythonScriptHostService, ILogger logger) { _settings = mqttSettings ?? throw new ArgumentNullException(nameof(mqttSettings)); @@ -179,7 +179,7 @@ namespace MQTTnet.Server.Mqtt .WithApplicationMessageInterceptor(_mqttApplicationMessageInterceptor) .WithSubscriptionInterceptor(_mqttSubscriptionInterceptor) .WithStorage(_mqttServerStorage); - + // Configure unencrypted connections if (_settings.TcpEndPoint.Enabled) { @@ -210,9 +210,23 @@ namespace MQTTnet.Server.Mqtt { options .WithEncryptedEndpoint() - .WithEncryptionSslProtocol(SslProtocols.Tls12) - .WithEncryptionCertificate(_settings.EncryptedTcpEndPoint.ReadCertificate()); + .WithEncryptionSslProtocol(SslProtocols.Tls12); + + if (!string.IsNullOrEmpty(_settings.EncryptedTcpEndPoint?.Certificate?.Path)) + { + IMqttServerCertificateCredentials certificateCredentials = null; + if (!string.IsNullOrEmpty(_settings.EncryptedTcpEndPoint?.Certificate?.Password)) + { + certificateCredentials = new MqttServerCertificateCredentials + { + Password = _settings.EncryptedTcpEndPoint.Certificate.Password + }; + } + + options.WithEncryptionCertificate(_settings.EncryptedTcpEndPoint.Certificate.ReadCertificate(), certificateCredentials); + } + if (_settings.EncryptedTcpEndPoint.TryReadIPv4(out var address4)) { options.WithEncryptedEndpointBoundIPAddress(address4); diff --git a/Source/MQTTnet.Server/appsettings.json b/Source/MQTTnet.Server/appsettings.json index 8ea10d6..71eaf20 100644 --- a/Source/MQTTnet.Server/appsettings.json +++ b/Source/MQTTnet.Server/appsettings.json @@ -27,7 +27,10 @@ "IPv4": "*", "IPv6": "*", "Port": 8883, - "CertificatePath": "/absolute/path/to/pfx" + "Certificate": { + "Path": "/absolute/path/to/pfx", + "Password": "" + } }, "WebSocketEndPoint": { "Enabled": true, @@ -63,4 +66,4 @@ } }, "AllowedHosts": "*" -} +} \ No newline at end of file From 8ad1fb287144b0ff8fa34a5736afd48bfdae2835 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sun, 11 Aug 2019 21:46:13 +0200 Subject: [PATCH 02/17] Refactor server certificate classes (breaking change). --- Source/MQTTnet/Server/IMqttServerCertificateCredentials.cs | 4 ++++ Source/MQTTnet/Server/IMqttServerCredentials.cs | 6 ------ Source/MQTTnet/Server/MqttServerCertificateCredentials.cs | 7 +++++++ Source/MQTTnet/Server/MqttServerOptionsBuilder.cs | 2 +- Source/MQTTnet/Server/MqttServerTlsTcpEndpointOptions.cs | 2 +- 5 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 Source/MQTTnet/Server/IMqttServerCertificateCredentials.cs delete mode 100644 Source/MQTTnet/Server/IMqttServerCredentials.cs create mode 100644 Source/MQTTnet/Server/MqttServerCertificateCredentials.cs diff --git a/Source/MQTTnet/Server/IMqttServerCertificateCredentials.cs b/Source/MQTTnet/Server/IMqttServerCertificateCredentials.cs new file mode 100644 index 0000000..3f5fe0e --- /dev/null +++ b/Source/MQTTnet/Server/IMqttServerCertificateCredentials.cs @@ -0,0 +1,4 @@ +public interface IMqttServerCertificateCredentials +{ + string Password { get; } +} diff --git a/Source/MQTTnet/Server/IMqttServerCredentials.cs b/Source/MQTTnet/Server/IMqttServerCredentials.cs deleted file mode 100644 index 5e75be9..0000000 --- a/Source/MQTTnet/Server/IMqttServerCredentials.cs +++ /dev/null @@ -1,6 +0,0 @@ -using System; - -public interface IMqttServerCredentials -{ - String Password { get; } -} diff --git a/Source/MQTTnet/Server/MqttServerCertificateCredentials.cs b/Source/MQTTnet/Server/MqttServerCertificateCredentials.cs new file mode 100644 index 0000000..05b6c5f --- /dev/null +++ b/Source/MQTTnet/Server/MqttServerCertificateCredentials.cs @@ -0,0 +1,7 @@ +namespace MQTTnet.Server +{ + public class MqttServerCertificateCredentials : IMqttServerCertificateCredentials + { + public string Password { get; set; } + } +} diff --git a/Source/MQTTnet/Server/MqttServerOptionsBuilder.cs b/Source/MQTTnet/Server/MqttServerOptionsBuilder.cs index 5991e7d..c25af84 100644 --- a/Source/MQTTnet/Server/MqttServerOptionsBuilder.cs +++ b/Source/MQTTnet/Server/MqttServerOptionsBuilder.cs @@ -82,7 +82,7 @@ namespace MQTTnet.Server return this; } - public MqttServerOptionsBuilder WithEncryptionCertificate(byte[] value, IMqttServerCredentials credentials = null) + public MqttServerOptionsBuilder WithEncryptionCertificate(byte[] value, IMqttServerCertificateCredentials credentials = null) { _options.TlsEndpointOptions.Certificate = value; _options.TlsEndpointOptions.CertificateCredentials = credentials; diff --git a/Source/MQTTnet/Server/MqttServerTlsTcpEndpointOptions.cs b/Source/MQTTnet/Server/MqttServerTlsTcpEndpointOptions.cs index e92d987..9bf325b 100644 --- a/Source/MQTTnet/Server/MqttServerTlsTcpEndpointOptions.cs +++ b/Source/MQTTnet/Server/MqttServerTlsTcpEndpointOptions.cs @@ -12,7 +12,7 @@ namespace MQTTnet.Server public byte[] Certificate { get; set; } - public IMqttServerCredentials CertificateCredentials { get; set; } + public IMqttServerCertificateCredentials CertificateCredentials { get; set; } public bool ClientCertificateRequired { get; set; } From 6d0e2c20223a3d313276983ab389c7e560e4a7a1 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sun, 11 Aug 2019 22:07:57 +0200 Subject: [PATCH 03/17] Remove dedicated UWP builds and code. --- Build/MQTTnet.nuspec | 30 +- Build/build.ps1 | 8 - MQTTnet.noUWP.sln | 260 ------------------ .../MQTTnet.Extensions.ManagedClient.csproj | 16 +- .../MQTTnet.Extensions.Rpc.csproj | 16 +- .../MQTTnet.Extensions.WebSocket4Net.csproj | 16 +- .../TargetFrameworkInfoProvider.cs | 6 - Source/MQTTnet/Formatter/MqttPacketReader.cs | 53 ---- .../Implementations/MqttTcpChannel.Uwp.cs | 196 ------------- .../MQTTnet/Implementations/MqttTcpChannel.cs | 6 +- .../MqttTcpServerAdapter.Uwp.cs | 122 -------- .../Implementations/MqttTcpServerAdapter.cs | 6 +- .../Implementations/MqttTcpServerListener.cs | 10 +- .../Implementations/MqttWebSocketChannel.cs | 6 +- Source/MQTTnet/MQTTnet.csproj | 31 +-- .../Server/MqttServerOptionsBuilder.cs | 6 +- .../MqttServerTcpEndpointBaseOptions.cs | 4 - .../Server/MqttServerTlsTcpEndpointOptions.cs | 4 +- .../MainPage.xaml.cs | 13 +- 19 files changed, 26 insertions(+), 783 deletions(-) delete mode 100644 MQTTnet.noUWP.sln delete mode 100644 Source/MQTTnet/Implementations/MqttTcpChannel.Uwp.cs delete mode 100644 Source/MQTTnet/Implementations/MqttTcpServerAdapter.Uwp.cs diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 6aafdc6..eded1fd 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -11,16 +11,9 @@ false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol. -* [Core] Nuget packages with symbols are now also published to improve debugging. -* [Core] Improve task handling (thanks to @mwinterb) -* [ManagedClient] Fix a race condition in the message storage (thanks to @PaulFake). -* [Server] Added items dictionary to client session in order to share data across interceptors as along as the session exists. -* [Server] Exposed CONNECT packet properties in Application Message and Subscription interceptor. -* [Server] Fixed: Sending Large packets with AspnetCore based connection throws System.ArgumentException. -* [Server] Fixed wrong usage of socket option _NoDelay_. -* [Server] Added remote certificate validation callback (thanks to @rudacs). -* [Server] Add support for certificate passwords (thanks to @cslutgen). -* [MQTTnet.Server] Added REST API for publishing basic messages. +* [Core] Removed dedicated UWP builds. The lib is now supporting net452, netstandard1.3 and netstandard2.0 only (which covers mostly everything currently supported by MS). +* [Server] Refactoring of TLS certificate handling (BREAKING CHANGE!) +* [MQTTnet.Server] Added support for passwords when using TLS certificate (BREAKING CHANGE!) Copyright Christian Kratky 2016-2019 MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin @@ -37,31 +30,22 @@ - - - + + + + - - - - - - - - - - \ No newline at end of file diff --git a/Build/build.ps1 b/Build/build.ps1 index 33f2767..08107dc 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -14,34 +14,26 @@ Write-Host # Build the core library &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" -&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" -&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" # Build the ASP.NET Core 2.0 extension &$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" # Build the RPC extension &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" -&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" -&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" # Build the Managed Client extension &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" -&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" -&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" # Build the WebSocket4Net extension &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" -&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" -&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" # Create NuGet packages. diff --git a/MQTTnet.noUWP.sln b/MQTTnet.noUWP.sln deleted file mode 100644 index 3d842a5..0000000 --- a/MQTTnet.noUWP.sln +++ /dev/null @@ -1,260 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27004.2010 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{9248C2E1-B9D6-40BF-81EC-86004D7765B4}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{32A630A7-2598-41D7-B625-204CD906F5FB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet", "Source\MQTTnet\MQTTnet.csproj", "{3587E506-55A2-4EB3-99C7-DC01E42D25D2}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{67C28AC1-BC3A-420A-BE9C-FA2401431CF9}" - ProjectSection(SolutionItems) = preProject - Build\build.ps1 = Build\build.ps1 - Build\MQTTnet.AspNetCore.nuspec = Build\MQTTnet.AspNetCore.nuspec - Build\MQTTnet.Extensions.ManagedClient.nuspec = Build\MQTTnet.Extensions.ManagedClient.nuspec - Build\MQTTnet.Extensions.Rpc.nuspec = Build\MQTTnet.Extensions.Rpc.nuspec - Build\MQTTnet.nuspec = Build\MQTTnet.nuspec - Build\upload.ps1 = Build\upload.ps1 - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B3F60ECB-45BA-4C66-8903-8BB89CA67998}" - ProjectSection(SolutionItems) = preProject - .bettercodehub.yml = .bettercodehub.yml - appveyor.yml = appveyor.yml - LICENSE = LICENSE - README.md = README.md - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.TestApp.NetCore", "Tests\MQTTnet.TestApp.NetCore\MQTTnet.TestApp.NetCore.csproj", "{3D283AAD-AAA8-4339-8394-52F80B6304DB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.TestApp.AspNetCore2", "Tests\MQTTnet.TestApp.AspNetCore2\MQTTnet.TestApp.AspNetCore2.csproj", "{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.AspNetCore", "Source\MQTTnet.AspnetCore\MQTTnet.AspNetCore.csproj", "{F10C4060-F7EE-4A83-919F-FF723E72F94A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{12816BCC-AF9E-44A9-9AE5-C246AF2A0587}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.Rpc", "Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj", "{C444E9C8-95FA-430E-9126-274129DE16CD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Benchmarks", "Tests\MQTTnet.Benchmarks\MQTTnet.Benchmarks.csproj", "{998D04DD-7CB0-45F5-A393-E2495C16399E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.ManagedClient", "Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj", "{C400533A-8EBA-4F0B-BF4D-295C3708604B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.AspNetCore.Tests", "Tests\MQTTnet.AspNetCore.Tests\MQTTnet.AspNetCore.Tests.csproj", "{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Tests.csproj", "{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Server", "Source\MQTTnet.Server\MQTTnet.Server.csproj", "{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.WebSocket4Net", "Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj", "{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|ARM = Debug|ARM - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|ARM = Release|ARM - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|ARM.ActiveCfg = Debug|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|ARM.Build.0 = Debug|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|x64.ActiveCfg = Debug|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|x64.Build.0 = Debug|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|x86.ActiveCfg = Debug|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|x86.Build.0 = Debug|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|Any CPU.Build.0 = Release|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|ARM.ActiveCfg = Release|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|ARM.Build.0 = Release|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|x64.ActiveCfg = Release|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|x64.Build.0 = Release|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|x86.ActiveCfg = Release|Any CPU - {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|x86.Build.0 = Release|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|ARM.ActiveCfg = Debug|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|ARM.Build.0 = Debug|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|x64.ActiveCfg = Debug|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|x64.Build.0 = Debug|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|x86.ActiveCfg = Debug|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|x86.Build.0 = Debug|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|Any CPU.Build.0 = Release|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|ARM.ActiveCfg = Release|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|ARM.Build.0 = Release|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|x64.ActiveCfg = Release|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|x64.Build.0 = Release|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|x86.ActiveCfg = Release|Any CPU - {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|x86.Build.0 = Release|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|ARM.ActiveCfg = Debug|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|ARM.Build.0 = Debug|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|x64.ActiveCfg = Debug|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|x64.Build.0 = Debug|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|x86.ActiveCfg = Debug|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|x86.Build.0 = Debug|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|Any CPU.Build.0 = Release|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|ARM.ActiveCfg = Release|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|ARM.Build.0 = Release|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|x64.ActiveCfg = Release|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|x64.Build.0 = Release|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|x86.ActiveCfg = Release|Any CPU - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|x86.Build.0 = Release|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|ARM.ActiveCfg = Debug|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|ARM.Build.0 = Debug|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|x64.ActiveCfg = Debug|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|x64.Build.0 = Debug|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|x86.ActiveCfg = Debug|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|x86.Build.0 = Debug|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|Any CPU.Build.0 = Release|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|ARM.ActiveCfg = Release|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|ARM.Build.0 = Release|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|x64.ActiveCfg = Release|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|x64.Build.0 = Release|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|x86.ActiveCfg = Release|Any CPU - {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|x86.Build.0 = Release|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|ARM.ActiveCfg = Debug|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|ARM.Build.0 = Debug|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|x64.ActiveCfg = Debug|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|x64.Build.0 = Debug|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|x86.ActiveCfg = Debug|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|x86.Build.0 = Debug|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|Any CPU.Build.0 = Release|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|ARM.ActiveCfg = Release|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|ARM.Build.0 = Release|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|x64.ActiveCfg = Release|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|x64.Build.0 = Release|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|x86.ActiveCfg = Release|Any CPU - {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|x86.Build.0 = Release|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|ARM.ActiveCfg = Debug|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|ARM.Build.0 = Debug|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|x64.ActiveCfg = Debug|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|x64.Build.0 = Debug|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|x86.ActiveCfg = Debug|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|x86.Build.0 = Debug|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|Any CPU.Build.0 = Release|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|ARM.ActiveCfg = Release|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|ARM.Build.0 = Release|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|x64.ActiveCfg = Release|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|x64.Build.0 = Release|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|x86.ActiveCfg = Release|Any CPU - {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|x86.Build.0 = Release|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|ARM.ActiveCfg = Debug|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|ARM.Build.0 = Debug|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|x64.ActiveCfg = Debug|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|x64.Build.0 = Debug|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|x86.ActiveCfg = Debug|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|x86.Build.0 = Debug|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|Any CPU.Build.0 = Release|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|ARM.ActiveCfg = Release|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|ARM.Build.0 = Release|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|x64.ActiveCfg = Release|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|x64.Build.0 = Release|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|x86.ActiveCfg = Release|Any CPU - {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|x86.Build.0 = Release|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|ARM.ActiveCfg = Debug|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|ARM.Build.0 = Debug|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|x64.ActiveCfg = Debug|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|x64.Build.0 = Debug|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|x86.ActiveCfg = Debug|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|x86.Build.0 = Debug|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|Any CPU.Build.0 = Release|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|ARM.ActiveCfg = Release|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|ARM.Build.0 = Release|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x64.ActiveCfg = Release|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x64.Build.0 = Release|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x86.ActiveCfg = Release|Any CPU - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x86.Build.0 = Release|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|ARM.ActiveCfg = Debug|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|ARM.Build.0 = Debug|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|x64.ActiveCfg = Debug|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|x64.Build.0 = Debug|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|x86.ActiveCfg = Debug|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|x86.Build.0 = Debug|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|Any CPU.Build.0 = Release|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|ARM.ActiveCfg = Release|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|ARM.Build.0 = Release|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|x64.ActiveCfg = Release|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|x64.Build.0 = Release|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|x86.ActiveCfg = Release|Any CPU - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|x86.Build.0 = Release|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|ARM.ActiveCfg = Debug|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|ARM.Build.0 = Debug|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|x64.ActiveCfg = Debug|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|x64.Build.0 = Debug|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|x86.ActiveCfg = Debug|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|x86.Build.0 = Debug|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|Any CPU.Build.0 = Release|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|ARM.ActiveCfg = Release|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|ARM.Build.0 = Release|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|x64.ActiveCfg = Release|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|x64.Build.0 = Release|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|x86.ActiveCfg = Release|Any CPU - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|x86.Build.0 = Release|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|ARM.ActiveCfg = Debug|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|ARM.Build.0 = Debug|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|x64.ActiveCfg = Debug|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|x64.Build.0 = Debug|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|x86.ActiveCfg = Debug|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|x86.Build.0 = Debug|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|Any CPU.Build.0 = Release|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|ARM.ActiveCfg = Release|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|ARM.Build.0 = Release|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|x64.ActiveCfg = Release|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|x64.Build.0 = Release|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|x86.ActiveCfg = Release|Any CPU - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {3587E506-55A2-4EB3-99C7-DC01E42D25D2} = {32A630A7-2598-41D7-B625-204CD906F5FB} - {3D283AAD-AAA8-4339-8394-52F80B6304DB} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} - {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} - {F10C4060-F7EE-4A83-919F-FF723E72F94A} = {32A630A7-2598-41D7-B625-204CD906F5FB} - {C444E9C8-95FA-430E-9126-274129DE16CD} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587} - {998D04DD-7CB0-45F5-A393-E2495C16399E} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} - {C400533A-8EBA-4F0B-BF4D-295C3708604B} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587} - {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} - {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} - {DADEA836-5CC3-474C-A2D8-4D0F31118CD7} = {32A630A7-2598-41D7-B625-204CD906F5FB} - {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {07536672-5CBC-4BE3-ACE0-708A431A7894} - EndGlobalSection -EndGlobal diff --git a/Source/MQTTnet.Extensions.ManagedClient/MQTTnet.Extensions.ManagedClient.csproj b/Source/MQTTnet.Extensions.ManagedClient/MQTTnet.Extensions.ManagedClient.csproj index b59b7f4..80131c4 100644 --- a/Source/MQTTnet.Extensions.ManagedClient/MQTTnet.Extensions.ManagedClient.csproj +++ b/Source/MQTTnet.Extensions.ManagedClient/MQTTnet.Extensions.ManagedClient.csproj @@ -2,27 +2,13 @@ netstandard1.3;netstandard2.0 - $(TargetFrameworks);net452;net461 - $(TargetFrameworks);uap10.0 + $(TargetFrameworks);net452 - - false - UAP,Version=v10.0 - UAP - 10.0.17134.0 - 10.0.10240.0 - .NETCore - v5.0 - $(DefineConstants);WINDOWS_UWP - en - $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets - - diff --git a/Source/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj b/Source/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj index b59b7f4..80131c4 100644 --- a/Source/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj +++ b/Source/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj @@ -2,27 +2,13 @@ netstandard1.3;netstandard2.0 - $(TargetFrameworks);net452;net461 - $(TargetFrameworks);uap10.0 + $(TargetFrameworks);net452 - - false - UAP,Version=v10.0 - UAP - 10.0.17134.0 - 10.0.10240.0 - .NETCore - v5.0 - $(DefineConstants);WINDOWS_UWP - en - $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets - - diff --git a/Source/MQTTnet.Extensions.WebSocket4Net/MQTTnet.Extensions.WebSocket4Net.csproj b/Source/MQTTnet.Extensions.WebSocket4Net/MQTTnet.Extensions.WebSocket4Net.csproj index bdf26c6..639e048 100644 --- a/Source/MQTTnet.Extensions.WebSocket4Net/MQTTnet.Extensions.WebSocket4Net.csproj +++ b/Source/MQTTnet.Extensions.WebSocket4Net/MQTTnet.Extensions.WebSocket4Net.csproj @@ -2,27 +2,13 @@ netstandard1.3;netstandard2.0 - $(TargetFrameworks);net452;net461 - $(TargetFrameworks);uap10.0 + $(TargetFrameworks);net452 - - false - UAP,Version=v10.0 - UAP - 10.0.17134.0 - 10.0.10240.0 - .NETCore - v5.0 - $(DefineConstants);WINDOWS_UWP - en - $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets - - diff --git a/Source/MQTTnet/Diagnostics/TargetFrameworkInfoProvider.cs b/Source/MQTTnet/Diagnostics/TargetFrameworkInfoProvider.cs index efbf08b..fec0809 100644 --- a/Source/MQTTnet/Diagnostics/TargetFrameworkInfoProvider.cs +++ b/Source/MQTTnet/Diagnostics/TargetFrameworkInfoProvider.cs @@ -8,16 +8,10 @@ { #if NET452 return "net452"; -#elif NET461 - return "net461"; -#elif NET472 - return "net472"; #elif NETSTANDARD1_3 return "netstandard1.3"; #elif NETSTANDARD2_0 return "netstandard2.0"; -#elif WINDOWS_UWP - return "uap10.0"; #endif } } diff --git a/Source/MQTTnet/Formatter/MqttPacketReader.cs b/Source/MQTTnet/Formatter/MqttPacketReader.cs index 2589c5b..5cd4dcf 100644 --- a/Source/MQTTnet/Formatter/MqttPacketReader.cs +++ b/Source/MQTTnet/Formatter/MqttPacketReader.cs @@ -55,16 +55,7 @@ namespace MQTTnet.Formatter }; } -#if WINDOWS_UWP - // UWP will have a dead lock when calling this not async. var bodyLength = await ReadBodyLengthAsync(buffer[1], cancellationToken).ConfigureAwait(false); -#else - // Here the async/await pattern is not used because the overhead of context switches - // is too big for reading 1 byte in a row. We expect that the remaining data was sent - // directly after the initial bytes. If the client disconnects just in this moment we - // will get an exception anyway. - var bodyLength = ReadBodyLength(buffer[1], cancellationToken); -#endif if (!bodyLength.HasValue) { @@ -81,49 +72,6 @@ namespace MQTTnet.Formatter }; } -#if !WINDOWS_UWP - private int? ReadBodyLength(byte initialEncodedByte, CancellationToken cancellationToken) - { - var offset = 0; - var multiplier = 128; - var value = initialEncodedByte & 127; - int encodedByte = initialEncodedByte; - - while ((encodedByte & 128) != 0) - { - offset++; - if (offset > 3) - { - throw new MqttProtocolViolationException("Remaining length is invalid."); - } - - if (cancellationToken.IsCancellationRequested) - { - return null; - } - - var readCount = _channel.ReadAsync(_singleByteBuffer, 0, 1, cancellationToken).GetAwaiter().GetResult(); - - if (cancellationToken.IsCancellationRequested) - { - return null; - } - - if (readCount == 0) - { - return null; - } - - encodedByte = _singleByteBuffer[0]; - - value += (encodedByte & 127) * multiplier; - multiplier *= 128; - } - - return value; - } -#else - private async Task ReadBodyLengthAsync(byte initialEncodedByte, CancellationToken cancellationToken) { var offset = 0; @@ -164,6 +112,5 @@ namespace MQTTnet.Formatter return value; } -#endif } } diff --git a/Source/MQTTnet/Implementations/MqttTcpChannel.Uwp.cs b/Source/MQTTnet/Implementations/MqttTcpChannel.Uwp.cs deleted file mode 100644 index cb0f71c..0000000 --- a/Source/MQTTnet/Implementations/MqttTcpChannel.Uwp.cs +++ /dev/null @@ -1,196 +0,0 @@ -#if WINDOWS_UWP -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; -using System.Security.Authentication; -using System.Security.Cryptography.X509Certificates; -using System.Threading; -using System.Threading.Tasks; -using Windows.Networking; -using Windows.Networking.Sockets; -using Windows.Security.Cryptography.Certificates; -using MQTTnet.Channel; -using MQTTnet.Client.Options; -using MQTTnet.Server; - -namespace MQTTnet.Implementations -{ - public class MqttTcpChannel : IMqttChannel - { - private readonly MqttClientTcpOptions _options; - private readonly int _bufferSize; - - private StreamSocket _socket; - private Stream _readStream; - private Stream _writeStream; - - public MqttTcpChannel(IMqttClientOptions clientOptions) - { - _options = (MqttClientTcpOptions)clientOptions.ChannelOptions; - _bufferSize = _options.BufferSize; - } - - public MqttTcpChannel(StreamSocket socket, X509Certificate2 clientCertificate, IMqttServerOptions serverOptions) - { - _socket = socket ?? throw new ArgumentNullException(nameof(socket)); - _bufferSize = serverOptions.DefaultEndpointOptions.BufferSize; - - CreateStreams(); - - IsSecureConnection = socket.Information.ProtectionLevel >= SocketProtectionLevel.Tls12; - ClientCertificate = clientCertificate; - - Endpoint = _socket.Information.RemoteAddress + ":" + _socket.Information.RemotePort; - } - - public static Func> CustomIgnorableServerCertificateErrorsResolver { get; set; } - - public string Endpoint { get; private set; } - - public bool IsSecureConnection { get; } - - public X509Certificate2 ClientCertificate { get; } - - public async Task ConnectAsync(CancellationToken cancellationToken) - { - if (_socket == null) - { - _socket = new StreamSocket(); - _socket.Control.NoDelay = _options.NoDelay; - _socket.Control.KeepAlive = true; - } - - if (_options.TlsOptions?.UseTls != true) - { - await _socket.ConnectAsync(new HostName(_options.Server), _options.GetPort().ToString()); - } - else - { - _socket.Control.ClientCertificate = LoadCertificate(_options); - - foreach (var ignorableChainValidationResult in ResolveIgnorableServerCertificateErrors()) - { - _socket.Control.IgnorableServerCertificateErrors.Add(ignorableChainValidationResult); - } - - var socketProtectionLevel = SocketProtectionLevel.Tls12; - if (_options.TlsOptions.SslProtocol == SslProtocols.Tls11) - { - socketProtectionLevel = SocketProtectionLevel.Tls11; - } - else if (_options.TlsOptions.SslProtocol == SslProtocols.Tls) - { - socketProtectionLevel = SocketProtectionLevel.Tls10; - } - - await _socket.ConnectAsync(new HostName(_options.Server), _options.GetPort().ToString(), socketProtectionLevel); - } - - Endpoint = _socket.Information.RemoteAddress + ":" + _socket.Information.RemotePort; - - CreateStreams(); - } - - public Task DisconnectAsync(CancellationToken cancellationToken) - { - Dispose(); - return Task.FromResult(0); - } - - public Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - return _readStream.ReadAsync(buffer, offset, count, cancellationToken); - } - - public Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - // In the write method only the internal buffer will be filled. So here is no - // async/await required. The real network transmit is done when calling the - // Flush method. - _writeStream.Write(buffer, offset, count); - return _writeStream.FlushAsync(cancellationToken); - } - - public void Dispose() - { - TryDispose(_readStream, () => _readStream = null); - TryDispose(_writeStream, () => _writeStream = null); - TryDispose(_socket, () => _socket = null); - } - - private static Certificate LoadCertificate(IMqttClientChannelOptions options) - { - if (options.TlsOptions.Certificates == null || !options.TlsOptions.Certificates.Any()) - { - return null; - } - - if (options.TlsOptions.Certificates.Count > 1) - { - throw new NotSupportedException("Only one client certificate is supported for UWP."); - } - - return new Certificate(options.TlsOptions.Certificates.First().AsBuffer()); - } - - private IEnumerable ResolveIgnorableServerCertificateErrors() - { - if (CustomIgnorableServerCertificateErrorsResolver != null) - { - return CustomIgnorableServerCertificateErrorsResolver(_options); - } - - var result = new List(); - - if (_options.TlsOptions.IgnoreCertificateRevocationErrors) - { - result.Add(ChainValidationResult.RevocationInformationMissing); - //_socket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Revoked); Not supported. - result.Add(ChainValidationResult.RevocationFailure); - } - - if (_options.TlsOptions.IgnoreCertificateChainErrors) - { - result.Add(ChainValidationResult.IncompleteChain); - } - - if (_options.TlsOptions.AllowUntrustedCertificates) - { - result.Add(ChainValidationResult.Untrusted); - } - - return result; - } - - private void CreateStreams() - { - // Attention! Do not set the buffer for the read method. This will - // limit the internal buffer and the read operation will hang forever - // if more data than the buffer size was received. - _readStream = _socket.InputStream.AsStreamForRead(); - - _writeStream = _socket.OutputStream.AsStreamForWrite(_bufferSize); - } - - private static void TryDispose(IDisposable disposable, Action afterDispose) - { - try - { - disposable?.Dispose(); - } - catch (ObjectDisposedException) - { - } - catch (NullReferenceException) - { - } - finally - { - afterDispose(); - } - } - } -} -#endif \ No newline at end of file diff --git a/Source/MQTTnet/Implementations/MqttTcpChannel.cs b/Source/MQTTnet/Implementations/MqttTcpChannel.cs index 12fd2bb..9a68e55 100644 --- a/Source/MQTTnet/Implementations/MqttTcpChannel.cs +++ b/Source/MQTTnet/Implementations/MqttTcpChannel.cs @@ -1,4 +1,3 @@ -#if !WINDOWS_UWP using System; using System.Net.Security; using System.Net.Sockets; @@ -72,7 +71,7 @@ namespace MQTTnet.Implementations // Workaround for: workaround for https://github.com/dotnet/corefx/issues/24430 using (cancellationToken.Register(() => socket.Dispose())) { -#if NET452 || NET461 +#if NET452 await Task.Factory.FromAsync(socket.BeginConnect, socket.EndConnect, _options.Server, _options.GetPort(), null).ConfigureAwait(false); #else await socket.ConnectAsync(_options.Server, _options.GetPort()).ConfigureAwait(false); @@ -220,5 +219,4 @@ namespace MQTTnet.Implementations return certificates; } } -} -#endif +} \ No newline at end of file diff --git a/Source/MQTTnet/Implementations/MqttTcpServerAdapter.Uwp.cs b/Source/MQTTnet/Implementations/MqttTcpServerAdapter.Uwp.cs deleted file mode 100644 index 3b24bd1..0000000 --- a/Source/MQTTnet/Implementations/MqttTcpServerAdapter.Uwp.cs +++ /dev/null @@ -1,122 +0,0 @@ -#if WINDOWS_UWP -using Windows.Networking.Sockets; -using MQTTnet.Adapter; -using MQTTnet.Diagnostics; -using MQTTnet.Formatter; -using MQTTnet.Server; -using System; -using System.Runtime.InteropServices.WindowsRuntime; -using System.Security.Cryptography.X509Certificates; -using System.Threading.Tasks; - -namespace MQTTnet.Implementations -{ - public class MqttTcpServerAdapter : IMqttServerAdapter - { - private readonly IMqttNetChildLogger _logger; - - private IMqttServerOptions _options; - private StreamSocketListener _listener; - - public MqttTcpServerAdapter(IMqttNetChildLogger logger) - { - if (logger == null) throw new ArgumentNullException(nameof(logger)); - - _logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter)); - } - - public Func ClientHandler { get; set; } - - public async Task StartAsync(IMqttServerOptions options) - { - _options = options ?? throw new ArgumentNullException(nameof(options)); - - if (_listener != null) throw new InvalidOperationException("Server is already started."); - - if (options.DefaultEndpointOptions.IsEnabled) - { - _listener = new StreamSocketListener(); - - // This also affects the client sockets. - _listener.Control.NoDelay = options.DefaultEndpointOptions.NoDelay; - _listener.Control.KeepAlive = true; - _listener.Control.QualityOfService = SocketQualityOfService.LowLatency; - _listener.ConnectionReceived += OnConnectionReceivedAsync; - - await _listener.BindServiceNameAsync(options.DefaultEndpointOptions.Port.ToString(), SocketProtectionLevel.PlainSocket); - } - - if (options.TlsEndpointOptions.IsEnabled) - { - throw new NotSupportedException("TLS servers are not supported for UWP apps."); - } - } - - public Task StopAsync() - { - if (_listener != null) - { - _listener.ConnectionReceived -= OnConnectionReceivedAsync; - } - - return Task.FromResult(0); - } - - public void Dispose() - { - _listener?.Dispose(); - _listener = null; - } - - private async void OnConnectionReceivedAsync(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args) - { - try - { - var clientHandler = ClientHandler; - if (clientHandler != null) - { - X509Certificate2 clientCertificate = null; - - if (args.Socket.Control.ClientCertificate != null) - { - try - { - clientCertificate = new X509Certificate2(args.Socket.Control.ClientCertificate.GetCertificateBlob().ToArray()); - } - catch (Exception exception) - { - _logger.Warning(exception, "Unable to convert UWP certificate to X509Certificate2."); - } - } - - using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket, clientCertificate, _options), new MqttPacketFormatterAdapter(), _logger)) - { - await clientHandler(clientAdapter).ConfigureAwait(false); - } - } - } - catch (Exception exception) - { - if (exception is ObjectDisposedException) - { - // It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed. - return; - } - - _logger.Error(exception, "Error while handling client connection."); - } - finally - { - try - { - args.Socket.Dispose(); - } - catch (Exception exception) - { - _logger.Error(exception, "Error while cleaning up client connection"); - } - } - } - } -} -#endif \ No newline at end of file diff --git a/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs b/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs index e3dcab8..b1ec182 100644 --- a/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs +++ b/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs @@ -1,5 +1,4 @@ -#if !WINDOWS_UWP -using System; +using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; @@ -128,5 +127,4 @@ namespace MQTTnet.Implementations return clientHandler(channelAdapter); } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/Source/MQTTnet/Implementations/MqttTcpServerListener.cs b/Source/MQTTnet/Implementations/MqttTcpServerListener.cs index d57888e..93b247f 100644 --- a/Source/MQTTnet/Implementations/MqttTcpServerListener.cs +++ b/Source/MQTTnet/Implementations/MqttTcpServerListener.cs @@ -1,5 +1,4 @@ -#if !WINDOWS_UWP -using System; +using System; using System.IO; using System.Net; using System.Net.Security; @@ -96,7 +95,7 @@ namespace MQTTnet.Implementations { _socket?.Dispose(); -#if NETSTANDARD1_3 || NETSTANDARD2_0 || NET461 || NET472 +#if NETSTANDARD1_3 || NETSTANDARD2_0 _tlsCertificate?.Dispose(); #endif } @@ -107,7 +106,7 @@ namespace MQTTnet.Implementations { try { -#if NET452 || NET461 +#if NET452 var clientSocket = await Task.Factory.FromAsync(_socket.BeginAccept, _socket.EndAccept, null).ConfigureAwait(false); #else var clientSocket = await _socket.AcceptAsync().ConfigureAwait(false); @@ -224,5 +223,4 @@ namespace MQTTnet.Implementations } } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/Source/MQTTnet/Implementations/MqttWebSocketChannel.cs b/Source/MQTTnet/Implementations/MqttWebSocketChannel.cs index 38e4342..e27cd09 100644 --- a/Source/MQTTnet/Implementations/MqttWebSocketChannel.cs +++ b/Source/MQTTnet/Implementations/MqttWebSocketChannel.cs @@ -161,10 +161,8 @@ namespace MQTTnet.Implementations return null; } -#if WINDOWS_UWP - throw new NotSupportedException("Proxies are not supported in UWP."); -#elif NETSTANDARD1_3 - throw new NotSupportedException("Proxies are not supported in netstandard 1.3."); +#if NETSTANDARD1_3 + throw new NotSupportedException("Proxies are not supported in netstandard1.3."); #else var proxyUri = new Uri(_options.ProxyOptions.Address); diff --git a/Source/MQTTnet/MQTTnet.csproj b/Source/MQTTnet/MQTTnet.csproj index 61ca517..1616d73 100644 --- a/Source/MQTTnet/MQTTnet.csproj +++ b/Source/MQTTnet/MQTTnet.csproj @@ -2,8 +2,7 @@ netstandard1.3;netstandard2.0 - $(TargetFrameworks);net452;net461 - $(TargetFrameworks);uap10.0 + $(TargetFrameworks);net452 MQTTnet MQTTnet False @@ -16,30 +15,13 @@ false - - false - UAP,Version=v10.0 - UAP - 10.0.17134.0 - 10.0.10586.212 - .NETCore - v5.0 - $(DefineConstants);WINDOWS_UWP - en - $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets - - Full - - - - - + @@ -53,14 +35,7 @@ - - - - - - - \ No newline at end of file diff --git a/Source/MQTTnet/Server/MqttServerOptionsBuilder.cs b/Source/MQTTnet/Server/MqttServerOptionsBuilder.cs index c25af84..0f21728 100644 --- a/Source/MQTTnet/Server/MqttServerOptionsBuilder.cs +++ b/Source/MQTTnet/Server/MqttServerOptionsBuilder.cs @@ -95,7 +95,6 @@ namespace MQTTnet.Server return this; } -#if !WINDOWS_UWP public MqttServerOptionsBuilder WithClientCertificate(RemoteCertificateValidationCallback validationCallback = null, bool checkCertificateRevocation = false) { _options.TlsEndpointOptions.ClientCertificateRequired = true; @@ -103,7 +102,6 @@ namespace MQTTnet.Server _options.TlsEndpointOptions.RemoteCertificateValidationCallback = validationCallback; return this; } -#endif public MqttServerOptionsBuilder WithoutEncryptedEndpoint() { @@ -111,14 +109,12 @@ namespace MQTTnet.Server return this; } -#if !WINDOWS_UWP public MqttServerOptionsBuilder WithRemoteCertificateValidationCallback(RemoteCertificateValidationCallback value) { _options.TlsEndpointOptions.RemoteCertificateValidationCallback = value; return this; } -#endif - + public MqttServerOptionsBuilder WithStorage(IMqttServerStorage value) { _options.Storage = value; diff --git a/Source/MQTTnet/Server/MqttServerTcpEndpointBaseOptions.cs b/Source/MQTTnet/Server/MqttServerTcpEndpointBaseOptions.cs index 7f305fe..29776aa 100644 --- a/Source/MQTTnet/Server/MqttServerTcpEndpointBaseOptions.cs +++ b/Source/MQTTnet/Server/MqttServerTcpEndpointBaseOptions.cs @@ -12,10 +12,6 @@ namespace MQTTnet.Server public bool NoDelay { get; set; } = true; -#if WINDOWS_UWP - public int BufferSize { get; set; } = 4096; -#endif - public IPAddress BoundInterNetworkAddress { get; set; } = IPAddress.Any; public IPAddress BoundInterNetworkV6Address { get; set; } = IPAddress.IPv6Any; diff --git a/Source/MQTTnet/Server/MqttServerTlsTcpEndpointOptions.cs b/Source/MQTTnet/Server/MqttServerTlsTcpEndpointOptions.cs index 9bf325b..c9c7791 100644 --- a/Source/MQTTnet/Server/MqttServerTlsTcpEndpointOptions.cs +++ b/Source/MQTTnet/Server/MqttServerTlsTcpEndpointOptions.cs @@ -17,10 +17,8 @@ namespace MQTTnet.Server public bool ClientCertificateRequired { get; set; } public bool CheckCertificateRevocation { get; set; } - -#if !WINDOWS_UWP public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; } -#endif + public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12; } } diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index 94abc41..13085b5 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -653,18 +653,7 @@ namespace MQTTnet.TestApp.UniversalWindows } // ---------------------------------- - - // For UWP apps: - MqttTcpChannel.CustomIgnorableServerCertificateErrorsResolver = o => - { - if (o.Server == "server_with_revoked_cert") - { - return new[] { ChainValidationResult.Revoked }; - } - - return new ChainValidationResult[0]; - }; - + { // Start a MQTT server. var mqttServer = new MqttFactory().CreateMqttServer(); From 6c53677e7d11f7e876ec7fb59fc58a89cbad4647 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sun, 11 Aug 2019 22:10:49 +0200 Subject: [PATCH 04/17] Update nugets. --- Build/MQTTnet.Extensions.ManagedClient.nuspec | 14 ++++---------- Build/MQTTnet.Extensions.Rpc.nuspec | 14 ++++---------- Build/MQTTnet.Extensions.WebSocket4Net.nuspec | 14 ++++---------- Build/MQTTnet.nuspec | 2 ++ 4 files changed, 14 insertions(+), 30 deletions(-) diff --git a/Build/MQTTnet.Extensions.ManagedClient.nuspec b/Build/MQTTnet.Extensions.ManagedClient.nuspec index edec769..2ba0a5e 100644 --- a/Build/MQTTnet.Extensions.ManagedClient.nuspec +++ b/Build/MQTTnet.Extensions.ManagedClient.nuspec @@ -19,24 +19,18 @@ + + + + - - - - - - - - - - diff --git a/Build/MQTTnet.Extensions.Rpc.nuspec b/Build/MQTTnet.Extensions.Rpc.nuspec index ce81cb6..1a1b087 100644 --- a/Build/MQTTnet.Extensions.Rpc.nuspec +++ b/Build/MQTTnet.Extensions.Rpc.nuspec @@ -19,24 +19,18 @@ + + + + - - - - - - - - - - diff --git a/Build/MQTTnet.Extensions.WebSocket4Net.nuspec b/Build/MQTTnet.Extensions.WebSocket4Net.nuspec index 054933e..ced0fe1 100644 --- a/Build/MQTTnet.Extensions.WebSocket4Net.nuspec +++ b/Build/MQTTnet.Extensions.WebSocket4Net.nuspec @@ -19,24 +19,18 @@ + + + + - - - - - - - - - - diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index eded1fd..93b4db5 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -18,6 +18,8 @@ Copyright Christian Kratky 2016-2019 MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin + + From 232605304e65f76f042c01ffc8f29842a5097eb3 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sun, 11 Aug 2019 22:10:49 +0200 Subject: [PATCH 05/17] Revert "Update nugets." This reverts commit 6c53677e7d11f7e876ec7fb59fc58a89cbad4647. --- Build/MQTTnet.Extensions.ManagedClient.nuspec | 14 ++++++++++---- Build/MQTTnet.Extensions.Rpc.nuspec | 14 ++++++++++---- Build/MQTTnet.Extensions.WebSocket4Net.nuspec | 14 ++++++++++---- Build/MQTTnet.nuspec | 2 -- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Build/MQTTnet.Extensions.ManagedClient.nuspec b/Build/MQTTnet.Extensions.ManagedClient.nuspec index 2ba0a5e..edec769 100644 --- a/Build/MQTTnet.Extensions.ManagedClient.nuspec +++ b/Build/MQTTnet.Extensions.ManagedClient.nuspec @@ -19,18 +19,24 @@ - - - - + + + + + + + + + + diff --git a/Build/MQTTnet.Extensions.Rpc.nuspec b/Build/MQTTnet.Extensions.Rpc.nuspec index 1a1b087..ce81cb6 100644 --- a/Build/MQTTnet.Extensions.Rpc.nuspec +++ b/Build/MQTTnet.Extensions.Rpc.nuspec @@ -19,18 +19,24 @@ - - - - + + + + + + + + + + diff --git a/Build/MQTTnet.Extensions.WebSocket4Net.nuspec b/Build/MQTTnet.Extensions.WebSocket4Net.nuspec index ced0fe1..054933e 100644 --- a/Build/MQTTnet.Extensions.WebSocket4Net.nuspec +++ b/Build/MQTTnet.Extensions.WebSocket4Net.nuspec @@ -19,18 +19,24 @@ - - - - + + + + + + + + + + diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 93b4db5..eded1fd 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -18,8 +18,6 @@ Copyright Christian Kratky 2016-2019 MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin - - From 9ac726b2712a62b8e646d1a59e78176e558459d0 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sun, 11 Aug 2019 22:07:57 +0200 Subject: [PATCH 06/17] Revert "Remove dedicated UWP builds and code." This reverts commit 6d0e2c20223a3d313276983ab389c7e560e4a7a1. --- Build/MQTTnet.nuspec | 30 +- Build/build.ps1 | 8 + MQTTnet.noUWP.sln | 260 ++++++++++++++++++ .../MQTTnet.Extensions.ManagedClient.csproj | 16 +- .../MQTTnet.Extensions.Rpc.csproj | 16 +- .../MQTTnet.Extensions.WebSocket4Net.csproj | 16 +- .../TargetFrameworkInfoProvider.cs | 6 + Source/MQTTnet/Formatter/MqttPacketReader.cs | 53 ++++ .../Implementations/MqttTcpChannel.Uwp.cs | 196 +++++++++++++ .../MQTTnet/Implementations/MqttTcpChannel.cs | 6 +- .../MqttTcpServerAdapter.Uwp.cs | 122 ++++++++ .../Implementations/MqttTcpServerAdapter.cs | 6 +- .../Implementations/MqttTcpServerListener.cs | 10 +- .../Implementations/MqttWebSocketChannel.cs | 6 +- Source/MQTTnet/MQTTnet.csproj | 31 ++- .../Server/MqttServerOptionsBuilder.cs | 6 +- .../MqttServerTcpEndpointBaseOptions.cs | 4 + .../Server/MqttServerTlsTcpEndpointOptions.cs | 4 +- .../MainPage.xaml.cs | 13 +- 19 files changed, 783 insertions(+), 26 deletions(-) create mode 100644 MQTTnet.noUWP.sln create mode 100644 Source/MQTTnet/Implementations/MqttTcpChannel.Uwp.cs create mode 100644 Source/MQTTnet/Implementations/MqttTcpServerAdapter.Uwp.cs diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index eded1fd..6aafdc6 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -11,9 +11,16 @@ false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol. -* [Core] Removed dedicated UWP builds. The lib is now supporting net452, netstandard1.3 and netstandard2.0 only (which covers mostly everything currently supported by MS). -* [Server] Refactoring of TLS certificate handling (BREAKING CHANGE!) -* [MQTTnet.Server] Added support for passwords when using TLS certificate (BREAKING CHANGE!) +* [Core] Nuget packages with symbols are now also published to improve debugging. +* [Core] Improve task handling (thanks to @mwinterb) +* [ManagedClient] Fix a race condition in the message storage (thanks to @PaulFake). +* [Server] Added items dictionary to client session in order to share data across interceptors as along as the session exists. +* [Server] Exposed CONNECT packet properties in Application Message and Subscription interceptor. +* [Server] Fixed: Sending Large packets with AspnetCore based connection throws System.ArgumentException. +* [Server] Fixed wrong usage of socket option _NoDelay_. +* [Server] Added remote certificate validation callback (thanks to @rudacs). +* [Server] Add support for certificate passwords (thanks to @cslutgen). +* [MQTTnet.Server] Added REST API for publishing basic messages. Copyright Christian Kratky 2016-2019 MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin @@ -30,22 +37,31 @@ + + + - - - - + + + + + + + + + + \ No newline at end of file diff --git a/Build/build.ps1 b/Build/build.ps1 index 08107dc..33f2767 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -14,26 +14,34 @@ Write-Host # Build the core library &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" +&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" +&$msbuild ..\Source\MQTTnet\MQTTnet.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" # Build the ASP.NET Core 2.0 extension &$msbuild ..\Source\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" # Build the RPC extension &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" +&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" +&$msbuild ..\Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" # Build the Managed Client extension &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" +&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" +&$msbuild ..\Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" # Build the WebSocket4Net extension &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" +&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" +&$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" # Create NuGet packages. diff --git a/MQTTnet.noUWP.sln b/MQTTnet.noUWP.sln new file mode 100644 index 0000000..3d842a5 --- /dev/null +++ b/MQTTnet.noUWP.sln @@ -0,0 +1,260 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2010 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{9248C2E1-B9D6-40BF-81EC-86004D7765B4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{32A630A7-2598-41D7-B625-204CD906F5FB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet", "Source\MQTTnet\MQTTnet.csproj", "{3587E506-55A2-4EB3-99C7-DC01E42D25D2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{67C28AC1-BC3A-420A-BE9C-FA2401431CF9}" + ProjectSection(SolutionItems) = preProject + Build\build.ps1 = Build\build.ps1 + Build\MQTTnet.AspNetCore.nuspec = Build\MQTTnet.AspNetCore.nuspec + Build\MQTTnet.Extensions.ManagedClient.nuspec = Build\MQTTnet.Extensions.ManagedClient.nuspec + Build\MQTTnet.Extensions.Rpc.nuspec = Build\MQTTnet.Extensions.Rpc.nuspec + Build\MQTTnet.nuspec = Build\MQTTnet.nuspec + Build\upload.ps1 = Build\upload.ps1 + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B3F60ECB-45BA-4C66-8903-8BB89CA67998}" + ProjectSection(SolutionItems) = preProject + .bettercodehub.yml = .bettercodehub.yml + appveyor.yml = appveyor.yml + LICENSE = LICENSE + README.md = README.md + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.TestApp.NetCore", "Tests\MQTTnet.TestApp.NetCore\MQTTnet.TestApp.NetCore.csproj", "{3D283AAD-AAA8-4339-8394-52F80B6304DB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.TestApp.AspNetCore2", "Tests\MQTTnet.TestApp.AspNetCore2\MQTTnet.TestApp.AspNetCore2.csproj", "{C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.AspNetCore", "Source\MQTTnet.AspnetCore\MQTTnet.AspNetCore.csproj", "{F10C4060-F7EE-4A83-919F-FF723E72F94A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{12816BCC-AF9E-44A9-9AE5-C246AF2A0587}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.Rpc", "Source\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj", "{C444E9C8-95FA-430E-9126-274129DE16CD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Benchmarks", "Tests\MQTTnet.Benchmarks\MQTTnet.Benchmarks.csproj", "{998D04DD-7CB0-45F5-A393-E2495C16399E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.ManagedClient", "Source\MQTTnet.Extensions.ManagedClient\MQTTnet.Extensions.ManagedClient.csproj", "{C400533A-8EBA-4F0B-BF4D-295C3708604B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.AspNetCore.Tests", "Tests\MQTTnet.AspNetCore.Tests\MQTTnet.AspNetCore.Tests.csproj", "{61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Tests.csproj", "{9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Server", "Source\MQTTnet.Server\MQTTnet.Server.csproj", "{DADEA836-5CC3-474C-A2D8-4D0F31118CD7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.WebSocket4Net", "Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj", "{9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|ARM.ActiveCfg = Debug|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|ARM.Build.0 = Debug|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|x64.ActiveCfg = Debug|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|x64.Build.0 = Debug|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|x86.ActiveCfg = Debug|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Debug|x86.Build.0 = Debug|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|Any CPU.Build.0 = Release|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|ARM.ActiveCfg = Release|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|ARM.Build.0 = Release|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|x64.ActiveCfg = Release|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|x64.Build.0 = Release|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|x86.ActiveCfg = Release|Any CPU + {3587E506-55A2-4EB3-99C7-DC01E42D25D2}.Release|x86.Build.0 = Release|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|ARM.ActiveCfg = Debug|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|ARM.Build.0 = Debug|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|x64.ActiveCfg = Debug|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|x64.Build.0 = Debug|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|x86.ActiveCfg = Debug|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Debug|x86.Build.0 = Debug|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|Any CPU.Build.0 = Release|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|ARM.ActiveCfg = Release|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|ARM.Build.0 = Release|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|x64.ActiveCfg = Release|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|x64.Build.0 = Release|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|x86.ActiveCfg = Release|Any CPU + {3D283AAD-AAA8-4339-8394-52F80B6304DB}.Release|x86.Build.0 = Release|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|ARM.ActiveCfg = Debug|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|ARM.Build.0 = Debug|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|x64.ActiveCfg = Debug|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|x64.Build.0 = Debug|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|x86.ActiveCfg = Debug|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Debug|x86.Build.0 = Debug|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|Any CPU.Build.0 = Release|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|ARM.ActiveCfg = Release|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|ARM.Build.0 = Release|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|x64.ActiveCfg = Release|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|x64.Build.0 = Release|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|x86.ActiveCfg = Release|Any CPU + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9}.Release|x86.Build.0 = Release|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|ARM.ActiveCfg = Debug|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|ARM.Build.0 = Debug|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|x64.ActiveCfg = Debug|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|x64.Build.0 = Debug|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|x86.ActiveCfg = Debug|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Debug|x86.Build.0 = Debug|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|Any CPU.Build.0 = Release|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|ARM.ActiveCfg = Release|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|ARM.Build.0 = Release|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|x64.ActiveCfg = Release|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|x64.Build.0 = Release|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|x86.ActiveCfg = Release|Any CPU + {F10C4060-F7EE-4A83-919F-FF723E72F94A}.Release|x86.Build.0 = Release|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|ARM.ActiveCfg = Debug|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|ARM.Build.0 = Debug|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|x64.ActiveCfg = Debug|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|x64.Build.0 = Debug|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|x86.ActiveCfg = Debug|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Debug|x86.Build.0 = Debug|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|Any CPU.Build.0 = Release|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|ARM.ActiveCfg = Release|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|ARM.Build.0 = Release|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|x64.ActiveCfg = Release|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|x64.Build.0 = Release|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|x86.ActiveCfg = Release|Any CPU + {C444E9C8-95FA-430E-9126-274129DE16CD}.Release|x86.Build.0 = Release|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|ARM.ActiveCfg = Debug|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|ARM.Build.0 = Debug|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|x64.ActiveCfg = Debug|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|x64.Build.0 = Debug|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|x86.ActiveCfg = Debug|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Debug|x86.Build.0 = Debug|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|Any CPU.Build.0 = Release|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|ARM.ActiveCfg = Release|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|ARM.Build.0 = Release|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|x64.ActiveCfg = Release|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|x64.Build.0 = Release|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|x86.ActiveCfg = Release|Any CPU + {998D04DD-7CB0-45F5-A393-E2495C16399E}.Release|x86.Build.0 = Release|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|ARM.ActiveCfg = Debug|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|ARM.Build.0 = Debug|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|x64.ActiveCfg = Debug|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|x64.Build.0 = Debug|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|x86.ActiveCfg = Debug|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Debug|x86.Build.0 = Debug|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|Any CPU.Build.0 = Release|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|ARM.ActiveCfg = Release|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|ARM.Build.0 = Release|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|x64.ActiveCfg = Release|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|x64.Build.0 = Release|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|x86.ActiveCfg = Release|Any CPU + {C400533A-8EBA-4F0B-BF4D-295C3708604B}.Release|x86.Build.0 = Release|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|ARM.ActiveCfg = Debug|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|ARM.Build.0 = Debug|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|x64.ActiveCfg = Debug|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|x64.Build.0 = Debug|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|x86.ActiveCfg = Debug|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Debug|x86.Build.0 = Debug|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|Any CPU.Build.0 = Release|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|ARM.ActiveCfg = Release|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|ARM.Build.0 = Release|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x64.ActiveCfg = Release|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x64.Build.0 = Release|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x86.ActiveCfg = Release|Any CPU + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E}.Release|x86.Build.0 = Release|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|ARM.ActiveCfg = Debug|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|ARM.Build.0 = Debug|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|x64.ActiveCfg = Debug|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|x64.Build.0 = Debug|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|x86.ActiveCfg = Debug|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Debug|x86.Build.0 = Debug|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|Any CPU.Build.0 = Release|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|ARM.ActiveCfg = Release|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|ARM.Build.0 = Release|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|x64.ActiveCfg = Release|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|x64.Build.0 = Release|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|x86.ActiveCfg = Release|Any CPU + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41}.Release|x86.Build.0 = Release|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|ARM.ActiveCfg = Debug|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|ARM.Build.0 = Debug|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|x64.ActiveCfg = Debug|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|x64.Build.0 = Debug|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|x86.ActiveCfg = Debug|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Debug|x86.Build.0 = Debug|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|Any CPU.Build.0 = Release|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|ARM.ActiveCfg = Release|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|ARM.Build.0 = Release|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|x64.ActiveCfg = Release|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|x64.Build.0 = Release|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|x86.ActiveCfg = Release|Any CPU + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7}.Release|x86.Build.0 = Release|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|ARM.ActiveCfg = Debug|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|ARM.Build.0 = Debug|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|x64.ActiveCfg = Debug|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|x64.Build.0 = Debug|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|x86.ActiveCfg = Debug|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Debug|x86.Build.0 = Debug|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|Any CPU.Build.0 = Release|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|ARM.ActiveCfg = Release|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|ARM.Build.0 = Release|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|x64.ActiveCfg = Release|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|x64.Build.0 = Release|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|x86.ActiveCfg = Release|Any CPU + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {3587E506-55A2-4EB3-99C7-DC01E42D25D2} = {32A630A7-2598-41D7-B625-204CD906F5FB} + {3D283AAD-AAA8-4339-8394-52F80B6304DB} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} + {C6FF8AEA-0855-41EC-A1F3-AC262225BAB9} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} + {F10C4060-F7EE-4A83-919F-FF723E72F94A} = {32A630A7-2598-41D7-B625-204CD906F5FB} + {C444E9C8-95FA-430E-9126-274129DE16CD} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587} + {998D04DD-7CB0-45F5-A393-E2495C16399E} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} + {C400533A-8EBA-4F0B-BF4D-295C3708604B} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587} + {61B62223-F5D0-48E4-BBD6-2CBA9353CB5E} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} + {9C7106CA-96B8-4ABE-B3B4-9357AB8ACB41} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} + {DADEA836-5CC3-474C-A2D8-4D0F31118CD7} = {32A630A7-2598-41D7-B625-204CD906F5FB} + {9AE2F8DA-4178-470B-B8C4-88BE1DAE7D5F} = {12816BCC-AF9E-44A9-9AE5-C246AF2A0587} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {07536672-5CBC-4BE3-ACE0-708A431A7894} + EndGlobalSection +EndGlobal diff --git a/Source/MQTTnet.Extensions.ManagedClient/MQTTnet.Extensions.ManagedClient.csproj b/Source/MQTTnet.Extensions.ManagedClient/MQTTnet.Extensions.ManagedClient.csproj index 80131c4..b59b7f4 100644 --- a/Source/MQTTnet.Extensions.ManagedClient/MQTTnet.Extensions.ManagedClient.csproj +++ b/Source/MQTTnet.Extensions.ManagedClient/MQTTnet.Extensions.ManagedClient.csproj @@ -2,13 +2,27 @@ netstandard1.3;netstandard2.0 - $(TargetFrameworks);net452 + $(TargetFrameworks);net452;net461 + $(TargetFrameworks);uap10.0 + + false + UAP,Version=v10.0 + UAP + 10.0.17134.0 + 10.0.10240.0 + .NETCore + v5.0 + $(DefineConstants);WINDOWS_UWP + en + $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets + + diff --git a/Source/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj b/Source/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj index 80131c4..b59b7f4 100644 --- a/Source/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj +++ b/Source/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj @@ -2,13 +2,27 @@ netstandard1.3;netstandard2.0 - $(TargetFrameworks);net452 + $(TargetFrameworks);net452;net461 + $(TargetFrameworks);uap10.0 + + false + UAP,Version=v10.0 + UAP + 10.0.17134.0 + 10.0.10240.0 + .NETCore + v5.0 + $(DefineConstants);WINDOWS_UWP + en + $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets + + diff --git a/Source/MQTTnet.Extensions.WebSocket4Net/MQTTnet.Extensions.WebSocket4Net.csproj b/Source/MQTTnet.Extensions.WebSocket4Net/MQTTnet.Extensions.WebSocket4Net.csproj index 639e048..bdf26c6 100644 --- a/Source/MQTTnet.Extensions.WebSocket4Net/MQTTnet.Extensions.WebSocket4Net.csproj +++ b/Source/MQTTnet.Extensions.WebSocket4Net/MQTTnet.Extensions.WebSocket4Net.csproj @@ -2,13 +2,27 @@ netstandard1.3;netstandard2.0 - $(TargetFrameworks);net452 + $(TargetFrameworks);net452;net461 + $(TargetFrameworks);uap10.0 + + false + UAP,Version=v10.0 + UAP + 10.0.17134.0 + 10.0.10240.0 + .NETCore + v5.0 + $(DefineConstants);WINDOWS_UWP + en + $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets + + diff --git a/Source/MQTTnet/Diagnostics/TargetFrameworkInfoProvider.cs b/Source/MQTTnet/Diagnostics/TargetFrameworkInfoProvider.cs index fec0809..efbf08b 100644 --- a/Source/MQTTnet/Diagnostics/TargetFrameworkInfoProvider.cs +++ b/Source/MQTTnet/Diagnostics/TargetFrameworkInfoProvider.cs @@ -8,10 +8,16 @@ { #if NET452 return "net452"; +#elif NET461 + return "net461"; +#elif NET472 + return "net472"; #elif NETSTANDARD1_3 return "netstandard1.3"; #elif NETSTANDARD2_0 return "netstandard2.0"; +#elif WINDOWS_UWP + return "uap10.0"; #endif } } diff --git a/Source/MQTTnet/Formatter/MqttPacketReader.cs b/Source/MQTTnet/Formatter/MqttPacketReader.cs index 5cd4dcf..2589c5b 100644 --- a/Source/MQTTnet/Formatter/MqttPacketReader.cs +++ b/Source/MQTTnet/Formatter/MqttPacketReader.cs @@ -55,7 +55,16 @@ namespace MQTTnet.Formatter }; } +#if WINDOWS_UWP + // UWP will have a dead lock when calling this not async. var bodyLength = await ReadBodyLengthAsync(buffer[1], cancellationToken).ConfigureAwait(false); +#else + // Here the async/await pattern is not used because the overhead of context switches + // is too big for reading 1 byte in a row. We expect that the remaining data was sent + // directly after the initial bytes. If the client disconnects just in this moment we + // will get an exception anyway. + var bodyLength = ReadBodyLength(buffer[1], cancellationToken); +#endif if (!bodyLength.HasValue) { @@ -72,6 +81,49 @@ namespace MQTTnet.Formatter }; } +#if !WINDOWS_UWP + private int? ReadBodyLength(byte initialEncodedByte, CancellationToken cancellationToken) + { + var offset = 0; + var multiplier = 128; + var value = initialEncodedByte & 127; + int encodedByte = initialEncodedByte; + + while ((encodedByte & 128) != 0) + { + offset++; + if (offset > 3) + { + throw new MqttProtocolViolationException("Remaining length is invalid."); + } + + if (cancellationToken.IsCancellationRequested) + { + return null; + } + + var readCount = _channel.ReadAsync(_singleByteBuffer, 0, 1, cancellationToken).GetAwaiter().GetResult(); + + if (cancellationToken.IsCancellationRequested) + { + return null; + } + + if (readCount == 0) + { + return null; + } + + encodedByte = _singleByteBuffer[0]; + + value += (encodedByte & 127) * multiplier; + multiplier *= 128; + } + + return value; + } +#else + private async Task ReadBodyLengthAsync(byte initialEncodedByte, CancellationToken cancellationToken) { var offset = 0; @@ -112,5 +164,6 @@ namespace MQTTnet.Formatter return value; } +#endif } } diff --git a/Source/MQTTnet/Implementations/MqttTcpChannel.Uwp.cs b/Source/MQTTnet/Implementations/MqttTcpChannel.Uwp.cs new file mode 100644 index 0000000..cb0f71c --- /dev/null +++ b/Source/MQTTnet/Implementations/MqttTcpChannel.Uwp.cs @@ -0,0 +1,196 @@ +#if WINDOWS_UWP +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using Windows.Networking; +using Windows.Networking.Sockets; +using Windows.Security.Cryptography.Certificates; +using MQTTnet.Channel; +using MQTTnet.Client.Options; +using MQTTnet.Server; + +namespace MQTTnet.Implementations +{ + public class MqttTcpChannel : IMqttChannel + { + private readonly MqttClientTcpOptions _options; + private readonly int _bufferSize; + + private StreamSocket _socket; + private Stream _readStream; + private Stream _writeStream; + + public MqttTcpChannel(IMqttClientOptions clientOptions) + { + _options = (MqttClientTcpOptions)clientOptions.ChannelOptions; + _bufferSize = _options.BufferSize; + } + + public MqttTcpChannel(StreamSocket socket, X509Certificate2 clientCertificate, IMqttServerOptions serverOptions) + { + _socket = socket ?? throw new ArgumentNullException(nameof(socket)); + _bufferSize = serverOptions.DefaultEndpointOptions.BufferSize; + + CreateStreams(); + + IsSecureConnection = socket.Information.ProtectionLevel >= SocketProtectionLevel.Tls12; + ClientCertificate = clientCertificate; + + Endpoint = _socket.Information.RemoteAddress + ":" + _socket.Information.RemotePort; + } + + public static Func> CustomIgnorableServerCertificateErrorsResolver { get; set; } + + public string Endpoint { get; private set; } + + public bool IsSecureConnection { get; } + + public X509Certificate2 ClientCertificate { get; } + + public async Task ConnectAsync(CancellationToken cancellationToken) + { + if (_socket == null) + { + _socket = new StreamSocket(); + _socket.Control.NoDelay = _options.NoDelay; + _socket.Control.KeepAlive = true; + } + + if (_options.TlsOptions?.UseTls != true) + { + await _socket.ConnectAsync(new HostName(_options.Server), _options.GetPort().ToString()); + } + else + { + _socket.Control.ClientCertificate = LoadCertificate(_options); + + foreach (var ignorableChainValidationResult in ResolveIgnorableServerCertificateErrors()) + { + _socket.Control.IgnorableServerCertificateErrors.Add(ignorableChainValidationResult); + } + + var socketProtectionLevel = SocketProtectionLevel.Tls12; + if (_options.TlsOptions.SslProtocol == SslProtocols.Tls11) + { + socketProtectionLevel = SocketProtectionLevel.Tls11; + } + else if (_options.TlsOptions.SslProtocol == SslProtocols.Tls) + { + socketProtectionLevel = SocketProtectionLevel.Tls10; + } + + await _socket.ConnectAsync(new HostName(_options.Server), _options.GetPort().ToString(), socketProtectionLevel); + } + + Endpoint = _socket.Information.RemoteAddress + ":" + _socket.Information.RemotePort; + + CreateStreams(); + } + + public Task DisconnectAsync(CancellationToken cancellationToken) + { + Dispose(); + return Task.FromResult(0); + } + + public Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + return _readStream.ReadAsync(buffer, offset, count, cancellationToken); + } + + public Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + // In the write method only the internal buffer will be filled. So here is no + // async/await required. The real network transmit is done when calling the + // Flush method. + _writeStream.Write(buffer, offset, count); + return _writeStream.FlushAsync(cancellationToken); + } + + public void Dispose() + { + TryDispose(_readStream, () => _readStream = null); + TryDispose(_writeStream, () => _writeStream = null); + TryDispose(_socket, () => _socket = null); + } + + private static Certificate LoadCertificate(IMqttClientChannelOptions options) + { + if (options.TlsOptions.Certificates == null || !options.TlsOptions.Certificates.Any()) + { + return null; + } + + if (options.TlsOptions.Certificates.Count > 1) + { + throw new NotSupportedException("Only one client certificate is supported for UWP."); + } + + return new Certificate(options.TlsOptions.Certificates.First().AsBuffer()); + } + + private IEnumerable ResolveIgnorableServerCertificateErrors() + { + if (CustomIgnorableServerCertificateErrorsResolver != null) + { + return CustomIgnorableServerCertificateErrorsResolver(_options); + } + + var result = new List(); + + if (_options.TlsOptions.IgnoreCertificateRevocationErrors) + { + result.Add(ChainValidationResult.RevocationInformationMissing); + //_socket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Revoked); Not supported. + result.Add(ChainValidationResult.RevocationFailure); + } + + if (_options.TlsOptions.IgnoreCertificateChainErrors) + { + result.Add(ChainValidationResult.IncompleteChain); + } + + if (_options.TlsOptions.AllowUntrustedCertificates) + { + result.Add(ChainValidationResult.Untrusted); + } + + return result; + } + + private void CreateStreams() + { + // Attention! Do not set the buffer for the read method. This will + // limit the internal buffer and the read operation will hang forever + // if more data than the buffer size was received. + _readStream = _socket.InputStream.AsStreamForRead(); + + _writeStream = _socket.OutputStream.AsStreamForWrite(_bufferSize); + } + + private static void TryDispose(IDisposable disposable, Action afterDispose) + { + try + { + disposable?.Dispose(); + } + catch (ObjectDisposedException) + { + } + catch (NullReferenceException) + { + } + finally + { + afterDispose(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Source/MQTTnet/Implementations/MqttTcpChannel.cs b/Source/MQTTnet/Implementations/MqttTcpChannel.cs index 9a68e55..12fd2bb 100644 --- a/Source/MQTTnet/Implementations/MqttTcpChannel.cs +++ b/Source/MQTTnet/Implementations/MqttTcpChannel.cs @@ -1,3 +1,4 @@ +#if !WINDOWS_UWP using System; using System.Net.Security; using System.Net.Sockets; @@ -71,7 +72,7 @@ namespace MQTTnet.Implementations // Workaround for: workaround for https://github.com/dotnet/corefx/issues/24430 using (cancellationToken.Register(() => socket.Dispose())) { -#if NET452 +#if NET452 || NET461 await Task.Factory.FromAsync(socket.BeginConnect, socket.EndConnect, _options.Server, _options.GetPort(), null).ConfigureAwait(false); #else await socket.ConnectAsync(_options.Server, _options.GetPort()).ConfigureAwait(false); @@ -219,4 +220,5 @@ namespace MQTTnet.Implementations return certificates; } } -} \ No newline at end of file +} +#endif diff --git a/Source/MQTTnet/Implementations/MqttTcpServerAdapter.Uwp.cs b/Source/MQTTnet/Implementations/MqttTcpServerAdapter.Uwp.cs new file mode 100644 index 0000000..3b24bd1 --- /dev/null +++ b/Source/MQTTnet/Implementations/MqttTcpServerAdapter.Uwp.cs @@ -0,0 +1,122 @@ +#if WINDOWS_UWP +using Windows.Networking.Sockets; +using MQTTnet.Adapter; +using MQTTnet.Diagnostics; +using MQTTnet.Formatter; +using MQTTnet.Server; +using System; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; + +namespace MQTTnet.Implementations +{ + public class MqttTcpServerAdapter : IMqttServerAdapter + { + private readonly IMqttNetChildLogger _logger; + + private IMqttServerOptions _options; + private StreamSocketListener _listener; + + public MqttTcpServerAdapter(IMqttNetChildLogger logger) + { + if (logger == null) throw new ArgumentNullException(nameof(logger)); + + _logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter)); + } + + public Func ClientHandler { get; set; } + + public async Task StartAsync(IMqttServerOptions options) + { + _options = options ?? throw new ArgumentNullException(nameof(options)); + + if (_listener != null) throw new InvalidOperationException("Server is already started."); + + if (options.DefaultEndpointOptions.IsEnabled) + { + _listener = new StreamSocketListener(); + + // This also affects the client sockets. + _listener.Control.NoDelay = options.DefaultEndpointOptions.NoDelay; + _listener.Control.KeepAlive = true; + _listener.Control.QualityOfService = SocketQualityOfService.LowLatency; + _listener.ConnectionReceived += OnConnectionReceivedAsync; + + await _listener.BindServiceNameAsync(options.DefaultEndpointOptions.Port.ToString(), SocketProtectionLevel.PlainSocket); + } + + if (options.TlsEndpointOptions.IsEnabled) + { + throw new NotSupportedException("TLS servers are not supported for UWP apps."); + } + } + + public Task StopAsync() + { + if (_listener != null) + { + _listener.ConnectionReceived -= OnConnectionReceivedAsync; + } + + return Task.FromResult(0); + } + + public void Dispose() + { + _listener?.Dispose(); + _listener = null; + } + + private async void OnConnectionReceivedAsync(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args) + { + try + { + var clientHandler = ClientHandler; + if (clientHandler != null) + { + X509Certificate2 clientCertificate = null; + + if (args.Socket.Control.ClientCertificate != null) + { + try + { + clientCertificate = new X509Certificate2(args.Socket.Control.ClientCertificate.GetCertificateBlob().ToArray()); + } + catch (Exception exception) + { + _logger.Warning(exception, "Unable to convert UWP certificate to X509Certificate2."); + } + } + + using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket, clientCertificate, _options), new MqttPacketFormatterAdapter(), _logger)) + { + await clientHandler(clientAdapter).ConfigureAwait(false); + } + } + } + catch (Exception exception) + { + if (exception is ObjectDisposedException) + { + // It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed. + return; + } + + _logger.Error(exception, "Error while handling client connection."); + } + finally + { + try + { + args.Socket.Dispose(); + } + catch (Exception exception) + { + _logger.Error(exception, "Error while cleaning up client connection"); + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs b/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs index b1ec182..e3dcab8 100644 --- a/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs +++ b/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs @@ -1,4 +1,5 @@ -using System; +#if !WINDOWS_UWP +using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; @@ -127,4 +128,5 @@ namespace MQTTnet.Implementations return clientHandler(channelAdapter); } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Source/MQTTnet/Implementations/MqttTcpServerListener.cs b/Source/MQTTnet/Implementations/MqttTcpServerListener.cs index 93b247f..d57888e 100644 --- a/Source/MQTTnet/Implementations/MqttTcpServerListener.cs +++ b/Source/MQTTnet/Implementations/MqttTcpServerListener.cs @@ -1,4 +1,5 @@ -using System; +#if !WINDOWS_UWP +using System; using System.IO; using System.Net; using System.Net.Security; @@ -95,7 +96,7 @@ namespace MQTTnet.Implementations { _socket?.Dispose(); -#if NETSTANDARD1_3 || NETSTANDARD2_0 +#if NETSTANDARD1_3 || NETSTANDARD2_0 || NET461 || NET472 _tlsCertificate?.Dispose(); #endif } @@ -106,7 +107,7 @@ namespace MQTTnet.Implementations { try { -#if NET452 +#if NET452 || NET461 var clientSocket = await Task.Factory.FromAsync(_socket.BeginAccept, _socket.EndAccept, null).ConfigureAwait(false); #else var clientSocket = await _socket.AcceptAsync().ConfigureAwait(false); @@ -223,4 +224,5 @@ namespace MQTTnet.Implementations } } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Source/MQTTnet/Implementations/MqttWebSocketChannel.cs b/Source/MQTTnet/Implementations/MqttWebSocketChannel.cs index e27cd09..38e4342 100644 --- a/Source/MQTTnet/Implementations/MqttWebSocketChannel.cs +++ b/Source/MQTTnet/Implementations/MqttWebSocketChannel.cs @@ -161,8 +161,10 @@ namespace MQTTnet.Implementations return null; } -#if NETSTANDARD1_3 - throw new NotSupportedException("Proxies are not supported in netstandard1.3."); +#if WINDOWS_UWP + throw new NotSupportedException("Proxies are not supported in UWP."); +#elif NETSTANDARD1_3 + throw new NotSupportedException("Proxies are not supported in netstandard 1.3."); #else var proxyUri = new Uri(_options.ProxyOptions.Address); diff --git a/Source/MQTTnet/MQTTnet.csproj b/Source/MQTTnet/MQTTnet.csproj index 1616d73..61ca517 100644 --- a/Source/MQTTnet/MQTTnet.csproj +++ b/Source/MQTTnet/MQTTnet.csproj @@ -2,7 +2,8 @@ netstandard1.3;netstandard2.0 - $(TargetFrameworks);net452 + $(TargetFrameworks);net452;net461 + $(TargetFrameworks);uap10.0 MQTTnet MQTTnet False @@ -15,13 +16,30 @@ false + + false + UAP,Version=v10.0 + UAP + 10.0.17134.0 + 10.0.10586.212 + .NETCore + v5.0 + $(DefineConstants);WINDOWS_UWP + en + $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets + + Full + + - + @@ -35,7 +53,14 @@ + + + + + + + \ No newline at end of file diff --git a/Source/MQTTnet/Server/MqttServerOptionsBuilder.cs b/Source/MQTTnet/Server/MqttServerOptionsBuilder.cs index 0f21728..c25af84 100644 --- a/Source/MQTTnet/Server/MqttServerOptionsBuilder.cs +++ b/Source/MQTTnet/Server/MqttServerOptionsBuilder.cs @@ -95,6 +95,7 @@ namespace MQTTnet.Server return this; } +#if !WINDOWS_UWP public MqttServerOptionsBuilder WithClientCertificate(RemoteCertificateValidationCallback validationCallback = null, bool checkCertificateRevocation = false) { _options.TlsEndpointOptions.ClientCertificateRequired = true; @@ -102,6 +103,7 @@ namespace MQTTnet.Server _options.TlsEndpointOptions.RemoteCertificateValidationCallback = validationCallback; return this; } +#endif public MqttServerOptionsBuilder WithoutEncryptedEndpoint() { @@ -109,12 +111,14 @@ namespace MQTTnet.Server return this; } +#if !WINDOWS_UWP public MqttServerOptionsBuilder WithRemoteCertificateValidationCallback(RemoteCertificateValidationCallback value) { _options.TlsEndpointOptions.RemoteCertificateValidationCallback = value; return this; } - +#endif + public MqttServerOptionsBuilder WithStorage(IMqttServerStorage value) { _options.Storage = value; diff --git a/Source/MQTTnet/Server/MqttServerTcpEndpointBaseOptions.cs b/Source/MQTTnet/Server/MqttServerTcpEndpointBaseOptions.cs index 29776aa..7f305fe 100644 --- a/Source/MQTTnet/Server/MqttServerTcpEndpointBaseOptions.cs +++ b/Source/MQTTnet/Server/MqttServerTcpEndpointBaseOptions.cs @@ -12,6 +12,10 @@ namespace MQTTnet.Server public bool NoDelay { get; set; } = true; +#if WINDOWS_UWP + public int BufferSize { get; set; } = 4096; +#endif + public IPAddress BoundInterNetworkAddress { get; set; } = IPAddress.Any; public IPAddress BoundInterNetworkV6Address { get; set; } = IPAddress.IPv6Any; diff --git a/Source/MQTTnet/Server/MqttServerTlsTcpEndpointOptions.cs b/Source/MQTTnet/Server/MqttServerTlsTcpEndpointOptions.cs index c9c7791..9bf325b 100644 --- a/Source/MQTTnet/Server/MqttServerTlsTcpEndpointOptions.cs +++ b/Source/MQTTnet/Server/MqttServerTlsTcpEndpointOptions.cs @@ -17,8 +17,10 @@ namespace MQTTnet.Server public bool ClientCertificateRequired { get; set; } public bool CheckCertificateRevocation { get; set; } - public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; } +#if !WINDOWS_UWP + public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; } +#endif public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12; } } diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index 13085b5..94abc41 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -653,7 +653,18 @@ namespace MQTTnet.TestApp.UniversalWindows } // ---------------------------------- - + + // For UWP apps: + MqttTcpChannel.CustomIgnorableServerCertificateErrorsResolver = o => + { + if (o.Server == "server_with_revoked_cert") + { + return new[] { ChainValidationResult.Revoked }; + } + + return new ChainValidationResult[0]; + }; + { // Start a MQTT server. var mqttServer = new MqttFactory().CreateMqttServer(); From 0cfb8b402076c9dbd5c511757fdb47adb3431b59 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sun, 11 Aug 2019 22:25:05 +0200 Subject: [PATCH 07/17] Remove not async task handling. --- Source/MQTTnet/Formatter/MqttPacketReader.cs | 55 -------------------- 1 file changed, 55 deletions(-) diff --git a/Source/MQTTnet/Formatter/MqttPacketReader.cs b/Source/MQTTnet/Formatter/MqttPacketReader.cs index 2589c5b..61698a1 100644 --- a/Source/MQTTnet/Formatter/MqttPacketReader.cs +++ b/Source/MQTTnet/Formatter/MqttPacketReader.cs @@ -21,8 +21,6 @@ namespace MQTTnet.Formatter { // The MQTT fixed header contains 1 byte of flags and at least 1 byte for the remaining data length. // So in all cases at least 2 bytes must be read for a complete MQTT packet. - // async/await is used here because the next packet is received in a couple of minutes so the performance - // impact is acceptable according to a useless waiting thread. var buffer = fixedHeaderBuffer; var totalBytesRead = 0; @@ -55,16 +53,7 @@ namespace MQTTnet.Formatter }; } -#if WINDOWS_UWP - // UWP will have a dead lock when calling this not async. var bodyLength = await ReadBodyLengthAsync(buffer[1], cancellationToken).ConfigureAwait(false); -#else - // Here the async/await pattern is not used because the overhead of context switches - // is too big for reading 1 byte in a row. We expect that the remaining data was sent - // directly after the initial bytes. If the client disconnects just in this moment we - // will get an exception anyway. - var bodyLength = ReadBodyLength(buffer[1], cancellationToken); -#endif if (!bodyLength.HasValue) { @@ -81,49 +70,6 @@ namespace MQTTnet.Formatter }; } -#if !WINDOWS_UWP - private int? ReadBodyLength(byte initialEncodedByte, CancellationToken cancellationToken) - { - var offset = 0; - var multiplier = 128; - var value = initialEncodedByte & 127; - int encodedByte = initialEncodedByte; - - while ((encodedByte & 128) != 0) - { - offset++; - if (offset > 3) - { - throw new MqttProtocolViolationException("Remaining length is invalid."); - } - - if (cancellationToken.IsCancellationRequested) - { - return null; - } - - var readCount = _channel.ReadAsync(_singleByteBuffer, 0, 1, cancellationToken).GetAwaiter().GetResult(); - - if (cancellationToken.IsCancellationRequested) - { - return null; - } - - if (readCount == 0) - { - return null; - } - - encodedByte = _singleByteBuffer[0]; - - value += (encodedByte & 127) * multiplier; - multiplier *= 128; - } - - return value; - } -#else - private async Task ReadBodyLengthAsync(byte initialEncodedByte, CancellationToken cancellationToken) { var offset = 0; @@ -164,6 +110,5 @@ namespace MQTTnet.Formatter return value; } -#endif } } From d7948afd98f91db96c44543f0dd07c10bba66645 Mon Sep 17 00:00:00 2001 From: Craig Lutgen Date: Mon, 12 Aug 2019 17:34:05 -0500 Subject: [PATCH 08/17] Fix client SslStream certificate chain CRL validation. The logic was inverse and CRLs were never checked. Add a missing dispose in managed client. --- Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClient.cs | 1 + Source/MQTTnet/Implementations/MqttTcpChannel.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClient.cs b/Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClient.cs index f53a8dd..c9053e4 100644 --- a/Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClient.cs +++ b/Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClient.cs @@ -252,6 +252,7 @@ namespace MQTTnet.Extensions.ManagedClient _maintainConnectionTask = null; } + _messageQueueLock.Dispose(); _mqttClient.Dispose(); } diff --git a/Source/MQTTnet/Implementations/MqttTcpChannel.cs b/Source/MQTTnet/Implementations/MqttTcpChannel.cs index 12fd2bb..d7943ad 100644 --- a/Source/MQTTnet/Implementations/MqttTcpChannel.cs +++ b/Source/MQTTnet/Implementations/MqttTcpChannel.cs @@ -86,7 +86,7 @@ namespace MQTTnet.Implementations var sslStream = new SslStream(networkStream, false, InternalUserCertificateValidationCallback); _stream = sslStream; - await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), _options.TlsOptions.SslProtocol, _options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false); + await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), _options.TlsOptions.SslProtocol, !_options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false); } else { From 2e3cf54f11c9e01e69ebe90ef42a5d5a1cbec4a0 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 13 Aug 2019 19:53:55 +0200 Subject: [PATCH 09/17] Add support for different strategies when generating RPC topics. --- .../MQTTnet.Extensions.Rpc/MqttRpcClient.cs | 33 +++++++++++++++++-- .../Options/IMqttRpcClientOptions.cs | 9 +++++ .../Options/MqttRpcClientOptions.cs | 9 +++++ .../Options/MqttRpcClientOptionsBuilder.cs | 25 ++++++++++++++ .../Options/MqttRpcTopicPair.cs | 9 +++++ ...ultMqttRpcClientTopicGenerationStrategy.cs | 20 +++++++++++ .../IMqttRpcClientTopicGenerationStrategy.cs | 7 ++++ .../TopicGeneration/TopicGenerationContext.cs | 16 +++++++++ Tests/MQTTnet.Core.Tests/RPC_Tests.cs | 33 +++++++++++++++++-- 9 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 Source/MQTTnet.Extensions.Rpc/Options/IMqttRpcClientOptions.cs create mode 100644 Source/MQTTnet.Extensions.Rpc/Options/MqttRpcClientOptions.cs create mode 100644 Source/MQTTnet.Extensions.Rpc/Options/MqttRpcClientOptionsBuilder.cs create mode 100644 Source/MQTTnet.Extensions.Rpc/Options/MqttRpcTopicPair.cs create mode 100644 Source/MQTTnet.Extensions.Rpc/Options/TopicGeneration/DefaultMqttRpcClientTopicGenerationStrategy.cs create mode 100644 Source/MQTTnet.Extensions.Rpc/Options/TopicGeneration/IMqttRpcClientTopicGenerationStrategy.cs create mode 100644 Source/MQTTnet.Extensions.Rpc/Options/TopicGeneration/TopicGenerationContext.cs diff --git a/Source/MQTTnet.Extensions.Rpc/MqttRpcClient.cs b/Source/MQTTnet.Extensions.Rpc/MqttRpcClient.cs index c025bdf..8696f83 100644 --- a/Source/MQTTnet.Extensions.Rpc/MqttRpcClient.cs +++ b/Source/MQTTnet.Extensions.Rpc/MqttRpcClient.cs @@ -5,6 +5,8 @@ using System.Threading; using System.Threading.Tasks; using MQTTnet.Client; using MQTTnet.Exceptions; +using MQTTnet.Extensions.Rpc.Options; +using MQTTnet.Extensions.Rpc.Options.TopicGeneration; using MQTTnet.Protocol; namespace MQTTnet.Extensions.Rpc @@ -13,11 +15,18 @@ namespace MQTTnet.Extensions.Rpc { private readonly ConcurrentDictionary> _waitingCalls = new ConcurrentDictionary>(); private readonly IMqttClient _mqttClient; + private readonly IMqttRpcClientOptions _options; private readonly RpcAwareApplicationMessageReceivedHandler _applicationMessageReceivedHandler; - public MqttRpcClient(IMqttClient mqttClient) + [Obsolete("Use MqttRpcClient(IMqttClient mqttClient, IMqttRpcClientOptions options).")] + public MqttRpcClient(IMqttClient mqttClient) : this(mqttClient, new MqttRpcClientOptions()) + { + } + + public MqttRpcClient(IMqttClient mqttClient, IMqttRpcClientOptions options) { _mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient)); + _options = options ?? throw new ArgumentNullException(nameof(options)); _applicationMessageReceivedHandler = new RpcAwareApplicationMessageReceivedHandler( mqttClient.ApplicationMessageReceivedHandler, @@ -55,8 +64,26 @@ namespace MQTTnet.Extensions.Rpc throw new InvalidOperationException("The application message received handler was modified."); } - var requestTopic = $"MQTTnet.RPC/{Guid.NewGuid():N}/{methodName}"; - var responseTopic = requestTopic + "/response"; + var topicNames = _options.TopicGenerationStrategy.CreateRpcTopics(new TopicGenerationContext + { + MethodName = methodName, + QualityOfServiceLevel = qualityOfServiceLevel, + MqttClient = _mqttClient, + Options = _options + }); + + var requestTopic = topicNames.RequestTopic; + var responseTopic = topicNames.ResponseTopic; + + if (string.IsNullOrWhiteSpace(requestTopic)) + { + throw new MqttProtocolViolationException("RPC request topic is empty."); + } + + if (string.IsNullOrWhiteSpace(responseTopic)) + { + throw new MqttProtocolViolationException("RPC response topic is empty."); + } var requestMessage = new MqttApplicationMessageBuilder() .WithTopic(requestTopic) diff --git a/Source/MQTTnet.Extensions.Rpc/Options/IMqttRpcClientOptions.cs b/Source/MQTTnet.Extensions.Rpc/Options/IMqttRpcClientOptions.cs new file mode 100644 index 0000000..6b7afa9 --- /dev/null +++ b/Source/MQTTnet.Extensions.Rpc/Options/IMqttRpcClientOptions.cs @@ -0,0 +1,9 @@ +using MQTTnet.Extensions.Rpc.Options.TopicGeneration; + +namespace MQTTnet.Extensions.Rpc.Options +{ + public interface IMqttRpcClientOptions + { + IMqttRpcClientTopicGenerationStrategy TopicGenerationStrategy { get; set; } + } +} \ No newline at end of file diff --git a/Source/MQTTnet.Extensions.Rpc/Options/MqttRpcClientOptions.cs b/Source/MQTTnet.Extensions.Rpc/Options/MqttRpcClientOptions.cs new file mode 100644 index 0000000..0dc4517 --- /dev/null +++ b/Source/MQTTnet.Extensions.Rpc/Options/MqttRpcClientOptions.cs @@ -0,0 +1,9 @@ +using MQTTnet.Extensions.Rpc.Options.TopicGeneration; + +namespace MQTTnet.Extensions.Rpc.Options +{ + public class MqttRpcClientOptions : IMqttRpcClientOptions + { + public IMqttRpcClientTopicGenerationStrategy TopicGenerationStrategy { get; set; } = new DefaultMqttRpcClientTopicGenerationStrategy(); + } +} diff --git a/Source/MQTTnet.Extensions.Rpc/Options/MqttRpcClientOptionsBuilder.cs b/Source/MQTTnet.Extensions.Rpc/Options/MqttRpcClientOptionsBuilder.cs new file mode 100644 index 0000000..69277ac --- /dev/null +++ b/Source/MQTTnet.Extensions.Rpc/Options/MqttRpcClientOptionsBuilder.cs @@ -0,0 +1,25 @@ +using MQTTnet.Extensions.Rpc.Options.TopicGeneration; +using System; + +namespace MQTTnet.Extensions.Rpc.Options +{ + public class MqttRpcClientOptionsBuilder + { + IMqttRpcClientTopicGenerationStrategy _topicGenerationStrategy = new DefaultMqttRpcClientTopicGenerationStrategy(); + + public MqttRpcClientOptionsBuilder WithTopicGenerationStrategy(IMqttRpcClientTopicGenerationStrategy value) + { + _topicGenerationStrategy = value ?? throw new ArgumentNullException(nameof(value)); + + return this; + } + + public IMqttRpcClientOptions Build() + { + return new MqttRpcClientOptions + { + TopicGenerationStrategy = _topicGenerationStrategy + }; + } + } +} diff --git a/Source/MQTTnet.Extensions.Rpc/Options/MqttRpcTopicPair.cs b/Source/MQTTnet.Extensions.Rpc/Options/MqttRpcTopicPair.cs new file mode 100644 index 0000000..12bccce --- /dev/null +++ b/Source/MQTTnet.Extensions.Rpc/Options/MqttRpcTopicPair.cs @@ -0,0 +1,9 @@ +namespace MQTTnet.Extensions.Rpc.Options +{ + public class MqttRpcTopicPair + { + public string RequestTopic { get; set; } + + public string ResponseTopic { get; set; } + } +} diff --git a/Source/MQTTnet.Extensions.Rpc/Options/TopicGeneration/DefaultMqttRpcClientTopicGenerationStrategy.cs b/Source/MQTTnet.Extensions.Rpc/Options/TopicGeneration/DefaultMqttRpcClientTopicGenerationStrategy.cs new file mode 100644 index 0000000..d38aa0b --- /dev/null +++ b/Source/MQTTnet.Extensions.Rpc/Options/TopicGeneration/DefaultMqttRpcClientTopicGenerationStrategy.cs @@ -0,0 +1,20 @@ +using MQTTnet.Extensions.Rpc.Options.TopicGeneration; +using System; + +namespace MQTTnet.Extensions.Rpc.Options +{ + public class DefaultMqttRpcClientTopicGenerationStrategy : IMqttRpcClientTopicGenerationStrategy + { + public MqttRpcTopicPair CreateRpcTopics(TopicGenerationContext context) + { + var requestTopic = $"MQTTnet.RPC/{Guid.NewGuid():N}/{context.MethodName}"; + var responseTopic = requestTopic + "/response"; + + return new MqttRpcTopicPair + { + RequestTopic = requestTopic, + ResponseTopic = responseTopic + }; + } + } +} diff --git a/Source/MQTTnet.Extensions.Rpc/Options/TopicGeneration/IMqttRpcClientTopicGenerationStrategy.cs b/Source/MQTTnet.Extensions.Rpc/Options/TopicGeneration/IMqttRpcClientTopicGenerationStrategy.cs new file mode 100644 index 0000000..19c78d3 --- /dev/null +++ b/Source/MQTTnet.Extensions.Rpc/Options/TopicGeneration/IMqttRpcClientTopicGenerationStrategy.cs @@ -0,0 +1,7 @@ +namespace MQTTnet.Extensions.Rpc.Options.TopicGeneration +{ + public interface IMqttRpcClientTopicGenerationStrategy + { + MqttRpcTopicPair CreateRpcTopics(TopicGenerationContext context); + } +} diff --git a/Source/MQTTnet.Extensions.Rpc/Options/TopicGeneration/TopicGenerationContext.cs b/Source/MQTTnet.Extensions.Rpc/Options/TopicGeneration/TopicGenerationContext.cs new file mode 100644 index 0000000..dc7263f --- /dev/null +++ b/Source/MQTTnet.Extensions.Rpc/Options/TopicGeneration/TopicGenerationContext.cs @@ -0,0 +1,16 @@ +using MQTTnet.Client; +using MQTTnet.Protocol; + +namespace MQTTnet.Extensions.Rpc.Options.TopicGeneration +{ + public class TopicGenerationContext + { + public string MethodName { get; set; } + + public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; } + + public IMqttClient MqttClient { get; set; } + + public IMqttRpcClientOptions Options { get; set; } + } +} diff --git a/Tests/MQTTnet.Core.Tests/RPC_Tests.cs b/Tests/MQTTnet.Core.Tests/RPC_Tests.cs index 9f03172..a420697 100644 --- a/Tests/MQTTnet.Core.Tests/RPC_Tests.cs +++ b/Tests/MQTTnet.Core.Tests/RPC_Tests.cs @@ -10,6 +10,8 @@ using MQTTnet.Extensions.Rpc; using MQTTnet.Protocol; using MQTTnet.Client.Options; using MQTTnet.Formatter; +using MQTTnet.Extensions.Rpc.Options; +using MQTTnet.Extensions.Rpc.Options.TopicGeneration; namespace MQTTnet.Tests { @@ -62,7 +64,22 @@ namespace MQTTnet.Tests var requestSender = await testEnvironment.ConnectClientAsync(); - var rpcClient = new MqttRpcClient(requestSender); + var rpcClient = new MqttRpcClient(requestSender, new MqttRpcClientOptionsBuilder().Build()); + await rpcClient.ExecuteAsync(TimeSpan.FromSeconds(2), "ping", "", MqttQualityOfServiceLevel.AtMostOnce); + } + } + + [TestMethod] + [ExpectedException(typeof(MqttCommunicationTimedOutException))] + public async Task Execute_With_Custom_Topic_Names() + { + using (var testEnvironment = new TestEnvironment()) + { + await testEnvironment.StartServerAsync(); + + var requestSender = await testEnvironment.ConnectClientAsync(); + + var rpcClient = new MqttRpcClient(requestSender, new MqttRpcClientOptionsBuilder().WithTopicGenerationStrategy(new TestTopicStrategy()) .Build()); await rpcClient.ExecuteAsync(TimeSpan.FromSeconds(2), "ping", "", MqttQualityOfServiceLevel.AtMostOnce); } } @@ -82,11 +99,23 @@ namespace MQTTnet.Tests var requestSender = await testEnvironment.ConnectClientAsync(); - var rpcClient = new MqttRpcClient(requestSender); + var rpcClient = new MqttRpcClient(requestSender, new MqttRpcClientOptionsBuilder().Build()); var response = await rpcClient.ExecuteAsync(TimeSpan.FromSeconds(5), "ping", "", qosLevel); Assert.AreEqual("pong", Encoding.UTF8.GetString(response)); } } + + private class TestTopicStrategy : IMqttRpcClientTopicGenerationStrategy + { + public MqttRpcTopicPair CreateRpcTopics(TopicGenerationContext context) + { + return new MqttRpcTopicPair + { + RequestTopic = "a", + ResponseTopic = "b" + }; + } + } } } From b09f31d654a4cb1201e4736ff9113f8c112459d5 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 13 Aug 2019 20:07:10 +0200 Subject: [PATCH 10/17] Fix TCP server adpater when using empty password. --- .../Implementations/MqttTcpServerAdapter.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs b/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs index e3dcab8..d7f4e6f 100644 --- a/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs +++ b/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs @@ -41,14 +41,24 @@ namespace MQTTnet.Implementations RegisterListeners(options.DefaultEndpointOptions, null, _cancellationTokenSource.Token); } - if (options.TlsEndpointOptions.IsEnabled) + if (options.TlsEndpointOptions?.IsEnabled == true) { if (options.TlsEndpointOptions.Certificate == null) { throw new ArgumentException("TLS certificate is not set."); } - var tlsCertificate = new X509Certificate2(options.TlsEndpointOptions.Certificate, options.TlsEndpointOptions.CertificateCredentials.Password); + X509Certificate2 tlsCertificate; + if (string.IsNullOrEmpty(options.TlsEndpointOptions.CertificateCredentials?.Password)) + { + // Use a different overload when no password is specified. Otherwise the constructor will fail. + tlsCertificate = new X509Certificate2(options.TlsEndpointOptions.Certificate); + } + else + { + tlsCertificate = new X509Certificate2(options.TlsEndpointOptions.Certificate, options.TlsEndpointOptions.CertificateCredentials.Password); + } + if (!tlsCertificate.HasPrivateKey) { throw new InvalidOperationException("The certificate for TLS encryption must contain the private key."); From c0b4155ab48a258e8e769666caa5ec4ed9625734 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 13 Aug 2019 20:07:14 +0200 Subject: [PATCH 11/17] Update docs. --- Build/MQTTnet.nuspec | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 6aafdc6..4a23a7e 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -11,16 +11,10 @@ false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol. -* [Core] Nuget packages with symbols are now also published to improve debugging. -* [Core] Improve task handling (thanks to @mwinterb) -* [ManagedClient] Fix a race condition in the message storage (thanks to @PaulFake). -* [Server] Added items dictionary to client session in order to share data across interceptors as along as the session exists. -* [Server] Exposed CONNECT packet properties in Application Message and Subscription interceptor. -* [Server] Fixed: Sending Large packets with AspnetCore based connection throws System.ArgumentException. -* [Server] Fixed wrong usage of socket option _NoDelay_. -* [Server] Added remote certificate validation callback (thanks to @rudacs). -* [Server] Add support for certificate passwords (thanks to @cslutgen). -* [MQTTnet.Server] Added REST API for publishing basic messages. +* [Core] Converted all pending methods to use async/await. +* [Client] Fixed an issue when checking for revoked SSL certificates (thanks to @cslutgen). +* [Server] Fixed an issue with empty server certificate passwords (thanks to @SeppPenner). +* [MQTTnet.Server] Added support for certificate passwords (BREAKING CHANGE IN CONFIG!) Copyright Christian Kratky 2016-2019 MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin From 2320352124d37f4d00b2d2132bbedf8ac1865fef Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 13 Aug 2019 20:09:21 +0200 Subject: [PATCH 12/17] Update docs. --- Build/MQTTnet.nuspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 4a23a7e..5977775 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -13,6 +13,8 @@ * [Core] Converted all pending methods to use async/await. * [Client] Fixed an issue when checking for revoked SSL certificates (thanks to @cslutgen). +* [RpcClient] Added support for custom topic generation strategies. +* [Server] Refactoring of server certificate password classes (BREAKING CHANGE!). * [Server] Fixed an issue with empty server certificate passwords (thanks to @SeppPenner). * [MQTTnet.Server] Added support for certificate passwords (BREAKING CHANGE IN CONFIG!) From a4420063c031af3c86242e5d68a6de7225bfabaf Mon Sep 17 00:00:00 2001 From: JanEggers Date: Wed, 14 Aug 2019 22:29:51 +0200 Subject: [PATCH 13/17] fixed #743 --- Build/MQTTnet.nuspec | 1 + .../SpanBasedMqttPacketWriter.cs | 1 - .../MqttPacketSerializer_Tests.cs | 21 +++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 5977775..1e14f0d 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -17,6 +17,7 @@ * [Server] Refactoring of server certificate password classes (BREAKING CHANGE!). * [Server] Fixed an issue with empty server certificate passwords (thanks to @SeppPenner). * [MQTTnet.Server] Added support for certificate passwords (BREAKING CHANGE IN CONFIG!) +* [MQTTnet.AspNetCore] fixed an issue with mqtt V5 package serialization (#743) Copyright Christian Kratky 2016-2019 MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin diff --git a/Source/MQTTnet.AspnetCore/SpanBasedMqttPacketWriter.cs b/Source/MQTTnet.AspnetCore/SpanBasedMqttPacketWriter.cs index 27e13c4..66addfd 100644 --- a/Source/MQTTnet.AspnetCore/SpanBasedMqttPacketWriter.cs +++ b/Source/MQTTnet.AspnetCore/SpanBasedMqttPacketWriter.cs @@ -64,7 +64,6 @@ namespace MQTTnet.AspNetCore GrowIfNeeded(propertyWriter.Length); Write(propertyWriter.GetBuffer(), 0, propertyWriter.Length); - Commit(propertyWriter.Length); } public void Write(byte[] payload, int start, int length) diff --git a/Tests/MQTTnet.Core.Tests/MqttPacketSerializer_Tests.cs b/Tests/MQTTnet.Core.Tests/MqttPacketSerializer_Tests.cs index b67d2a2..a1f798a 100644 --- a/Tests/MQTTnet.Core.Tests/MqttPacketSerializer_Tests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttPacketSerializer_Tests.cs @@ -8,6 +8,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using MQTTnet.Adapter; using MQTTnet.Formatter; using MQTTnet.Formatter.V3; +using MQTTnet.Formatter.V5; using MQTTnet.Internal; using MQTTnet.Packets; using MQTTnet.Protocol; @@ -258,6 +259,26 @@ namespace MQTTnet.Tests Assert.IsTrue(deserialized.Properties.UserProperties.Any(x => x.Name == "Foo")); } + + [TestMethod] + public void SerializeV500_MqttPublishPacket_CorrelationData() + { + var data = "123456789"; + var req = new MqttApplicationMessageBuilder() + .WithTopic("Foo") + .WithResponseTopic($"_") + .WithCorrelationData(Guid.NewGuid().ToByteArray()) + .WithPayload(data) + .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce) + .Build(); + + var p = new MqttV500DataConverter().CreatePublishPacket(req); + + var deserialized = Roundtrip(p, MqttProtocolVersion.V500); + + Assert.IsTrue(p.Payload.SequenceEqual(deserialized.Payload)); + } + [TestMethod] public void DeserializeV311_MqttPublishPacket() { From 2767d897a4af9084dd95e258c1ef687e38650602 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Wed, 14 Aug 2019 22:45:15 +0200 Subject: [PATCH 14/17] Fix serialization issue of MQTTv5 PubRec packet. --- Source/MQTTnet/Formatter/IMqttPacketWriter.cs | 26 +++++++++++++------ .../Formatter/V5/MqttV500PacketEncoder.cs | 7 +++-- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Source/MQTTnet/Formatter/IMqttPacketWriter.cs b/Source/MQTTnet/Formatter/IMqttPacketWriter.cs index 5ea6ca3..bae6dec 100644 --- a/Source/MQTTnet/Formatter/IMqttPacketWriter.cs +++ b/Source/MQTTnet/Formatter/IMqttPacketWriter.cs @@ -5,15 +5,25 @@ int Length { get; } void WriteWithLengthPrefix(string value); - void Write(byte returnCode); - void WriteWithLengthPrefix(byte[] payload); - void Write(ushort keepAlivePeriod); - void Write(IMqttPacketWriter propertyWriter); - void WriteVariableLengthInteger(uint length); - void Write(byte[] payload, int v, int length); - void Reset(int v); - void Seek(int v); + + void Write(byte value); + + void WriteWithLengthPrefix(byte[] value); + + void Write(ushort value); + + void Write(IMqttPacketWriter value); + + void WriteVariableLengthInteger(uint value); + + void Write(byte[] value, int offset, int length); + + void Reset(int length); + + void Seek(int offset); + void FreeBuffer(); + byte[] GetBuffer(); } } diff --git a/Source/MQTTnet/Formatter/V5/MqttV500PacketEncoder.cs b/Source/MQTTnet/Formatter/V5/MqttV500PacketEncoder.cs index 23b7f1a..9ebc740 100644 --- a/Source/MQTTnet/Formatter/V5/MqttV500PacketEncoder.cs +++ b/Source/MQTTnet/Formatter/V5/MqttV500PacketEncoder.cs @@ -328,10 +328,7 @@ namespace MQTTnet.Formatter.V5 { ThrowReasonCodeNotSetException(); } - - packetWriter.Write(packet.PacketIdentifier.Value); - packetWriter.Write((byte)packet.ReasonCode.Value); - + var propertiesWriter = new MqttV500PropertiesWriter(); if (packet.Properties != null) { @@ -339,6 +336,8 @@ namespace MQTTnet.Formatter.V5 propertiesWriter.WriteUserProperties(packet.Properties.UserProperties); } + packetWriter.Write(packet.PacketIdentifier.Value); + if (packetWriter.Length > 0 || packet.ReasonCode.Value != MqttPubRecReasonCode.Success) { packetWriter.Write((byte)packet.ReasonCode.Value); From 4614df7fa56c871cf6de29bf502e8393c57caa65 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Wed, 14 Aug 2019 22:57:17 +0200 Subject: [PATCH 15/17] Update docs. --- Build/MQTTnet.nuspec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 1e14f0d..32b02ca 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -12,12 +12,13 @@ MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol. * [Core] Converted all pending methods to use async/await. +* [Core] Fixed an issue when serializing a PubRec (QoS 2) packet for MQTTv5. * [Client] Fixed an issue when checking for revoked SSL certificates (thanks to @cslutgen). * [RpcClient] Added support for custom topic generation strategies. * [Server] Refactoring of server certificate password classes (BREAKING CHANGE!). * [Server] Fixed an issue with empty server certificate passwords (thanks to @SeppPenner). * [MQTTnet.Server] Added support for certificate passwords (BREAKING CHANGE IN CONFIG!) -* [MQTTnet.AspNetCore] fixed an issue with mqtt V5 package serialization (#743) +* [MQTTnet.AspNetCore] Fixed an issue with MQTTv5 package serialization (#743, thanks to @JanEggers, @pcbing). Copyright Christian Kratky 2016-2019 MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin From 50d65f2feded729bb5e3d451d0e0f5e0a9587e96 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Wed, 14 Aug 2019 23:06:45 +0200 Subject: [PATCH 16/17] Update nugets. --- Tests/MQTTnet.AspNetCore.Tests/MQTTnet.AspNetCore.Tests.csproj | 2 +- Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/MQTTnet.AspNetCore.Tests/MQTTnet.AspNetCore.Tests.csproj b/Tests/MQTTnet.AspNetCore.Tests/MQTTnet.AspNetCore.Tests.csproj index 06f0e5f..a756dd1 100644 --- a/Tests/MQTTnet.AspNetCore.Tests/MQTTnet.AspNetCore.Tests.csproj +++ b/Tests/MQTTnet.AspNetCore.Tests/MQTTnet.AspNetCore.Tests.csproj @@ -7,7 +7,7 @@ - + diff --git a/Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj b/Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj index 74937a9..63bd0de 100644 --- a/Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj +++ b/Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj @@ -9,7 +9,7 @@ - + From cf6f0ece0e97931af4c12410dfa11ce7e234db0a Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sun, 18 Aug 2019 20:56:26 +0200 Subject: [PATCH 17/17] Add test execution in build script. --- Build/build.ps1 | 8 +++++++- .../MQTTnet.AspNetCore.Tests.csproj | 1 - Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj | 3 +-- .../MqttKeepAliveMonitor_Tests.cs | 14 +++++++------- Tests/MQTTnet.Core.Tests/Server_Tests.cs | 4 +++- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Build/build.ps1 b/Build/build.ps1 index 33f2767..57a60f6 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -43,8 +43,14 @@ Write-Host &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" &$msbuild ..\Source\MQTTnet.Extensions.WebSocket4Net\MQTTnet.Extensions.WebSocket4Net.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=".\..\..\Build\codeSigningKey.pfx" -# Create NuGet packages. +# Build and execute tests +&$msbuild ..\Tests\MQTTnet.Core.Tests\MQTTnet.Tests.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp2.1" /verbosity:m +&$msbuild ..\Tests\MQTTnet.AspNetCore.Tests\MQTTnet.AspNetCore.Tests.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netcoreapp2.1" /verbosity:m + +vstest.console.exe ..\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.1\MQTTnet.Tests.dll +vstest.console.exe ..\Tests\MQTTnet.AspNetCore.Tests\bin\Release\netcoreapp2.1\MQTTnet.AspNetCore.Tests.dll +# Create NuGet packages. Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile "nuget.exe" Remove-Item .\NuGet -Force -Recurse -ErrorAction SilentlyContinue diff --git a/Tests/MQTTnet.AspNetCore.Tests/MQTTnet.AspNetCore.Tests.csproj b/Tests/MQTTnet.AspNetCore.Tests/MQTTnet.AspNetCore.Tests.csproj index a756dd1..4569af3 100644 --- a/Tests/MQTTnet.AspNetCore.Tests/MQTTnet.AspNetCore.Tests.csproj +++ b/Tests/MQTTnet.AspNetCore.Tests/MQTTnet.AspNetCore.Tests.csproj @@ -2,7 +2,6 @@ netcoreapp2.1 - false diff --git a/Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj b/Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj index 63bd0de..830051d 100644 --- a/Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj +++ b/Tests/MQTTnet.Core.Tests/MQTTnet.Tests.csproj @@ -1,9 +1,8 @@  - Exe - Full netcoreapp2.1 + false diff --git a/Tests/MQTTnet.Core.Tests/MqttKeepAliveMonitor_Tests.cs b/Tests/MQTTnet.Core.Tests/MqttKeepAliveMonitor_Tests.cs index adf9a2b..fe1a0c5 100644 --- a/Tests/MQTTnet.Core.Tests/MqttKeepAliveMonitor_Tests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttKeepAliveMonitor_Tests.cs @@ -14,7 +14,7 @@ namespace MQTTnet.Tests public class MqttKeepAliveMonitor_Tests { [TestMethod] - public void KeepAlive_Timeout() + public async Task KeepAlive_Timeout() { var counter = 0; @@ -31,13 +31,13 @@ namespace MQTTnet.Tests Assert.AreEqual(0, counter); - Thread.Sleep(2000); // Internally the keep alive timeout is multiplied with 1.5 as per protocol specification. + await Task.Delay(2000); // Internally the keep alive timeout is multiplied with 1.5 as per protocol specification. Assert.AreEqual(1, counter); } [TestMethod] - public void KeepAlive_NoTimeout() + public async Task KeepAlive_NoTimeout() { var counter = 0; @@ -55,15 +55,15 @@ namespace MQTTnet.Tests Assert.AreEqual(0, counter); // Simulate traffic. - Thread.Sleep(1000); // Internally the keep alive timeout is multiplied with 1.5 as per protocol specification. + await Task.Delay(1000); // Internally the keep alive timeout is multiplied with 1.5 as per protocol specification. monitor.PacketReceived(); - Thread.Sleep(1000); + await Task.Delay(1000); monitor.PacketReceived(); - Thread.Sleep(1000); + await Task.Delay(1000); Assert.AreEqual(0, counter); - Thread.Sleep(2000); + await Task.Delay(2000); Assert.AreEqual(1, counter); } diff --git a/Tests/MQTTnet.Core.Tests/Server_Tests.cs b/Tests/MQTTnet.Core.Tests/Server_Tests.cs index d10ebaf..b2b3b70 100644 --- a/Tests/MQTTnet.Core.Tests/Server_Tests.cs +++ b/Tests/MQTTnet.Core.Tests/Server_Tests.cs @@ -1063,7 +1063,9 @@ namespace MQTTnet.Tests // forever. This is security related. var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); await client.ConnectAsync("localhost", testEnvironment.ServerPort); - await client.SendAsync(Encoding.UTF8.GetBytes("Garbage"), SocketFlags.None); + + var buffer = Encoding.UTF8.GetBytes("Garbage"); + client.Send(buffer, buffer.Length, SocketFlags.None); await Task.Delay(TimeSpan.FromSeconds(3));