From 49b1706495a523f7a5f014ac8ebe77e80f5244c0 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 23 Oct 2017 18:55:26 +0200 Subject: [PATCH 001/149] Set theme jekyll-theme-modernist --- _config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 _config.yml diff --git a/_config.yml b/_config.yml new file mode 100644 index 00000000..cc35c1df --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-modernist \ No newline at end of file From 2fe520ad46bce037cde27e407fb53d48992f0fd4 Mon Sep 17 00:00:00 2001 From: Jan Eggers Date: Mon, 30 Oct 2017 11:01:32 +0100 Subject: [PATCH 002/149] fix uwp platformtarget for release build --- .../MQTTnet.TestApp.UniversalWindows.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj index 42b16304..0d7e0394 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj @@ -166,7 +166,7 @@ ;2008 true pdbonly - AnyCPU + x86 false prompt MinimumRecommendedRules.ruleset From b51a603aa9f6fffe2428d5de0d6e39d8fa74ae14 Mon Sep 17 00:00:00 2001 From: JanEggers Date: Mon, 30 Oct 2017 11:06:26 +0100 Subject: [PATCH 003/149] Update appveyor.yml --- appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 97816dd1..532d22a6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,6 @@ version: 1.0.{build} image: Visual Studio 2017 +configuration: Release before_build: - cmd: >- msbuild /t:restore @@ -12,4 +13,4 @@ build: project: MQTTnet.sln verbosity: minimal test_script: -- cmd: vstest.console /logger:Appveyor Tests/MQTTnet.Core.Tests/bin/Release/net461/MQTTnet.Core.Tests.dll +- cmd: vstest.console /logger:Appveyor Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.0\MQTTnet.Core.Tests.dll From 98cac153e6803fb3841423dd9156a6e010cb8b5a Mon Sep 17 00:00:00 2001 From: JanEggers Date: Mon, 30 Oct 2017 11:13:20 +0100 Subject: [PATCH 004/149] Update appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 532d22a6..204ed14c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,4 +13,4 @@ build: project: MQTTnet.sln verbosity: minimal test_script: -- cmd: vstest.console /logger:Appveyor Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.0\MQTTnet.Core.Tests.dll +- cmd: vstest.console /logger:Appveyor "%APPVEYOR_BUILD_FOLDER%\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.0\MQTTnet.Core.Tests.dll" From 5e74869dbc400ea3bd74d8d3682241c9a78e9429 Mon Sep 17 00:00:00 2001 From: Jan Eggers Date: Mon, 30 Oct 2017 11:23:18 +0100 Subject: [PATCH 005/149] updated testadapter --- Tests/MQTTnet.Core.Tests/MQTTnet.Core.Tests.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/MQTTnet.Core.Tests/MQTTnet.Core.Tests.csproj b/Tests/MQTTnet.Core.Tests/MQTTnet.Core.Tests.csproj index 7ba48954..802d96d8 100644 --- a/Tests/MQTTnet.Core.Tests/MQTTnet.Core.Tests.csproj +++ b/Tests/MQTTnet.Core.Tests/MQTTnet.Core.Tests.csproj @@ -8,8 +8,8 @@ - - + + From fcd3bdf297062a701390ce7ddfe53cc6f7f94c12 Mon Sep 17 00:00:00 2001 From: JanEggers Date: Mon, 30 Oct 2017 11:28:10 +0100 Subject: [PATCH 006/149] Update appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 204ed14c..f91bf99c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,4 +13,4 @@ build: project: MQTTnet.sln verbosity: minimal test_script: -- cmd: vstest.console /logger:Appveyor "%APPVEYOR_BUILD_FOLDER%\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.0\MQTTnet.Core.Tests.dll" +- cmd: vstest.console /logger:Appveyor "%APPVEYOR_BUILD_FOLDER%\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.0\MQTTnet.Core.Tests.dll" /ListDiscoverers From 44ae9093f9feff129631f91ed4017d784e09c580 Mon Sep 17 00:00:00 2001 From: JanEggers Date: Mon, 30 Oct 2017 11:31:20 +0100 Subject: [PATCH 007/149] Update appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index f91bf99c..43a852bc 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,4 +13,4 @@ build: project: MQTTnet.sln verbosity: minimal test_script: -- cmd: vstest.console /logger:Appveyor "%APPVEYOR_BUILD_FOLDER%\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.0\MQTTnet.Core.Tests.dll" /ListDiscoverers +- cmd: vstest.console /logger:Appveyor "%APPVEYOR_BUILD_FOLDER%\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.0\MQTTnet.Core.Tests.dll" /UseVsixExtensions:true From e969b2f31f23416e557819dde9a49fba14fa0118 Mon Sep 17 00:00:00 2001 From: JanEggers Date: Mon, 30 Oct 2017 12:33:59 +0100 Subject: [PATCH 008/149] Update appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 43a852bc..35a75aa0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,4 +13,4 @@ build: project: MQTTnet.sln verbosity: minimal test_script: -- cmd: vstest.console /logger:Appveyor "%APPVEYOR_BUILD_FOLDER%\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.0\MQTTnet.Core.Tests.dll" /UseVsixExtensions:true +- cmd: dotnet vstest /logger:Appveyor "%APPVEYOR_BUILD_FOLDER%\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.0\MQTTnet.Core.Tests.dll" /UseVsixExtensions:true From 4519c4fe3d7955387c0fc014e88aaf6251b56dd2 Mon Sep 17 00:00:00 2001 From: JanEggers Date: Mon, 30 Oct 2017 12:36:27 +0100 Subject: [PATCH 009/149] Update appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 35a75aa0..fbfc84a2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,4 +13,4 @@ build: project: MQTTnet.sln verbosity: minimal test_script: -- cmd: dotnet vstest /logger:Appveyor "%APPVEYOR_BUILD_FOLDER%\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.0\MQTTnet.Core.Tests.dll" /UseVsixExtensions:true +- cmd: dotnet vstest /logger:Appveyor "%APPVEYOR_BUILD_FOLDER%\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.0\MQTTnet.Core.Tests.dll" From 6240d6000339bd31f5ae32b885f41a938ff3839e Mon Sep 17 00:00:00 2001 From: JanEggers Date: Mon, 30 Oct 2017 12:41:40 +0100 Subject: [PATCH 010/149] Update appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index fbfc84a2..253e07d9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,4 +13,4 @@ build: project: MQTTnet.sln verbosity: minimal test_script: -- cmd: dotnet vstest /logger:Appveyor "%APPVEYOR_BUILD_FOLDER%\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.0\MQTTnet.Core.Tests.dll" +- cmd: dotnet vstest "%APPVEYOR_BUILD_FOLDER%\Tests\MQTTnet.Core.Tests\bin\Release\netcoreapp2.0\MQTTnet.Core.Tests.dll" From 83821453a0d51109562ca99b5ce93848be59b8eb Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Mon, 30 Oct 2017 19:44:24 +0100 Subject: [PATCH 011/149] Refactor shared library. Extend error messages --- .gitignore | 2 +- .../MqttWebSocketServerAdapter.cs | 2 +- ...verAdapter.cs => MqttServerAdapter.Uwp.cs} | 19 +++++++++-------- .../{NetStandard => }/MqttServerAdapter.cs | 11 +++++----- ...qttTcpChannel.cs => MqttTcpChannel.Uwp.cs} | 3 +-- .../{NetStandard => }/MqttTcpChannel.cs | 0 .../Implementations/MqttWebSocketChannel.cs | 2 +- Frameworks/MQTTnet.NetStandard/MqttFactory.cs | 8 +++---- .../IMqttCommunicationAdapterFactory.cs | 4 ++-- MQTTnet.Core/Client/MqttClient.cs | 2 +- MQTTnet.Core/Serializer/MqttPacketReader.cs | 20 ++++++++++++++---- .../MqttCommunicationAdapterFactory.cs | 4 ++-- .../MQTTnet.TestApp.UniversalWindows.csproj | 2 +- ....TestApp.UniversalWindows_TemporaryKey.pfx | Bin 0 -> 2504 bytes .../MainPage.xaml | 4 +++- .../MainPage.xaml.cs | 3 +++ .../Package.appxmanifest | 4 ++-- 17 files changed, 53 insertions(+), 37 deletions(-) rename Frameworks/MQTTnet.NetStandard/Implementations/{Uap/MqttServerAdapter.cs => MqttServerAdapter.Uwp.cs} (78%) rename Frameworks/MQTTnet.NetStandard/Implementations/{NetStandard => }/MqttServerAdapter.cs (90%) rename Frameworks/MQTTnet.NetStandard/Implementations/{Uap/MqttTcpChannel.cs => MqttTcpChannel.Uwp.cs} (99%) rename Frameworks/MQTTnet.NetStandard/Implementations/{NetStandard => }/MqttTcpChannel.cs (100%) create mode 100644 Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows_TemporaryKey.pfx diff --git a/.gitignore b/.gitignore index 39550dc5..4372f8ed 100644 --- a/.gitignore +++ b/.gitignore @@ -197,7 +197,7 @@ ClientBin/ *.dbmdl *.dbproj.schemaview *.jfm -*.pfx +# *.pfx *.publishsettings orleans.codegen.cs diff --git a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs index 5cd5d555..45bf5457 100644 --- a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs +++ b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs @@ -36,7 +36,7 @@ namespace MQTTnet.AspNetCore if (webSocket == null) throw new ArgumentNullException(nameof(webSocket)); var channel = new MqttWebSocketServerChannel(webSocket); - var clientAdapter = _mqttCommunicationAdapterFactory.CreateServerMqttCommunicationAdapter(channel); + var clientAdapter = _mqttCommunicationAdapterFactory.CreateServerCommunicationAdapter(channel); var eventArgs = new MqttServerAdapterClientAcceptedEventArgs(clientAdapter); ClientAccepted?.Invoke(this, eventArgs); diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/Uap/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs similarity index 78% rename from Frameworks/MQTTnet.NetStandard/Implementations/Uap/MqttServerAdapter.cs rename to Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs index 7d9d25f1..658cfe83 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/Uap/MqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs @@ -1,5 +1,4 @@ -#if NET451 || NETSTANDARD1_3 -#else +#if WINDOWS_UWP using System; using System.Threading.Tasks; using MQTTnet.Core.Adapter; @@ -12,13 +11,13 @@ namespace MQTTnet.Implementations public class MqttServerAdapter : IMqttServerAdapter, IDisposable { private readonly ILogger _logger; - private readonly IMqttCommunicationAdapterFactory _mqttCommunicationAdapterFactory; + private readonly IMqttCommunicationAdapterFactory _communicationAdapterFactory; private StreamSocketListener _defaultEndpointSocket; - public MqttServerAdapter(ILogger logger, IMqttCommunicationAdapterFactory mqttCommunicationAdapterFactory) + public MqttServerAdapter(ILogger logger, IMqttCommunicationAdapterFactory communicationAdapterFactory) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _mqttCommunicationAdapterFactory = mqttCommunicationAdapterFactory ?? throw new ArgumentNullException(nameof(mqttCommunicationAdapterFactory)); + _communicationAdapterFactory = communicationAdapterFactory ?? throw new ArgumentNullException(nameof(communicationAdapterFactory)); } public event EventHandler ClientAccepted; @@ -32,7 +31,6 @@ namespace MQTTnet.Implementations if (options.DefaultEndpointOptions.IsEnabled) { _defaultEndpointSocket = new StreamSocketListener(); - _defaultEndpointSocket.Control.NoDelay = true; await _defaultEndpointSocket.BindServiceNameAsync(options.GetDefaultEndpointPort().ToString(), SocketProtectionLevel.PlainSocket); _defaultEndpointSocket.ConnectionReceived += AcceptDefaultEndpointConnectionsAsync; } @@ -45,6 +43,11 @@ namespace MQTTnet.Implementations public Task StopAsync() { + if (_defaultEndpointSocket != null) + { + _defaultEndpointSocket.ConnectionReceived -= AcceptDefaultEndpointConnectionsAsync; + } + _defaultEndpointSocket?.Dispose(); _defaultEndpointSocket = null; @@ -60,9 +63,7 @@ namespace MQTTnet.Implementations { try { - args.Socket.Control.NoDelay = true; - - var clientAdapter = _mqttCommunicationAdapterFactory.CreateServerMqttCommunicationAdapter(new MqttTcpChannel(args.Socket)); + var clientAdapter = _communicationAdapterFactory.CreateServerCommunicationAdapter(new MqttTcpChannel(args.Socket)); ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); } catch (Exception exception) diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/NetStandard/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs similarity index 90% rename from Frameworks/MQTTnet.NetStandard/Implementations/NetStandard/MqttServerAdapter.cs rename to Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs index 1a6e5b40..9d807b8b 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/NetStandard/MqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs @@ -1,5 +1,4 @@ #if NET451 || NETSTANDARD1_3 - using System; using System.Net; using System.Net.Security; @@ -17,17 +16,17 @@ namespace MQTTnet.Implementations public class MqttServerAdapter : IMqttServerAdapter, IDisposable { private readonly ILogger _logger; - private readonly IMqttCommunicationAdapterFactory _mqttCommunicationAdapterFactory; + private readonly IMqttCommunicationAdapterFactory _communicationAdapterFactory; private CancellationTokenSource _cancellationTokenSource; private Socket _defaultEndpointSocket; private Socket _tlsEndpointSocket; private X509Certificate2 _tlsCertificate; - public MqttServerAdapter(ILogger logger, IMqttCommunicationAdapterFactory mqttCommunicationAdapterFactory) + public MqttServerAdapter(ILogger logger, IMqttCommunicationAdapterFactory communicationAdapterFactory) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _mqttCommunicationAdapterFactory = mqttCommunicationAdapterFactory ?? throw new ArgumentNullException(nameof(mqttCommunicationAdapterFactory)); + _communicationAdapterFactory = communicationAdapterFactory ?? throw new ArgumentNullException(nameof(communicationAdapterFactory)); } public event EventHandler ClientAccepted; @@ -104,7 +103,7 @@ namespace MQTTnet.Implementations #else var clientSocket = await _defaultEndpointSocket.AcceptAsync().ConfigureAwait(false); #endif - var clientAdapter = _mqttCommunicationAdapterFactory.CreateServerMqttCommunicationAdapter(new MqttTcpChannel(clientSocket, null)); + var clientAdapter = _communicationAdapterFactory.CreateServerCommunicationAdapter(new MqttTcpChannel(clientSocket, null)); ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); } catch (Exception exception) @@ -132,7 +131,7 @@ namespace MQTTnet.Implementations var sslStream = new SslStream(new NetworkStream(clientSocket)); await sslStream.AuthenticateAsServerAsync(_tlsCertificate, false, SslProtocols.Tls12, false).ConfigureAwait(false); - var clientAdapter = _mqttCommunicationAdapterFactory.CreateServerMqttCommunicationAdapter(new MqttTcpChannel(clientSocket, sslStream)); + var clientAdapter = _communicationAdapterFactory.CreateServerCommunicationAdapter(new MqttTcpChannel(clientSocket, sslStream)); ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); } catch (Exception exception) diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/Uap/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs similarity index 99% rename from Frameworks/MQTTnet.NetStandard/Implementations/Uap/MqttTcpChannel.cs rename to Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs index 6e311d67..bd0614f5 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/Uap/MqttTcpChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs @@ -1,5 +1,4 @@ -#if NET451 || NETSTANDARD1_3 -#else +#if WINDOWS_UWP using System; using System.Collections.Generic; using System.IO; diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/NetStandard/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs similarity index 100% rename from Frameworks/MQTTnet.NetStandard/Implementations/NetStandard/MqttTcpChannel.cs rename to Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs index c120775b..1314a1c3 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs @@ -63,7 +63,7 @@ namespace MQTTnet.Implementations } } - await _webSocket.ConnectAsync(new Uri(uri), CancellationToken.None); + await _webSocket.ConnectAsync(new Uri(uri), CancellationToken.None).ConfigureAwait(false); RawReceiveStream = new WebSocketStream(_webSocket); } diff --git a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs index 50cdddea..432a3719 100644 --- a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs @@ -45,20 +45,20 @@ namespace MQTTnet return _serviceProvider.GetRequiredService(); } - public IMqttCommunicationAdapter CreateClientMqttCommunicationAdapter(IMqttClientOptions options) + public IMqttCommunicationAdapter CreateClientCommunicationAdapter(IMqttClientOptions options) { var logger = _serviceProvider.GetRequiredService>(); - return new MqttChannelCommunicationAdapter(CreateMqttCommunicationChannel(options.ChannelOptions), CreateSerializer(options.ProtocolVersion), logger); + return new MqttChannelCommunicationAdapter(CreateCommunicationChannel(options.ChannelOptions), CreateSerializer(options.ProtocolVersion), logger); } - public IMqttCommunicationAdapter CreateServerMqttCommunicationAdapter(IMqttCommunicationChannel channel) + public IMqttCommunicationAdapter CreateServerCommunicationAdapter(IMqttCommunicationChannel channel) { var serializer = _serviceProvider.GetRequiredService(); var logger = _serviceProvider.GetRequiredService>(); return new MqttChannelCommunicationAdapter(channel, serializer, logger); } - public IMqttCommunicationChannel CreateMqttCommunicationChannel(IMqttClientChannelOptions options) + public IMqttCommunicationChannel CreateCommunicationChannel(IMqttClientChannelOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); diff --git a/MQTTnet.Core/Adapter/IMqttCommunicationAdapterFactory.cs b/MQTTnet.Core/Adapter/IMqttCommunicationAdapterFactory.cs index ffcfd2c1..96098812 100644 --- a/MQTTnet.Core/Adapter/IMqttCommunicationAdapterFactory.cs +++ b/MQTTnet.Core/Adapter/IMqttCommunicationAdapterFactory.cs @@ -5,8 +5,8 @@ namespace MQTTnet.Core.Adapter { public interface IMqttCommunicationAdapterFactory { - IMqttCommunicationAdapter CreateClientMqttCommunicationAdapter(IMqttClientOptions options); + IMqttCommunicationAdapter CreateClientCommunicationAdapter(IMqttClientOptions options); - IMqttCommunicationAdapter CreateServerMqttCommunicationAdapter(IMqttCommunicationChannel channel); + IMqttCommunicationAdapter CreateServerCommunicationAdapter(IMqttCommunicationChannel channel); } } \ No newline at end of file diff --git a/MQTTnet.Core/Client/MqttClient.cs b/MQTTnet.Core/Client/MqttClient.cs index d16575b4..a8e4eba9 100644 --- a/MQTTnet.Core/Client/MqttClient.cs +++ b/MQTTnet.Core/Client/MqttClient.cs @@ -53,7 +53,7 @@ namespace MQTTnet.Core.Client _latestPacketIdentifier = 0; _packetDispatcher.Reset(); - _adapter = _communicationAdapterFactory.CreateClientMqttCommunicationAdapter(options); + _adapter = _communicationAdapterFactory.CreateClientCommunicationAdapter(options); _scopeHandle = _logger.BeginScope(options.LogId ?? options.ClientId); _logger.LogTrace("Trying to connect with server."); diff --git a/MQTTnet.Core/Serializer/MqttPacketReader.cs b/MQTTnet.Core/Serializer/MqttPacketReader.cs index 417c19a8..ce80cd50 100644 --- a/MQTTnet.Core/Serializer/MqttPacketReader.cs +++ b/MQTTnet.Core/Serializer/MqttPacketReader.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; @@ -13,7 +14,7 @@ namespace MQTTnet.Core.Serializer public sealed class MqttPacketReader : BinaryReader { private readonly ReceivedMqttPacket _receivedMqttPacket; - + public MqttPacketReader(ReceivedMqttPacket receivedMqttPacket) : base(receivedMqttPacket.Body, Encoding.UTF8, true) { @@ -70,6 +71,8 @@ namespace MQTTnet.Core.Serializer var multiplier = 1; var value = 0; byte encodedByte; + + var readBytes = new List(); do { if (cancellationToken.IsCancellationRequested) @@ -77,14 +80,23 @@ namespace MQTTnet.Core.Serializer throw new TaskCanceledException(); } - encodedByte = (byte)stream.ReadByte(); - value += (encodedByte & 127) * multiplier; + var buffer = stream.ReadByte(); + readBytes.Add(buffer); + + ////if (buffer == -1) + ////{ + //// break; + ////} + + encodedByte = (byte)buffer; + value += (byte)(encodedByte & 127) * multiplier; multiplier *= 128; if (multiplier > 128 * 128 * 128) { - throw new MqttProtocolViolationException("Remaining length is invalid."); + throw new MqttProtocolViolationException($"Remaining length is invalid (Data={string.Join(",", readBytes)})."); } } while ((encodedByte & 128) != 0); + return value; } } diff --git a/Tests/MQTTnet.Core.Tests/MqttCommunicationAdapterFactory.cs b/Tests/MQTTnet.Core.Tests/MqttCommunicationAdapterFactory.cs index 7e3a7dca..0e56411c 100644 --- a/Tests/MQTTnet.Core.Tests/MqttCommunicationAdapterFactory.cs +++ b/Tests/MQTTnet.Core.Tests/MqttCommunicationAdapterFactory.cs @@ -13,12 +13,12 @@ namespace MQTTnet.Core.Tests _adapter = adapter; } - public IMqttCommunicationAdapter CreateClientMqttCommunicationAdapter(IMqttClientOptions options) + public IMqttCommunicationAdapter CreateClientCommunicationAdapter(IMqttClientOptions options) { return _adapter; } - public IMqttCommunicationAdapter CreateServerMqttCommunicationAdapter(IMqttCommunicationChannel channel) + public IMqttCommunicationAdapter CreateServerCommunicationAdapter(IMqttCommunicationChannel channel) { return _adapter; } diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj index 753bac9c..096f72f6 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj @@ -18,7 +18,7 @@ {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} true MQTTnet.TestApp.UniversalWindows_TemporaryKey.pfx - 13E377A693C923EE9E88EE84B32A4B9881657362 + 05F70CAF1426E296BE2F7396F0B654070D72B930 win10;win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows_TemporaryKey.pfx b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows_TemporaryKey.pfx new file mode 100644 index 0000000000000000000000000000000000000000..1adc8878176c4eac6fecb87e8c9868c5d1d510da GIT binary patch literal 2504 zcmZWpc|6oxAN~zv8EaY6NM^7@AhINTB-=>L5M5&_ z*|Mc1HzfOVNkT#;+^Ns|-urn!?>V3EInVcbzTb1sKj%S{AuVhmb~G7sof9HYHKy+H zgSbFNWQZ@A4Dn>qZfG*c=l_v7=D=i*DHc7>iV;rU|8(*3fY^%2;B7P+{2495$@5>D zb+`bSd&*MG7d9Z)z{bWk2quFEN5v~B9WOhIyz@_-^|OhhPdbge#-|?!wscFY{Ozi7+Mwe}L($;S2 zIJCK)s*3*I=q}MB5Zl^v7?<+eAGMgKwUj5sh&_xV;V=5%Yiq3Sye9RB8n2<@VinUS zekMNg=A2*e3+s~j2tHY2>-y6GZe^k5c#Gj=utZ>2b53!8B7H&8P&WFG)}P2Yw~hG^ zhc<8F>je~i0f%qpAe)*(qHX-_ZEctI&(Bc^sIlbR%t*_I6C6@QY?@j;cQ-5ulW*0l z)s7f!gxlucG+A8~IJl$&3COJLr>2q*=k@K$%NeIF07r#k$Z6r(4{tt=9nri@xf@Q# z5oA2|BpE&H8l7}uY41}_FxVr%@w^CUC)nsfPOzj`gBjb8&*W=y@KQ0KNLY=WeH~JaiDUReo4*~A$IhBvWfv`hwOB0X6SNx^tZ&f#!ns)7ak&dm;rFj@OoUYMNupPtea*(jEO$ z4019C%|u%26=UZlx65Ts%j+i&GAMoCT|?qLHaFp|g;Jf)=I zMy5TcAb+uH)A`E7_*QvYnA$et<5~R?KJI3N2ll_e%6Veo4_MJ!Xz2IE5oEY<|246w zGcs!@Aj45-#2R0WnncGW73Mb?g~w!#!oF|8F$VUQ_~UumgTD2h%PC?+#@@WkOhu^> z{iwr+Hsj8jOVTEiP=+J)AZue$qP7wWoo}c3Dt#_E-q@Gj7;^bI**MZJxzz27q&A2v zte^h8!|KrXKGJg+TJc6MR6Y|sAhE?6gcc}3woJEV#ih9~*dJ9Gy0LH?Gq75xl$Tz1 z*3oM}aN^9%w+G>Qhg5`WDjF@=&znmckhJD}KN9DY&JQ5v1q_N!92#QYra;~YNr&U7qzwj$Myr~i5p$B*6DOH}HuwQpJ> zK6MVUI(qhtikpGSq0jr|2q&pMj(aXH6 z{KgD|(bdu97oNHI;FUa7LUEq8Lsv7z6+S+Wucs1anT(7(fGR0ERU$0m`iK1Qc1=1Hk@5s(=Oy zX|lMViU;7vLY}O8O;(o*tL~?!2B@>D)X>hH5Cu*U7(`Y-48mAQo(IeTU%(v*0Rn+g zR(Jtd0XSgIT7NPDfHy0{vG5Hbh{Xl6@(|YXL4eP%E;wNEt1gU{d9bbwL6h0N|9LqV zXAzm5z@lu}Kmcnq`&R+|ztt~BGH*&$$-4fu`e-sc{N=!?4nmM!Do!IC3qCTZp3sV4 z+86A&ps!O>2#XGS5UG1>%6ZE?OF#eWmjGeC%g>fwAr{WbOMjIf)B(L-=jMkHbqZ6> zwha<(f3YK+g6JpbV5o~!|8zF{hoOS)w(?fYLkwi>J>tptj9aq46s2QhZztVx#iP~M z>PHiID0=d9gQ$_O@^&JdrHPP^dqeID`RBsnR=J_`x>#L3=>pU~GlGrz%*4hdcBVgxRvzmz=b~qy zexg^mb^9V+VE)o0t=;5MMUgd$S;FZ>%GXZYYfDav_35)${hs!38YxCie_Op+*ne{u zy1L96U}d9_nYOvSEDNuv4l3O?^0_v;k6C#k7(>Y57p*KuxxZQ`Yew(8Sjn~}mc(EA zVVnIehEu&mZo>sHQhr}9sHX@)%PEBJv=gLgJt;X=Jv&t{b{az{%<9?P;seH|)d}tP z77gq0UJlpC)YPiyXq6U~J*#q^#xXu0()o8;Zm!7{eDQuB(L1KU?uRg9Ii9*w9|6 zA`$a@(?P@nfAt2NisGA}IgKd$YuO?m7bXk4fX|k!J=* zkIL%J)%Pr($!n)QOcdp^5of#i7~^12Nl{OeS`PWbbKv9}fXq#_Z!hyq-`Gun@+N#e z*9~!3AjxS@P( ClientId: - + Clean session: + + TCP WS diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index 76c0d073..ab467404 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -81,6 +81,8 @@ namespace MQTTnet.TestApp.UniversalWindows Password = Password.Text }; + options.CleanSession = CleanSession.IsChecked == true; + try { if (_mqttClient != null) @@ -226,6 +228,7 @@ namespace MQTTnet.TestApp.UniversalWindows .WithTcpServer("broker.hivemq.com") .WithCredentials("bud", "%spencer%") .WithTls() + .WithCleanSession() .Build(); await client.ConnectAsync(options); diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/Package.appxmanifest b/Tests/MQTTnet.TestApp.UniversalWindows/Package.appxmanifest index d6a7c4c1..b677c2aa 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/Package.appxmanifest +++ b/Tests/MQTTnet.TestApp.UniversalWindows/Package.appxmanifest @@ -1,10 +1,10 @@  - + MQTTnet.TestApp.UniversalWindows - chris + test Assets\StoreLogo.png From f0e8d8e98ce763bd29ea9efe145fe64ce8cd7ecd Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 31 Oct 2017 10:03:31 +0100 Subject: [PATCH 012/149] Update docs, extend UWP test app --- README.md | 1 + .../MainPage.xaml | 15 +++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6e99af3f..b6400db6 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@

[![NuGet Badge](https://buildstats.info/nuget/MQTTnet)](https://www.nuget.org/packages/MQTTnet) +[![Build status](https://ci.appveyor.com/api/projects/status/ycit86voxfevm2aa/branch/master?svg=true)](https://ci.appveyor.com/project/chkr1011/mqttnet/branch/develop) [![BCH compliance](https://bettercodehub.com/edge/badge/chkr1011/MQTTnet?branch=master)](https://bettercodehub.com/) # MQTTnet diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml index e2d58bed..64d1d679 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml @@ -9,14 +9,12 @@ mc:Ignorable="d"> - - - + Server: @@ -96,15 +94,16 @@
+ + + + + - + - - - - From d5dc3a1361c9e545080a76365dcca3cb6c0db83c Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 31 Oct 2017 10:34:27 +0100 Subject: [PATCH 013/149] Update docs --- README.md | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index b6400db6..eccffdc3 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,13 @@ [![BCH compliance](https://bettercodehub.com/edge/badge/chkr1011/MQTTnet?branch=master)](https://bettercodehub.com/) # MQTTnet -MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). The implementation is based on the documentation from http://mqtt.org/. -# Features +MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). The implementation is based on the documentation from . + +## Features ### General + * Async support * TLS 1.2 support for client and server (but not UWP servers) * Extensible communication channels (i.e. In-Memory, TCP, TCP+TLS, WS) @@ -21,9 +23,10 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov * Access to internal trace messages * Unit tested (70+ tests) -\* Tested on local machine with MQTTnet client and server running in the same process using the TCP channel. The app for verification is part of this repository and stored in _/Tests/MQTTnet.TestApp.NetFramework_. +\* Tested on local machine with MQTTnet client and server running in the same process using the TCP channel. The app for verification is part of this repository and stored in _/Tests/MQTTnet.TestApp.NetCore_. ### Client + * Communication via TCP (+TLS) or WS (WebSocket) supported * Included core _MqttClient_ with low level functionality * Also included _ManagedMqttClient_ which maintains the connection and subscriptions automatically. Also application messages are queued and re-scheduled for higher QoS levels automatically. @@ -31,16 +34,18 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov * Compatible with Microsoft Azure IoT Hub ### Server (broker) + * List of connected clients available * Supports connected clients with different protocol versions at the same time * Able to publish its own messages (no loopback client required) * Able to receive every message (no loopback client required) * Extensible client credential validation * Retained messages are supported including persisting via interface methods (own implementation required) -* WebSockets supported (via ASP.NET Core 2.0) +* WebSockets supported (via ASP.NET Core 2.0, separate nuget) * A custom message interceptor can be added which allows transforming or extending every received application message -# Supported frameworks +## Supported frameworks + * .NET Standard 1.3+ * .NET Core 1.1+ * .NET Core App 1.1+ @@ -48,28 +53,33 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov * Universal Windows (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU) * Mono 5.2+ -# Supported MQTT versions +## Supported MQTT versions + * 3.1.1 * 3.1.0 -# Nuget -This library is available as a nuget package: https://www.nuget.org/packages/MQTTnet/ +## Nuget -# Examples -Please find examples and the documentation at the Wiki of this repository (https://github.com/chkr1011/MQTTnet/wiki). +This library is available as a nuget package: + +## Examples + +Please find examples and the documentation at the Wiki of this repository (). + +## Contributions -# Contributions If you want to contribute to this project just create a pull request. But only pull requests which are matching the code style of this library will be accepted. Before creating a pull request please have a look at the library to get an overview of the required style. -# References +## References + This library is used in the following projects: -* MQTT Client Rx (Wrapper for Reactive Extensions, https://github.com/1iveowl/MQTTClient.rx) -* Wirehome (Open Source Home Automation system for .NET, https://github.com/chkr1011/Wirehome) +* MQTT Client Rx (Wrapper for Reactive Extensions, ) +* Wirehome (Open Source Home Automation system for .NET, ) If you use this library and want to see your project here please let me know. -# MIT License +## MIT License Copyright (c) 2017 Christian Kratky From 9c46b8fd7518e02e9970a4599747157ebdee65e0 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 31 Oct 2017 14:10:39 +0100 Subject: [PATCH 014/149] Fix handling of closed streams --- .../Adapter/MqttChannelCommunicationAdapter.cs | 6 +++++- MQTTnet.Core/Serializer/MqttPacketReader.cs | 16 +++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs index d47d4cee..7084227b 100644 --- a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs +++ b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs @@ -151,7 +151,7 @@ namespace MQTTnet.Core.Adapter receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).ConfigureAwait(false); } - if (cancellationToken.IsCancellationRequested) + if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested) { throw new TaskCanceledException(); } @@ -190,6 +190,10 @@ namespace MQTTnet.Core.Adapter private static async Task ReceiveAsync(Stream stream, CancellationToken cancellationToken) { var header = MqttPacketReader.ReadHeaderFromSource(stream, cancellationToken); + if (header == null) + { + return null; + } if (header.BodyLength == 0) { diff --git a/MQTTnet.Core/Serializer/MqttPacketReader.cs b/MQTTnet.Core/Serializer/MqttPacketReader.cs index ce80cd50..97b6478c 100644 --- a/MQTTnet.Core/Serializer/MqttPacketReader.cs +++ b/MQTTnet.Core/Serializer/MqttPacketReader.cs @@ -25,7 +25,13 @@ namespace MQTTnet.Core.Serializer public static MqttPacketHeader ReadHeaderFromSource(Stream stream, CancellationToken cancellationToken) { - var fixedHeader = (byte)stream.ReadByte(); + var buffer = stream.ReadByte(); + if (buffer == -1) + { + return null; + } + + var fixedHeader = (byte)buffer; var controlPacketType = (MqttControlPacketType)(fixedHeader >> 4); var bodyLength = ReadBodyLengthFromSource(stream, cancellationToken); @@ -83,10 +89,10 @@ namespace MQTTnet.Core.Serializer var buffer = stream.ReadByte(); readBytes.Add(buffer); - ////if (buffer == -1) - ////{ - //// break; - ////} + if (buffer == -1) + { + break; + } encodedByte = (byte)buffer; value += (byte)(encodedByte & 127) * multiplier; From c5e3bc70b16ef5bb79ba72ac0d48bbf5256aa6ce Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 31 Oct 2017 14:26:29 +0100 Subject: [PATCH 015/149] Update docs --- Build/MQTTnet.AspNetCore.nuspec | 2 -- Build/MQTTnet.nuspec | 8 +++++--- README.md | 4 +++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index eb5f637f..df0b9a4f 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -15,7 +15,6 @@ Copyright Christian Kratky 2016-2017 MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation - @@ -25,6 +24,5 @@ - \ No newline at end of file diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index fe5d708b..e8169020 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -10,20 +10,22 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * [Core] Merged the .NET Framwork and netstandard projects (Thanks to @JanEggers) + * [Core] Merged the platform specific projects (Thanks to @JanEggers) * [Core] Migrated the trace to a non-static approach (Breaking Change!) * [Core] Added a builder for application messages using a fluent API -* [Core] Introduced CI (Thanks to @JanEggers) +* [Core] Introduced CI and DI (Thanks to @JanEggers) * [Core] Added interfaces for publishing and receiving which applies to every client and server (Thanks to @ChristianRiedl) +* [Core] Fixed an issue when reading from closed streams * [Client] Added a first version of a managed client which will manage the connection, subscription etc. automatically (Thanks to @JTrotta) * [Client] The session state response from the server is now returned in the _ConnectAsync_ method and also part of the _Connected_ event args * [Client] Added a _TopicFilterBuilder_ using a fluent API (Namespace Changes!) * [Client] Added several new options for the WebSocket channel (Thanks to @ChristianRiedl) * [Client] Refactored the options and added a builder using a fluent API (Breaking Change!) * [Client] Added more options for WebSocket connections like RequestHeaders, SubProtocol etc. -* [Server] Added support for WebSockets via ASP.NET Core 2.0 (Thanks to @ChristianRiedl) +* [Server] Added support for WebSockets via ASP.NET Core 2.0 (additional nuget) (Thanks to @ChristianRiedl, @JanEggers) * [Server] Added support for a custom application message interceptor * [Server] Fixed an issue with dropped connections on UWP (Thanks to @haeberle) +* [Server] Added support for a custom subscription interceptor which allows denying of subscriptions and closing the connection Copyright Christian Kratky 2016-2017 MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation diff --git a/README.md b/README.md index eccffdc3..985c2837 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,11 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov * .NET Standard 1.3+ * .NET Core 1.1+ * .NET Core App 1.1+ +* Universal Windows Platform (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU) * .NET Framework 4.5.2+ (x86, x64, AnyCPU) -* Universal Windows (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU) * Mono 5.2+ +* Xamarin.Android 7.5+ +* Xamarin.iOS 10.14+ ## Supported MQTT versions From 3a6df2eab0d64540e19bd53bb43311c300d8961b Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 31 Oct 2017 14:38:24 +0100 Subject: [PATCH 016/149] Fix unit tests --- Build/MQTTnet.AspNetCore.nuspec | 2 +- Build/MQTTnet.nuspec | 2 +- .../MqttPacketReaderTests.cs | 20 +++++++++++++++++++ Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 4 ++-- 4 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index df0b9a4f..9cf4005e 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -13,7 +13,7 @@ initial version Copyright Christian Kratky 2016-2017 - MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation + 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/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index e8169020..4631f247 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -28,7 +28,7 @@ * [Server] Added support for a custom subscription interceptor which allows denying of subscriptions and closing the connection Copyright Christian Kratky 2016-2017 - MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation + 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/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs b/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs new file mode 100644 index 00000000..6800e6ce --- /dev/null +++ b/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs @@ -0,0 +1,20 @@ +using System.IO; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MQTTnet.Core.Serializer; + +namespace MQTTnet.Core.Tests +{ + [TestClass] + public class MqttPacketReaderTests + { + [TestMethod] + public void MqttPacketReader_EmptyStream() + { + var memStream = new MemoryStream(); + var header = MqttPacketReader.ReadHeaderFromSource(memStream, CancellationToken.None); + + Assert.IsNull(header); + } + } +} diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index 3f5b4cf6..106eca6e 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -274,8 +274,8 @@ namespace MQTTnet.Core.Tests public async Task MqttServer_PersistRetainedMessage() { var storage = new TestStorage(); - var serverAdapter = new TestMqttServerAdapter(); + var services = new ServiceCollection() .AddLogging() .AddMqttServer() @@ -297,7 +297,7 @@ namespace MQTTnet.Core.Tests await s.StopAsync(); } - s = services.GetRequiredService(); + s = new MqttFactory(services).CreateMqttServer(options => options.Storage = storage); var receivedMessagesCount = 0; try From 11ccb951aa7e3141b0d92d5eadf1b79a29d6a221 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Wed, 1 Nov 2017 13:34:39 +0100 Subject: [PATCH 017/149] Refactor traces of server session handling --- .../Adapter/MqttChannelCommunicationAdapter.cs | 4 ++-- .../Adapter/MqttCommunicationAdapterExtensions.cs | 2 ++ .../Server/MqttClientPendingMessagesQueue.cs | 14 ++++++++------ MQTTnet.Core/Server/MqttClientSession.cs | 1 - 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs index 7084227b..04857b5f 100644 --- a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs +++ b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs @@ -85,10 +85,10 @@ namespace MQTTnet.Core.Adapter public async Task SendPacketsAsync(TimeSpan timeout, CancellationToken cancellationToken, IEnumerable packets) { - await _semaphore.WaitAsync(cancellationToken); - try { + await _semaphore.WaitAsync(cancellationToken); + foreach (var packet in packets) { if (packet == null) diff --git a/MQTTnet.Core/Adapter/MqttCommunicationAdapterExtensions.cs b/MQTTnet.Core/Adapter/MqttCommunicationAdapterExtensions.cs index 0fa9ab54..2142fd07 100644 --- a/MQTTnet.Core/Adapter/MqttCommunicationAdapterExtensions.cs +++ b/MQTTnet.Core/Adapter/MqttCommunicationAdapterExtensions.cs @@ -9,6 +9,8 @@ namespace MQTTnet.Core.Adapter { public static Task SendPacketsAsync(this IMqttCommunicationAdapter adapter, TimeSpan timeout, CancellationToken cancellationToken, params MqttBasePacket[] packets) { + if (adapter == null) throw new ArgumentNullException(nameof(adapter)); + return adapter.SendPacketsAsync(timeout, cancellationToken, packets); } } diff --git a/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs b/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs index 446e0a86..599f4ee8 100644 --- a/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs +++ b/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs @@ -13,8 +13,8 @@ namespace MQTTnet.Core.Server public sealed class MqttClientPendingMessagesQueue { private readonly BlockingCollection _pendingPublishPackets = new BlockingCollection(); - private readonly MqttClientSession _session; private readonly MqttServerOptions _options; + private readonly MqttClientSession _session; private readonly ILogger _logger; public MqttClientPendingMessagesQueue(MqttServerOptions options, MqttClientSession session, ILogger logger) @@ -28,7 +28,7 @@ namespace MQTTnet.Core.Server { if (adapter == null) throw new ArgumentNullException(nameof(adapter)); - Task.Factory.StartNew(async () => await SendPendingPublishPacketsAsync(adapter, cancellationToken), cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false); + Task.Run(async () => await SendPendingPublishPacketsAsync(adapter, cancellationToken), cancellationToken).ConfigureAwait(false); } public void Enqueue(MqttPublishPacket publishPacket) @@ -36,6 +36,7 @@ namespace MQTTnet.Core.Server if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket)); _pendingPublishPackets.Add(publishPacket); + _logger.LogTrace("Enqueued packet (ClientId: {0}).", _session.ClientId); } private async Task SendPendingPublishPacketsAsync(IMqttCommunicationAdapter adapter, CancellationToken cancellationToken) @@ -52,7 +53,7 @@ namespace MQTTnet.Core.Server } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Unhandled exception while sending pending publish packets."); + _logger.LogError(new EventId(), exception, "Unhandled exception while sending enqueued packet (ClientId: {0}).", _session.ClientId); } } @@ -63,23 +64,24 @@ namespace MQTTnet.Core.Server try { await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, packet).ConfigureAwait(false); + _logger.LogTrace("Enqueued packet sent (ClientId: {0}).", _session.ClientId); } catch (Exception exception) { if (exception is MqttCommunicationTimedOutException) { - _logger.LogWarning(new EventId(), exception, "Sending publish packet failed due to timeout."); + _logger.LogWarning(new EventId(), exception, "Sending publish packet failed due to timeout (ClientId: {0}).", _session.ClientId); } else if (exception is MqttCommunicationException) { - _logger.LogWarning(new EventId(), exception, "Sending publish packet failed due to communication exception."); + _logger.LogWarning(new EventId(), exception, "Sending publish packet failed due to communication exception (ClientId: {0}).", _session.ClientId); } else if (exception is OperationCanceledException) { } else { - _logger.LogError(new EventId(), exception, "Sending publish packet failed."); + _logger.LogError(new EventId(), exception, "Sending publish packet failed (ClientId: {0}).", _session.ClientId); } if (packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) diff --git a/MQTTnet.Core/Server/MqttClientSession.cs b/MQTTnet.Core/Server/MqttClientSession.cs index 903b3306..52f6393f 100644 --- a/MQTTnet.Core/Server/MqttClientSession.cs +++ b/MQTTnet.Core/Server/MqttClientSession.cs @@ -108,7 +108,6 @@ namespace MQTTnet.Core.Server } _pendingMessagesQueue.Enqueue(publishPacket); - _logger.LogTrace("Client '{0}': Enqueued pending publish packet.", ClientId); } public void Dispose() From 387a3bc281402a496c3b6a75e4339cbfb59a9ed8 Mon Sep 17 00:00:00 2001 From: Jan Eggers Date: Mon, 6 Nov 2017 08:36:34 +0100 Subject: [PATCH 018/149] added dependencies to nuspec and fixed build --- Build/MQTTnet.nuspec | 4 ++++ Build/build.ps1 | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 4631f247..c3f59858 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -34,10 +34,14 @@ + + + + diff --git a/Build/build.ps1 b/Build/build.ps1 index 6284473a..e74f9f06 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -11,7 +11,7 @@ if ($path) { &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net451" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m - &dotnet build ..\Frameworks\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj -c="Release" /p:FileVersion=$version /p:AssemblyVersion=$version + &$msbuild ..\Frameworks\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m Remove-Item .\NuGet -Force -Recurse New-Item -ItemType Directory -Force -Path .\NuGet From 5fbef7beb5f6dd688b0af4f7d7774305909b7d7e Mon Sep 17 00:00:00 2001 From: Jan Eggers Date: Mon, 6 Nov 2017 10:37:09 +0100 Subject: [PATCH 019/149] added more missing packages --- Build/MQTTnet.nuspec | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index c3f59858..9c841088 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -33,15 +33,20 @@ - + + + + + + From 8778848301f83854dff7606b8ade5c783b6fa99d Mon Sep 17 00:00:00 2001 From: Jan Eggers Date: Mon, 6 Nov 2017 10:57:27 +0100 Subject: [PATCH 020/149] added some more missing packages --- Build/MQTTnet.nuspec | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 9c841088..2583897c 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -48,6 +48,12 @@ + + + + + + From e6e88e132b73e5805f4a03efe406bc2b718d74e2 Mon Sep 17 00:00:00 2001 From: Jan Eggers Date: Mon, 6 Nov 2017 12:47:31 +0100 Subject: [PATCH 021/149] possibly fixed timing issue in test --- .../MQTTnet.AspnetCore/MqttHostedServer.cs | 10 ++++++++-- Frameworks/MQTTnet.NetStandard/MqttFactory.cs | 4 +++- .../ServiceCollectionExtensions.cs | 4 ++-- .../Server/IMqttClientRetainedMessageManager.cs | 15 +++++++++++++++ .../Server/MqttClientRetainedMessagesManager.cs | 2 +- MQTTnet.Core/Server/MqttClientSession.cs | 11 +++++++---- .../Server/MqttClientSessionsManager.cs | 4 ---- MQTTnet.Core/Server/MqttServer.cs | 13 +++++++++++-- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 17 +++++++++++++++++ 9 files changed, 64 insertions(+), 16 deletions(-) create mode 100644 MQTTnet.Core/Server/IMqttClientRetainedMessageManager.cs diff --git a/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs b/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs index db725735..8d005187 100644 --- a/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs +++ b/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs @@ -11,8 +11,14 @@ namespace MQTTnet.AspNetCore { public class MqttHostedServer : MqttServer, IHostedService { - public MqttHostedServer(IOptions options, IEnumerable adapters, ILogger logger, MqttClientSessionsManager clientSessionsManager) - : base(options, adapters, logger, clientSessionsManager) + public MqttHostedServer( + IOptions options, + IEnumerable adapters, + ILogger logger, + MqttClientSessionsManager clientSessionsManager, + IMqttClientRetainedMessageManager clientRetainedMessageManager + ) + : base(options, adapters, logger, clientSessionsManager, clientRetainedMessageManager) { } diff --git a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs index 432a3719..394374de 100644 --- a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs @@ -99,7 +99,9 @@ namespace MQTTnet clientSessionsManager, _serviceProvider.GetRequiredService(), _serviceProvider.GetRequiredService>(), - _serviceProvider.GetRequiredService>()); + _serviceProvider.GetRequiredService>(), + _serviceProvider.GetRequiredService() + ); } public IMqttClient CreateMqttClient() diff --git a/Frameworks/MQTTnet.NetStandard/ServiceCollectionExtensions.cs b/Frameworks/MQTTnet.NetStandard/ServiceCollectionExtensions.cs index aa53e1b8..4e6639a7 100644 --- a/Frameworks/MQTTnet.NetStandard/ServiceCollectionExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/ServiceCollectionExtensions.cs @@ -33,9 +33,9 @@ namespace MQTTnet services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddSingleton(); services.AddTransient(); - services.AddTransient(); + services.AddSingleton(); return services; } diff --git a/MQTTnet.Core/Server/IMqttClientRetainedMessageManager.cs b/MQTTnet.Core/Server/IMqttClientRetainedMessageManager.cs new file mode 100644 index 00000000..cd3426ea --- /dev/null +++ b/MQTTnet.Core/Server/IMqttClientRetainedMessageManager.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using MQTTnet.Core.Packets; + +namespace MQTTnet.Core.Server +{ + public interface IMqttClientRetainedMessageManager + { + Task LoadMessagesAsync(); + + Task HandleMessageAsync(string clientId, MqttApplicationMessage applicationMessage); + + List GetMessages(MqttSubscribePacket subscribePacket); + } +} diff --git a/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs b/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs index 68a7b99b..2213360a 100644 --- a/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs +++ b/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Options; namespace MQTTnet.Core.Server { - public sealed class MqttClientRetainedMessagesManager + public sealed class MqttClientRetainedMessagesManager : IMqttClientRetainedMessageManager { private readonly Dictionary _retainedMessages = new Dictionary(); private readonly ILogger _logger; diff --git a/MQTTnet.Core/Server/MqttClientSession.cs b/MQTTnet.Core/Server/MqttClientSession.cs index 52f6393f..00f906ff 100644 --- a/MQTTnet.Core/Server/MqttClientSession.cs +++ b/MQTTnet.Core/Server/MqttClientSession.cs @@ -15,6 +15,7 @@ namespace MQTTnet.Core.Server { public sealed class MqttClientSession : IDisposable { + private readonly IMqttClientRetainedMessageManager _clientRetainedMessageManager; private readonly HashSet _unacknowledgedPublishPackets = new HashSet(); private readonly MqttClientSubscriptionsManager _subscriptionsManager; @@ -33,10 +34,12 @@ namespace MQTTnet.Core.Server MqttClientSessionsManager sessionsManager, MqttClientSubscriptionsManager subscriptionsManager, ILogger logger, - ILogger messageQueueLogger) + ILogger messageQueueLogger, + IMqttClientRetainedMessageManager clientRetainedMessageManager) { + _clientRetainedMessageManager = clientRetainedMessageManager ?? throw new ArgumentNullException(nameof(clientRetainedMessageManager)); _sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager)); - _subscriptionsManager = subscriptionsManager ?? throw new ArgumentNullException(nameof(sessionsManager)); + _subscriptionsManager = subscriptionsManager ?? throw new ArgumentNullException(nameof(subscriptionsManager)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); ClientId = clientId; @@ -206,7 +209,7 @@ namespace MQTTnet.Core.Server private void EnqueueRetainedMessages(MqttSubscribePacket subscribePacket) { - var retainedMessages = _sessionsManager.RetainedMessagesManager.GetMessages(subscribePacket); + var retainedMessages = _clientRetainedMessageManager.GetMessages(subscribePacket); foreach (var publishPacket in retainedMessages) { EnqueuePublishPacket(publishPacket.ToPublishPacket()); @@ -227,7 +230,7 @@ namespace MQTTnet.Core.Server if (applicationMessage.Retain) { - await _sessionsManager.RetainedMessagesManager.HandleMessageAsync(ClientId, applicationMessage); + await _clientRetainedMessageManager.HandleMessageAsync(ClientId, applicationMessage); } switch (applicationMessage.QualityOfServiceLevel) diff --git a/MQTTnet.Core/Server/MqttClientSessionsManager.cs b/MQTTnet.Core/Server/MqttClientSessionsManager.cs index 62cc1d82..b2cbdc09 100644 --- a/MQTTnet.Core/Server/MqttClientSessionsManager.cs +++ b/MQTTnet.Core/Server/MqttClientSessionsManager.cs @@ -24,12 +24,10 @@ namespace MQTTnet.Core.Server public MqttClientSessionsManager( IOptions options, ILogger logger, - MqttClientRetainedMessagesManager retainedMessagesManager, IMqttClientSesssionFactory clientSesssionFactory) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _options = options.Value ?? throw new ArgumentNullException(nameof(options)); - RetainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(options)); _clientSesssionFactory = clientSesssionFactory ?? throw new ArgumentNullException(nameof(clientSesssionFactory)); } @@ -37,8 +35,6 @@ namespace MQTTnet.Core.Server public event EventHandler ClientDisconnected; public event EventHandler ApplicationMessageReceived; - public MqttClientRetainedMessagesManager RetainedMessagesManager { get; } - public async Task RunClientSessionAsync(IMqttCommunicationAdapter clientAdapter, CancellationToken cancellationToken) { var clientId = string.Empty; diff --git a/MQTTnet.Core/Server/MqttServer.cs b/MQTTnet.Core/Server/MqttServer.cs index f1ed791e..f5a9527c 100644 --- a/MQTTnet.Core/Server/MqttServer.cs +++ b/MQTTnet.Core/Server/MqttServer.cs @@ -6,11 +6,13 @@ using MQTTnet.Core.Adapter; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System.Linq; +using Microsoft.Extensions.DependencyInjection; namespace MQTTnet.Core.Server { public class MqttServer : IMqttServer { + private readonly IMqttClientRetainedMessageManager _clientRetainedMessageManager; private readonly ILogger _logger; private readonly MqttClientSessionsManager _clientSessionsManager; private readonly ICollection _adapters; @@ -18,11 +20,18 @@ namespace MQTTnet.Core.Server private CancellationTokenSource _cancellationTokenSource; - public MqttServer(IOptions options, IEnumerable adapters, ILogger logger, MqttClientSessionsManager clientSessionsManager) + public MqttServer( + IOptions options, + IEnumerable adapters, + ILogger logger, + MqttClientSessionsManager clientSessionsManager, + IMqttClientRetainedMessageManager clientRetainedMessageManager + ) { _options = options.Value ?? throw new ArgumentNullException(nameof(options)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _clientSessionsManager = clientSessionsManager ?? throw new ArgumentNullException(nameof(clientSessionsManager)); + _clientRetainedMessageManager = clientRetainedMessageManager ?? throw new ArgumentNullException(nameof(clientRetainedMessageManager)); if (adapters == null) { @@ -79,7 +88,7 @@ namespace MQTTnet.Core.Server _cancellationTokenSource = new CancellationTokenSource(); - await _clientSessionsManager.RetainedMessagesManager.LoadMessagesAsync(); + await _clientRetainedMessageManager.LoadMessagesAsync(); foreach (var adapter in _adapters) { diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index 106eca6e..44d489b4 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -8,6 +9,7 @@ using MQTTnet.Core.Client; using MQTTnet.Core.Protocol; using MQTTnet.Core.Server; using Microsoft.Extensions.DependencyInjection; +using MQTTnet.Core.Packets; namespace MQTTnet.Core.Tests { @@ -210,6 +212,7 @@ namespace MQTTnet.Core.Tests .BuildServiceProvider(); var s = new MqttFactory(services).CreateMqttServer(); + var retainMessagemanager = services.GetRequiredService(); var receivedMessagesCount = 0; try @@ -220,6 +223,20 @@ namespace MQTTnet.Core.Tests await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build()); await c1.DisconnectAsync(); + var subscribe = new MqttSubscribePacket() + { + TopicFilters = new List() + { + new TopicFilter("retained", MqttQualityOfServiceLevel.AtMostOnce) + } + }; + + //make shure the retainedMessageManagerreceived the package + while (retainMessagemanager.GetMessages(subscribe).Any()) + { + await Task.Delay(TimeSpan.FromMilliseconds(10)); + } + var c2 = await serverAdapter.ConnectTestClient(s, "c2"); c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++; await c2.SubscribeAsync(new TopicFilter("retained", MqttQualityOfServiceLevel.AtMostOnce)); From e07ead53a9c3e18aabad337755909e41a6f73e27 Mon Sep 17 00:00:00 2001 From: Jan Eggers Date: Mon, 6 Nov 2017 12:52:41 +0100 Subject: [PATCH 022/149] fixed wait --- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index 44d489b4..86ff600e 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -232,7 +232,7 @@ namespace MQTTnet.Core.Tests }; //make shure the retainedMessageManagerreceived the package - while (retainMessagemanager.GetMessages(subscribe).Any()) + while (!retainMessagemanager.GetMessages(subscribe).Any()) { await Task.Delay(TimeSpan.FromMilliseconds(10)); } From f481c704c930a37bed5096970101d165a23098cd Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 7 Nov 2017 23:30:15 +0100 Subject: [PATCH 023/149] Fixed an issue with queued client message in the server. --- .../ManagedMqttClientOptionsBuilder.cs | 49 +++++++++++++++++++ .../Server/MqttClientPendingMessagesQueue.cs | 9 ++-- MQTTnet.Core/TopicFilter.cs | 2 +- MQTTnet.Core/TopicFilterBuilder.cs | 2 +- 4 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 MQTTnet.Core/ManagedClient/ManagedMqttClientOptionsBuilder.cs diff --git a/MQTTnet.Core/ManagedClient/ManagedMqttClientOptionsBuilder.cs b/MQTTnet.Core/ManagedClient/ManagedMqttClientOptionsBuilder.cs new file mode 100644 index 00000000..3972dcd2 --- /dev/null +++ b/MQTTnet.Core/ManagedClient/ManagedMqttClientOptionsBuilder.cs @@ -0,0 +1,49 @@ +using System; +using MQTTnet.Core.Client; + +namespace MQTTnet.Core.ManagedClient +{ + public class ManagedMqttClientOptionsBuilder + { + private readonly ManagedMqttClientOptions _options = new ManagedMqttClientOptions(); + + public ManagedMqttClientOptionsBuilder WithAutoReconnectDelay(TimeSpan value) + { + _options.AutoReconnectDelay = value; + return this; + } + + public ManagedMqttClientOptionsBuilder WithStorage(IManagedMqttClientStorage value) + { + _options.Storage = value; + return this; + } + + public ManagedMqttClientOptionsBuilder WithClientOptions(IMqttClientOptions value) + { + _options.ClientOptions = value ?? throw new ArgumentNullException(nameof(value)); + return this; + } + + public ManagedMqttClientOptionsBuilder WithClientOptions(Action options) + { + if (options == null) throw new ArgumentNullException(nameof(options)); + + var builder = new MqttClientOptionsBuilder(); + options(builder); + _options.ClientOptions = builder.Build(); + + return this; + } + + public ManagedMqttClientOptions Build() + { + if (_options.ClientOptions == null) + { + throw new InvalidOperationException("The ClientOptions cannot be null."); + } + + return _options; + } + } +} diff --git a/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs b/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs index 599f4ee8..6b370db6 100644 --- a/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs +++ b/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs @@ -59,11 +59,12 @@ namespace MQTTnet.Core.Server private async Task SendPendingPublishPacketAsync(IMqttCommunicationAdapter adapter, CancellationToken cancellationToken) { - var packet = _pendingPublishPackets.Take(cancellationToken); - + MqttPublishPacket packet = null; try { + packet = _pendingPublishPackets.Take(cancellationToken); await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, packet).ConfigureAwait(false); + _logger.LogTrace("Enqueued packet sent (ClientId: {0}).", _session.ClientId); } catch (Exception exception) @@ -84,10 +85,10 @@ namespace MQTTnet.Core.Server _logger.LogError(new EventId(), exception, "Sending publish packet failed (ClientId: {0}).", _session.ClientId); } - if (packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) + if (packet != null && packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) { packet.Dup = true; - _pendingPublishPackets.Add(packet, cancellationToken); + _pendingPublishPackets.Add(packet, CancellationToken.None); } _session.Stop(); diff --git a/MQTTnet.Core/TopicFilter.cs b/MQTTnet.Core/TopicFilter.cs index 3e95afa0..6d5258f4 100644 --- a/MQTTnet.Core/TopicFilter.cs +++ b/MQTTnet.Core/TopicFilter.cs @@ -4,7 +4,7 @@ namespace MQTTnet.Core { public sealed class TopicFilter { - public TopicFilter(string topic, MqttQualityOfServiceLevel qualityOfServiceLevel) + public TopicFilter(string topic, MqttQualityOfServiceLevel qualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce) { Topic = topic; QualityOfServiceLevel = qualityOfServiceLevel; diff --git a/MQTTnet.Core/TopicFilterBuilder.cs b/MQTTnet.Core/TopicFilterBuilder.cs index 90114e7c..bb8416c1 100644 --- a/MQTTnet.Core/TopicFilterBuilder.cs +++ b/MQTTnet.Core/TopicFilterBuilder.cs @@ -5,8 +5,8 @@ namespace MQTTnet.Core { public class TopicFilterBuilder { - private string _topic; private MqttQualityOfServiceLevel _qualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce; + private string _topic; public TopicFilterBuilder WithTopic(string topic) { From 7e487469442631ccad35c56d4888059bc6abdffa Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Wed, 8 Nov 2017 00:49:49 +0100 Subject: [PATCH 024/149] Fix cleanup of client sessions --- .../Adapter/MqttChannelCommunicationAdapter.cs | 4 ++-- .../Server/MqttClientRetainedMessagesManager.cs | 1 - MQTTnet.Core/Server/MqttClientSession.cs | 10 ++-------- MQTTnet.Core/Server/MqttClientSessionsManager.cs | 4 ++-- 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs index 04857b5f..b31a870e 100644 --- a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs +++ b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs @@ -14,10 +14,10 @@ namespace MQTTnet.Core.Adapter { public class MqttChannelCommunicationAdapter : IMqttCommunicationAdapter { + private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly ILogger _logger; private readonly IMqttCommunicationChannel _channel; - private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); - + public MqttChannelCommunicationAdapter(IMqttCommunicationChannel channel, IMqttPacketSerializer serializer, ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); diff --git a/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs b/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs index 2213360a..d299daaf 100644 --- a/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs +++ b/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs @@ -68,7 +68,6 @@ namespace MQTTnet.Core.Server try { - // ReSharper disable once UseNullPropagation if (_options.Storage != null) { await _options.Storage.SaveRetainedMessagesAsync(allRetainedMessages); diff --git a/MQTTnet.Core/Server/MqttClientSession.cs b/MQTTnet.Core/Server/MqttClientSession.cs index 00f906ff..7ec312ae 100644 --- a/MQTTnet.Core/Server/MqttClientSession.cs +++ b/MQTTnet.Core/Server/MqttClientSession.cs @@ -13,11 +13,11 @@ using Microsoft.Extensions.Options; namespace MQTTnet.Core.Server { - public sealed class MqttClientSession : IDisposable + public sealed class MqttClientSession { - private readonly IMqttClientRetainedMessageManager _clientRetainedMessageManager; private readonly HashSet _unacknowledgedPublishPackets = new HashSet(); + private readonly IMqttClientRetainedMessageManager _clientRetainedMessageManager; private readonly MqttClientSubscriptionsManager _subscriptionsManager; private readonly MqttClientSessionsManager _sessionsManager; private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue; @@ -113,12 +113,6 @@ namespace MQTTnet.Core.Server _pendingMessagesQueue.Enqueue(publishPacket); } - public void Dispose() - { - _cancellationTokenSource?.Cancel(); - _cancellationTokenSource?.Dispose(); - } - private async Task ReceivePacketsAsync(IMqttCommunicationAdapter adapter, CancellationToken cancellationToken) { try diff --git a/MQTTnet.Core/Server/MqttClientSessionsManager.cs b/MQTTnet.Core/Server/MqttClientSessionsManager.cs index b2cbdc09..48fd33ec 100644 --- a/MQTTnet.Core/Server/MqttClientSessionsManager.cs +++ b/MQTTnet.Core/Server/MqttClientSessionsManager.cs @@ -164,10 +164,10 @@ namespace MQTTnet.Core.Server if (connectPacket.CleanSession) { _clientSessions.Remove(connectPacket.ClientId); - clientSession.Dispose(); + clientSession.Stop(); clientSession = null; - _logger.LogTrace("Disposed existing session of client '{0}'.", connectPacket.ClientId); + _logger.LogTrace("Stopped existing session of client '{0}'.", connectPacket.ClientId); } else { From d2e481719c2a8bf2a4107a1011ac152861530784 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Wed, 8 Nov 2017 14:30:13 +0100 Subject: [PATCH 025/149] Optimized persisting of retained messages to avoid useless writes to the filesystem --- .../IMqttClientRetainedMessageManager.cs | 2 +- .../MqttClientRetainedMessagesManager.cs | 73 +++++++++++++------ MQTTnet.Core/Server/MqttClientSession.cs | 7 +- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 2 +- .../JsonServerStorage.cs | 50 +++++++++++++ .../MQTTnet.TestApp.UniversalWindows.csproj | 1 + .../MainPage.xaml | 17 ++++- .../MainPage.xaml.cs | 31 ++++++++ 8 files changed, 155 insertions(+), 28 deletions(-) create mode 100644 Tests/MQTTnet.TestApp.UniversalWindows/JsonServerStorage.cs diff --git a/MQTTnet.Core/Server/IMqttClientRetainedMessageManager.cs b/MQTTnet.Core/Server/IMqttClientRetainedMessageManager.cs index cd3426ea..f4008998 100644 --- a/MQTTnet.Core/Server/IMqttClientRetainedMessageManager.cs +++ b/MQTTnet.Core/Server/IMqttClientRetainedMessageManager.cs @@ -10,6 +10,6 @@ namespace MQTTnet.Core.Server Task HandleMessageAsync(string clientId, MqttApplicationMessage applicationMessage); - List GetMessages(MqttSubscribePacket subscribePacket); + Task> GetSubscribedMessagesAsync(MqttSubscribePacket subscribePacket); } } diff --git a/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs b/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs index d299daaf..dbdb1d7a 100644 --- a/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs +++ b/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using MQTTnet.Core.Packets; using Microsoft.Extensions.Logging; @@ -11,6 +12,7 @@ namespace MQTTnet.Core.Server public sealed class MqttClientRetainedMessagesManager : IMqttClientRetainedMessageManager { private readonly Dictionary _retainedMessages = new Dictionary(); + private readonly SemaphoreSlim _gate = new SemaphoreSlim(1, 1); private readonly ILogger _logger; private readonly MqttServerOptions _options; @@ -27,62 +29,87 @@ namespace MQTTnet.Core.Server return; } + await _gate.WaitAsync(); try { var retainedMessages = await _options.Storage.LoadRetainedMessagesAsync(); - lock (_retainedMessages) + + _retainedMessages.Clear(); + foreach (var retainedMessage in retainedMessages) { - _retainedMessages.Clear(); - foreach (var retainedMessage in retainedMessages) - { - _retainedMessages[retainedMessage.Topic] = retainedMessage; - } + _retainedMessages[retainedMessage.Topic] = retainedMessage; } } catch (Exception exception) { _logger.LogError(new EventId(), exception, "Unhandled exception while loading retained messages."); } + finally + { + _gate.Release(); + } } public async Task HandleMessageAsync(string clientId, MqttApplicationMessage applicationMessage) { if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); - List allRetainedMessages; - lock (_retainedMessages) + await _gate.WaitAsync(); + try { + var saveIsRequired = false; + if (applicationMessage.Payload?.Any() == false) { - _retainedMessages.Remove(applicationMessage.Topic); + saveIsRequired = _retainedMessages.Remove(applicationMessage.Topic); _logger.LogInformation("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic); } else { - _retainedMessages[applicationMessage.Topic] = applicationMessage; - _logger.LogInformation("Client '{0}' updated retained message for topic '{1}'.", clientId, applicationMessage.Topic); + if (!_retainedMessages.ContainsKey(applicationMessage.Topic)) + { + _retainedMessages[applicationMessage.Topic] = applicationMessage; + saveIsRequired = true; + } + else + { + var existingMessage = _retainedMessages[applicationMessage.Topic]; + if (existingMessage.QualityOfServiceLevel != applicationMessage.QualityOfServiceLevel || !existingMessage.Payload.SequenceEqual(applicationMessage.Payload ?? new byte[0])) + { + _retainedMessages[applicationMessage.Topic] = applicationMessage; + saveIsRequired = true; + } + } + + _logger.LogInformation("Client '{0}' set retained message for topic '{1}'.", clientId, applicationMessage.Topic); } - allRetainedMessages = new List(_retainedMessages.Values); - } - - try - { - if (_options.Storage != null) + if (!saveIsRequired) { - await _options.Storage.SaveRetainedMessagesAsync(allRetainedMessages); + _logger.LogTrace("Skipped saving retained messages because no changes were detected."); + } + + if (saveIsRequired && _options.Storage != null) + { + await _options.Storage.SaveRetainedMessagesAsync(_retainedMessages.Values.ToList()); } } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Unhandled exception while saving retained messages."); + _logger.LogError(new EventId(), exception, "Unhandled exception while handling retained messages."); + } + finally + { + _gate.Release(); } } - public List GetMessages(MqttSubscribePacket subscribePacket) + public async Task> GetSubscribedMessagesAsync(MqttSubscribePacket subscribePacket) { var retainedMessages = new List(); - lock (_retainedMessages) + + await _gate.WaitAsync(); + try { foreach (var retainedMessage in _retainedMessages.Values) { @@ -103,6 +130,10 @@ namespace MQTTnet.Core.Server } } } + finally + { + _gate.Release(); + } return retainedMessages; } diff --git a/MQTTnet.Core/Server/MqttClientSession.cs b/MQTTnet.Core/Server/MqttClientSession.cs index 7ec312ae..9b14e587 100644 --- a/MQTTnet.Core/Server/MqttClientSession.cs +++ b/MQTTnet.Core/Server/MqttClientSession.cs @@ -191,8 +191,9 @@ namespace MQTTnet.Core.Server private async Task HandleIncomingSubscribePacketAsync(IMqttCommunicationAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken) { var subscribeResult = _subscriptionsManager.Subscribe(subscribePacket, ClientId); + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, subscribeResult.ResponsePacket); - EnqueueRetainedMessages(subscribePacket); + await EnqueueSubscribedRetainedMessagesAsync(subscribePacket); if (subscribeResult.CloseConnection) { @@ -201,9 +202,9 @@ namespace MQTTnet.Core.Server } } - private void EnqueueRetainedMessages(MqttSubscribePacket subscribePacket) + private async Task EnqueueSubscribedRetainedMessagesAsync(MqttSubscribePacket subscribePacket) { - var retainedMessages = _clientRetainedMessageManager.GetMessages(subscribePacket); + var retainedMessages = await _clientRetainedMessageManager.GetSubscribedMessagesAsync(subscribePacket); foreach (var publishPacket in retainedMessages) { EnqueuePublishPacket(publishPacket.ToPublishPacket()); diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index 86ff600e..b7098353 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -232,7 +232,7 @@ namespace MQTTnet.Core.Tests }; //make shure the retainedMessageManagerreceived the package - while (!retainMessagemanager.GetMessages(subscribe).Any()) + while (!(await retainMessagemanager.GetSubscribedMessagesAsync(subscribe)).Any()) { await Task.Delay(TimeSpan.FromMilliseconds(10)); } diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/JsonServerStorage.cs b/Tests/MQTTnet.TestApp.UniversalWindows/JsonServerStorage.cs new file mode 100644 index 00000000..9baafec0 --- /dev/null +++ b/Tests/MQTTnet.TestApp.UniversalWindows/JsonServerStorage.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using MQTTnet.Core; +using MQTTnet.Core.Server; +using Newtonsoft.Json; + +namespace MQTTnet.TestApp.UniversalWindows +{ + public class JsonServerStorage : IMqttServerStorage + { + private readonly string _filename = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "Retained.json"); + + public async Task SaveRetainedMessagesAsync(IList messages) + { + await Task.CompletedTask; + + var json = JsonConvert.SerializeObject(messages); + File.WriteAllText(_filename, json); + } + + public async Task> LoadRetainedMessagesAsync() + { + await Task.CompletedTask; + + if (!File.Exists(_filename)) + { + return new List(); + } + + try + { + var json = File.ReadAllText(_filename); + return JsonConvert.DeserializeObject>(json); + } + catch + { + return new List(); + } + } + + public void Clear() + { + if (File.Exists(_filename)) + { + File.Delete(_filename); + } + } + } +} diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj index 8fda5d33..ce511d6c 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj @@ -94,6 +94,7 @@ App.xaml + MainPage.xaml diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml index 64d1d679..4fdbd2e6 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml @@ -27,7 +27,7 @@ Clean session: - + TCP WS @@ -77,9 +77,19 @@ 2 (Exactly once) + Received messages: + + + + + + + + - + + @@ -88,6 +98,9 @@ Port: + Persist retained messages in JSON format + Clear previously retained messages on startup + diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index ab467404..bcea348e 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -88,10 +88,13 @@ namespace MQTTnet.TestApp.UniversalWindows if (_mqttClient != null) { await _mqttClient.DisconnectAsync(); + _mqttClient.ApplicationMessageReceived -= OnApplicationMessageReceived; } var factory = new MqttFactory(); _mqttClient = factory.CreateMqttClient(); + _mqttClient.ApplicationMessageReceived += OnApplicationMessageReceived; + await _mqttClient.ConnectAsync(options); } catch (Exception exception) @@ -100,6 +103,17 @@ namespace MQTTnet.TestApp.UniversalWindows } } + private async void OnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs eventArgs) + { + var item = $"Timestamp: {DateTime.Now:O} | Topic: {eventArgs.ApplicationMessage.Topic} | Payload: {Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload)} | QoS: {eventArgs.ApplicationMessage.QualityOfServiceLevel}"; + + await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + ReceivedMessages.Items.Add(item); + }); + + } + private async void Publish(object sender, RoutedEventArgs e) { if (_mqttClient == null) @@ -332,9 +346,21 @@ namespace MQTTnet.TestApp.UniversalWindows return; } + JsonServerStorage storage = null; + if (ServerPersistRetainedMessages.IsChecked == true) + { + storage = new JsonServerStorage(); + + if (ServerClearRetainedMessages.IsChecked == true) + { + storage.Clear(); + } + } + _mqttServer = new MqttFactory().CreateMqttServer(o => { o.DefaultEndpointOptions.Port = int.Parse(ServerPort.Text); + o.Storage = storage; }); await _mqttServer.StartAsync(); @@ -350,5 +376,10 @@ namespace MQTTnet.TestApp.UniversalWindows await _mqttServer.StopAsync(); _mqttServer = null; } + + private void ClearReceivedMessages(object sender, RoutedEventArgs e) + { + ReceivedMessages.Items.Clear(); + } } } From 0b002e8d11ca09913dbe6f90725e1c66e48f55c9 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Wed, 8 Nov 2017 15:26:31 +0100 Subject: [PATCH 026/149] Remove the RAW stream approach --- Build/MQTTnet.nuspec | 4 ++-- Build/build.ps1 | 5 +++-- .../Implementations/MqttServerAdapter.cs | 6 +++--- .../Implementations/MqttTcpChannel.Uwp.cs | 5 ----- .../Implementations/MqttTcpChannel.cs | 21 ++++++++----------- .../MQTTnet.Netstandard.csproj | 4 ++-- .../MqttChannelCommunicationAdapter.cs | 2 +- .../Channel/IMqttCommunicationChannel.cs | 1 - MQTTnet.Core/Client/MqttClient.cs | 6 +++--- MQTTnet.sln | 2 +- .../MQTTnet.TestApp.NetCore.csproj | 2 +- Tests/MQTTnet.TestApp.NetCore/Program.cs | 6 ++++++ .../MQTTnet.TestApp.UniversalWindows.csproj | 2 +- 13 files changed, 32 insertions(+), 34 deletions(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 2583897c..5fdc919a 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -68,8 +68,8 @@ - - + + \ No newline at end of file diff --git a/Build/build.ps1 b/Build/build.ps1 index e74f9f06..e7d86d70 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -8,10 +8,11 @@ $path = &$vswhere -latest -products * -requires Microsoft.Component.MSBuild -pro if ($path) { $msbuild = join-path $path 'MSBuild\15.0\Bin\MSBuild.exe' - &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net451" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m + &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m - &$msbuild ..\Frameworks\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m + + &$msbuild ..\Frameworks\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m Remove-Item .\NuGet -Force -Recurse New-Item -ItemType Directory -Force -Path .\NuGet diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs index 9d807b8b..f894233a 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs @@ -1,4 +1,4 @@ -#if NET451 || NETSTANDARD1_3 +#if NET452 || NETSTANDARD1_3 using System; using System.Net; using System.Net.Security; @@ -98,7 +98,7 @@ namespace MQTTnet.Implementations try { //todo: else branch can be used with min dependency NET46 -#if NET451 +#if NET452 var clientSocket = await Task.Factory.FromAsync(_defaultEndpointSocket.BeginAccept, _defaultEndpointSocket.EndAccept, null).ConfigureAwait(false); #else var clientSocket = await _defaultEndpointSocket.AcceptAsync().ConfigureAwait(false); @@ -122,7 +122,7 @@ namespace MQTTnet.Implementations { try { -#if NET451 +#if NET452 var clientSocket = await Task.Factory.FromAsync(_tlsEndpointSocket.BeginAccept, _tlsEndpointSocket.EndAccept, null).ConfigureAwait(false); #else var clientSocket = await _tlsEndpointSocket.AcceptAsync().ConfigureAwait(false); diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs index bd0614f5..06fa1377 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs @@ -32,7 +32,6 @@ namespace MQTTnet.Implementations public Stream SendStream { get; private set; } public Stream ReceiveStream { get; private set; } - public Stream RawReceiveStream { get; private set; } public static Func> CustomIgnorableServerCertificateErrorsResolver { get; set; } @@ -70,9 +69,6 @@ namespace MQTTnet.Implementations public void Dispose() { - RawReceiveStream?.Dispose(); - RawReceiveStream = null; - SendStream?.Dispose(); SendStream = null; @@ -87,7 +83,6 @@ namespace MQTTnet.Implementations { SendStream = _socket.OutputStream.AsStreamForWrite(); ReceiveStream = _socket.InputStream.AsStreamForRead(); - RawReceiveStream = ReceiveStream; } private static Certificate LoadCertificate(MqttClientTcpOptions options) diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs index 62bb8787..0d6180c7 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs @@ -1,5 +1,4 @@ -#if NET451 || NETSTANDARD1_3 - +#if NET452 || NETSTANDARD1_3 using System; using System.Net.Security; using System.Net.Sockets; @@ -18,7 +17,7 @@ namespace MQTTnet.Implementations private readonly MqttClientTcpOptions _options; //todo: this can be used with min dependency NetStandard1.6 -#if NET45 +#if NET452 // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global public static int BufferSize { get; set; } = 4096 * 20; // Can be changed for fine tuning by library user. @@ -49,7 +48,6 @@ namespace MQTTnet.Implementations public Stream SendStream { get; private set; } public Stream ReceiveStream { get; private set; } - public Stream RawReceiveStream { get; private set; } public static Func CustomCertificateValidationCallback { get; set; } @@ -61,7 +59,7 @@ namespace MQTTnet.Implementations } //todo: else brach can be used with min dependency NET46 -#if NET451 +#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); @@ -140,19 +138,18 @@ namespace MQTTnet.Implementations private void CreateStreams(Socket socket, Stream sslStream) { - RawReceiveStream = sslStream ?? new NetworkStream(socket); - + var stream = sslStream ?? new NetworkStream(socket); //cannot use this as default buffering prevents from receiving the first connect message //need two streams otherwise read and write have to be synchronized //todo: if branch can be used with min dependency NetStandard1.6 -#if NET45 - SendStream = new BufferedStream(RawReceiveStream, BufferSize); - ReceiveStream = new BufferedStream(RawReceiveStream, BufferSize); +#if NET452 + SendStream = new BufferedStream(stream, BufferSize); + ReceiveStream = new BufferedStream(stream, BufferSize); #else - SendStream = RawReceiveStream; - ReceiveStream = RawReceiveStream; + SendStream = stream; + ReceiveStream = stream; #endif } diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj index 37b7e137..f981d604 100644 --- a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -1,7 +1,7 @@  - netstandard1.3;net451;uap10.0 + netstandard1.3;net452;uap10.0 MQTTnet MQTTnet 2.5.0.0 @@ -18,7 +18,7 @@ false UAP,Version=v10.0 UAP - 10.0.15063.0 + 10.0.16299.0 10.0.10240.0 .NETCore v5.0 diff --git a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs index b31a870e..888539c5 100644 --- a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs +++ b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs @@ -144,7 +144,7 @@ namespace MQTTnet.Core.Adapter ReceivedMqttPacket receivedMqttPacket; if (timeout > TimeSpan.Zero) { - receivedMqttPacket = await ReceiveAsync(_channel.RawReceiveStream, cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false); + receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false); } else { diff --git a/MQTTnet.Core/Channel/IMqttCommunicationChannel.cs b/MQTTnet.Core/Channel/IMqttCommunicationChannel.cs index 8c746d1e..e7a74c18 100644 --- a/MQTTnet.Core/Channel/IMqttCommunicationChannel.cs +++ b/MQTTnet.Core/Channel/IMqttCommunicationChannel.cs @@ -7,7 +7,6 @@ namespace MQTTnet.Core.Channel { Stream SendStream { get; } Stream ReceiveStream { get; } - Stream RawReceiveStream { get; } Task ConnectAsync(); Task DisconnectAsync(); diff --git a/MQTTnet.Core/Client/MqttClient.cs b/MQTTnet.Core/Client/MqttClient.cs index a8e4eba9..5cc70cd1 100644 --- a/MQTTnet.Core/Client/MqttClient.cs +++ b/MQTTnet.Core/Client/MqttClient.cs @@ -60,8 +60,8 @@ namespace MQTTnet.Core.Client await _adapter.ConnectAsync(_options.CommunicationTimeout).ConfigureAwait(false); _logger.LogTrace("Connection with server established."); - await SetupIncomingPacketProcessingAsync(); - var connectResponse = await AuthenticateAsync(options.WillMessage); + await SetupIncomingPacketProcessingAsync().ConfigureAwait(false); + var connectResponse = await AuthenticateAsync(options.WillMessage).ConfigureAwait(false); _logger.LogTrace("MQTT connection with server established."); @@ -218,7 +218,7 @@ namespace MQTTnet.Core.Client while (!_isReceivingPackets && _cancellationTokenSource != null && !_cancellationTokenSource.IsCancellationRequested) { - await Task.Delay(TimeSpan.FromMilliseconds(100)); + await Task.Delay(TimeSpan.FromMilliseconds(100)).ConfigureAwait(false); } } diff --git a/MQTTnet.sln b/MQTTnet.sln index 2207c1f8..86fee978 100644 --- a/MQTTnet.sln +++ b/MQTTnet.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27004.2002 +VisualStudioVersion = 15.0.27004.2006 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Core.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Core.Tests.csproj", "{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}" EndProject diff --git a/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj b/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj index 4c0f99d2..c4a2bac2 100644 --- a/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj +++ b/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj @@ -3,7 +3,7 @@ Exe Full - netcoreapp2.0;net451 + netcoreapp2.0;net452 diff --git a/Tests/MQTTnet.TestApp.NetCore/Program.cs b/Tests/MQTTnet.TestApp.NetCore/Program.cs index 2e1d8c90..42830870 100644 --- a/Tests/MQTTnet.TestApp.NetCore/Program.cs +++ b/Tests/MQTTnet.TestApp.NetCore/Program.cs @@ -83,6 +83,12 @@ namespace MQTTnet.TestApp.NetCore public Task SaveRetainedMessagesAsync(IList messages) { + var directory = Path.GetDirectoryName(Filename); + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + File.WriteAllText(Filename, JsonConvert.SerializeObject(messages)); return Task.FromResult(0); } diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj index ce511d6c..fa0763c7 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj @@ -11,7 +11,7 @@ MQTTnet.TestApp.UniversalWindows en-US UAP - 10.0.15063.0 + 10.0.16299.0 10.0.15063.0 14 512 From 7dfc19e58826c58f64dac6c51757418bba244be5 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Wed, 8 Nov 2017 18:44:36 +0100 Subject: [PATCH 027/149] Added missing ConfigureAwaits --- .../MqttChannelCommunicationAdapter.cs | 2 +- MQTTnet.Core/Client/MqttClient.cs | 4 ++-- MQTTnet.Core/Diagnostics/MqttNetLogger.cs | 8 ++++++-- MQTTnet.Core/Diagnostics/MqttNetTrace.cs | 6 ++++-- .../Serializer/MqttPacketSerializer.cs | 19 ++++++++++-------- MQTTnet.Core/Serializer/MqttPacketWriter.cs | 6 +++--- .../MqttClientRetainedMessagesManager.cs | 4 ++-- MQTTnet.Core/Server/MqttClientSession.cs | 20 +++++++++---------- .../PerformanceTest.cs | 12 +++++++---- 9 files changed, 47 insertions(+), 34 deletions(-) diff --git a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs index 888539c5..f537c410 100644 --- a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs +++ b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs @@ -87,7 +87,7 @@ namespace MQTTnet.Core.Adapter { try { - await _semaphore.WaitAsync(cancellationToken); + await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); foreach (var packet in packets) { diff --git a/MQTTnet.Core/Client/MqttClient.cs b/MQTTnet.Core/Client/MqttClient.cs index 5cc70cd1..202cbc58 100644 --- a/MQTTnet.Core/Client/MqttClient.cs +++ b/MQTTnet.Core/Client/MqttClient.cs @@ -151,7 +151,7 @@ namespace MQTTnet.Core.Client case MqttQualityOfServiceLevel.AtMostOnce: { // No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier] - await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, qosPackets); + await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, qosPackets).ConfigureAwait(false); break; } case MqttQualityOfServiceLevel.AtLeastOnce: @@ -159,7 +159,7 @@ namespace MQTTnet.Core.Client foreach (var publishPacket in qosPackets) { publishPacket.PacketIdentifier = GetNewPacketIdentifier(); - await SendAndReceiveAsync(publishPacket); + await SendAndReceiveAsync(publishPacket).ConfigureAwait(false); } break; diff --git a/MQTTnet.Core/Diagnostics/MqttNetLogger.cs b/MQTTnet.Core/Diagnostics/MqttNetLogger.cs index 54ab6d44..32d96093 100644 --- a/MQTTnet.Core/Diagnostics/MqttNetLogger.cs +++ b/MQTTnet.Core/Diagnostics/MqttNetLogger.cs @@ -21,15 +21,19 @@ namespace MQTTnet.Core.Diagnostics throw new ArgumentNullException(nameof(formatter)); } - var message = formatter(state, exception); + if (!MqttNetTrace.HasListeners) + { + return; + } + var message = formatter(state, exception); var traceMessage = new MqttNetTraceMessage(DateTime.Now, Environment.CurrentManagedThreadId, _categoryName, logLevel, message, exception); _mqttNetTrace.Publish(traceMessage); } public bool IsEnabled(LogLevel logLevel) { - return true; + return MqttNetTrace.HasListeners; } //not supported: async local requires netstandard1.3 diff --git a/MQTTnet.Core/Diagnostics/MqttNetTrace.cs b/MQTTnet.Core/Diagnostics/MqttNetTrace.cs index c14d4931..f75c7a9b 100644 --- a/MQTTnet.Core/Diagnostics/MqttNetTrace.cs +++ b/MQTTnet.Core/Diagnostics/MqttNetTrace.cs @@ -10,9 +10,11 @@ namespace MQTTnet.Core.Diagnostics public static event EventHandler TraceMessagePublished; - public void Publish(MqttNetTraceMessage msg) + public static bool HasListeners => TraceMessagePublished != null; + + public void Publish(MqttNetTraceMessage traceMessage) { - TraceMessagePublished?.Invoke(this, new MqttNetTraceMessagePublishedEventArgs(msg)); + TraceMessagePublished?.Invoke(this, new MqttNetTraceMessagePublishedEventArgs(traceMessage)); } public void Dispose() diff --git a/MQTTnet.Core/Serializer/MqttPacketSerializer.cs b/MQTTnet.Core/Serializer/MqttPacketSerializer.cs index 00906f4a..6c2fc56a 100644 --- a/MQTTnet.Core/Serializer/MqttPacketSerializer.cs +++ b/MQTTnet.Core/Serializer/MqttPacketSerializer.cs @@ -24,15 +24,18 @@ namespace MQTTnet.Core.Serializer using (var stream = new MemoryStream()) using (var writer = new MqttPacketWriter(stream)) { - var header = new List { SerializePacket(packet, writer) }; - var body = stream.ToArray(); - MqttPacketWriter.BuildLengthHeader(body.Length, header); - var headerArray = header.ToArray(); - var writeBuffer = new byte[header.Count + body.Length]; - Buffer.BlockCopy(headerArray, 0, writeBuffer, 0, headerArray.Length); - Buffer.BlockCopy(body, 0, writeBuffer, headerArray.Length, body.Length); + var fixedHeader = SerializePacket(packet, writer); + var headerBuffer = new List { fixedHeader }; + MqttPacketWriter.WriteRemainingLength((int)stream.Length, headerBuffer); - return writeBuffer; + var header = headerBuffer.ToArray(); + var body = stream.ToArray(); + + var buffer = new byte[header.Length + body.Length]; + Buffer.BlockCopy(header, 0, buffer, 0, header.Length); + Buffer.BlockCopy(body, 0, buffer, header.Length, body.Length); + + return buffer; } } diff --git a/MQTTnet.Core/Serializer/MqttPacketWriter.cs b/MQTTnet.Core/Serializer/MqttPacketWriter.cs index d8c997d2..fcd883c3 100644 --- a/MQTTnet.Core/Serializer/MqttPacketWriter.cs +++ b/MQTTnet.Core/Serializer/MqttPacketWriter.cs @@ -56,11 +56,11 @@ namespace MQTTnet.Core.Serializer Write(value); } - public static void BuildLengthHeader(int length, List header) + public static void WriteRemainingLength(int length, List target) { if (length == 0) { - header.Add(0); + target.Add(0); return; } @@ -75,7 +75,7 @@ namespace MQTTnet.Core.Serializer encodedByte = encodedByte | 128; } - header.Add((byte)encodedByte); + target.Add((byte)encodedByte); } while (x > 0); } } diff --git a/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs b/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs index dbdb1d7a..ab1d4871 100644 --- a/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs +++ b/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs @@ -54,7 +54,7 @@ namespace MQTTnet.Core.Server { if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); - await _gate.WaitAsync(); + await _gate.WaitAsync().ConfigureAwait(false); try { var saveIsRequired = false; @@ -108,7 +108,7 @@ namespace MQTTnet.Core.Server { var retainedMessages = new List(); - await _gate.WaitAsync(); + await _gate.WaitAsync().ConfigureAwait(false); try { foreach (var retainedMessage in _retainedMessages.Values) diff --git a/MQTTnet.Core/Server/MqttClientSession.cs b/MQTTnet.Core/Server/MqttClientSession.cs index 9b14e587..fb859b8f 100644 --- a/MQTTnet.Core/Server/MqttClientSession.cs +++ b/MQTTnet.Core/Server/MqttClientSession.cs @@ -29,11 +29,11 @@ namespace MQTTnet.Core.Server private MqttApplicationMessage _willMessage; public MqttClientSession( - string clientId, + string clientId, IOptions options, MqttClientSessionsManager sessionsManager, MqttClientSubscriptionsManager subscriptionsManager, - ILogger logger, + ILogger logger, ILogger messageQueueLogger, IMqttClientRetainedMessageManager clientRetainedMessageManager) { @@ -65,7 +65,7 @@ namespace MQTTnet.Core.Server _cancellationTokenSource = new CancellationTokenSource(); _pendingMessagesQueue.Start(adapter, _cancellationTokenSource.Token); - await ReceivePacketsAsync(adapter, _cancellationTokenSource.Token); + await ReceivePacketsAsync(adapter, _cancellationTokenSource.Token).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -175,7 +175,7 @@ namespace MQTTnet.Core.Server { return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, _subscriptionsManager.Unsubscribe(unsubscribePacket)); } - + if (packet is MqttDisconnectPacket || packet is MqttConnectPacket) { Stop(); @@ -192,19 +192,19 @@ namespace MQTTnet.Core.Server { var subscribeResult = _subscriptionsManager.Subscribe(subscribePacket, ClientId); - await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, subscribeResult.ResponsePacket); - await EnqueueSubscribedRetainedMessagesAsync(subscribePacket); + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, subscribeResult.ResponsePacket).ConfigureAwait(false); + await EnqueueSubscribedRetainedMessagesAsync(subscribePacket).ConfigureAwait(false); if (subscribeResult.CloseConnection) { - await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttDisconnectPacket()); + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttDisconnectPacket()).ConfigureAwait(false); Stop(); } } private async Task EnqueueSubscribedRetainedMessagesAsync(MqttSubscribePacket subscribePacket) { - var retainedMessages = await _clientRetainedMessageManager.GetSubscribedMessagesAsync(subscribePacket); + var retainedMessages = await _clientRetainedMessageManager.GetSubscribedMessagesAsync(subscribePacket).ConfigureAwait(false); foreach (var publishPacket in retainedMessages) { EnqueuePublishPacket(publishPacket.ToPublishPacket()); @@ -225,7 +225,7 @@ namespace MQTTnet.Core.Server if (applicationMessage.Retain) { - await _clientRetainedMessageManager.HandleMessageAsync(ClientId, applicationMessage); + await _clientRetainedMessageManager.HandleMessageAsync(ClientId, applicationMessage).ConfigureAwait(false); } switch (applicationMessage.QualityOfServiceLevel) @@ -255,7 +255,7 @@ namespace MQTTnet.Core.Server _sessionsManager.DispatchApplicationMessage(this, applicationMessage); await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, - new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }); + new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }).ConfigureAwait(false); return; } diff --git a/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs b/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs index 6ef76682..e21a7ea3 100644 --- a/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs @@ -41,7 +41,7 @@ namespace MQTTnet.TestApp.NetCore .AddLogging() .BuildServiceProvider(); - services.GetService().AddConsole(LogLevel.Warning, true); + //services.GetService().AddConsole(LogLevel.Warning, true); Console.WriteLine("Press 'c' for concurrent sends. Otherwise in one batch."); var concurrent = Console.ReadKey(true).KeyChar == 'c'; @@ -120,11 +120,15 @@ namespace MQTTnet.TestApp.NetCore stopwatch.Stop(); Console.WriteLine($"Sent 10.000 messages within {stopwatch.ElapsedMilliseconds} ms ({stopwatch.ElapsedMilliseconds / (float)testMessageCount} ms / message)."); - stopwatch.Restart(); + + var messages = new[] { message }; var sentMessagesCount = 0; + + stopwatch.Restart(); + while (stopwatch.ElapsedMilliseconds < 1000) { - await client.PublishAsync(message); + await client.PublishAsync(messages).ConfigureAwait(false); sentMessagesCount++; } @@ -180,7 +184,7 @@ namespace MQTTnet.TestApp.NetCore { Topic = "A/B/C", Payload = Encoding.UTF8.GetBytes("Hello World"), - QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce + QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce }; } From 40dd620f90b3ae8ad11bc319e664045432dd3c20 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Wed, 8 Nov 2017 19:10:45 +0100 Subject: [PATCH 028/149] Refactoring --- MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs | 6 +++++- MQTTnet.Core/Adapter/ReceivedMqttPacket.cs | 7 ++++++- MQTTnet.Core/Serializer/MqttPacketWriter.cs | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs index f537c410..35573023 100644 --- a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs +++ b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs @@ -139,9 +139,9 @@ namespace MQTTnet.Core.Adapter public async Task ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken) { + ReceivedMqttPacket receivedMqttPacket = null; try { - ReceivedMqttPacket receivedMqttPacket; if (timeout > TimeSpan.Zero) { receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false); @@ -185,6 +185,10 @@ namespace MQTTnet.Core.Adapter { throw new MqttCommunicationException(exception); } + finally + { + receivedMqttPacket?.Dispose(); + } } private static async Task ReceiveAsync(Stream stream, CancellationToken cancellationToken) diff --git a/MQTTnet.Core/Adapter/ReceivedMqttPacket.cs b/MQTTnet.Core/Adapter/ReceivedMqttPacket.cs index f8adc2eb..f7fdbcc5 100644 --- a/MQTTnet.Core/Adapter/ReceivedMqttPacket.cs +++ b/MQTTnet.Core/Adapter/ReceivedMqttPacket.cs @@ -4,7 +4,7 @@ using MQTTnet.Core.Packets; namespace MQTTnet.Core.Adapter { - public class ReceivedMqttPacket + public sealed class ReceivedMqttPacket : IDisposable { public ReceivedMqttPacket(MqttPacketHeader header, MemoryStream body) { @@ -15,5 +15,10 @@ namespace MQTTnet.Core.Adapter public MqttPacketHeader Header { get; } public MemoryStream Body { get; } + + public void Dispose() + { + Body?.Dispose(); + } } } diff --git a/MQTTnet.Core/Serializer/MqttPacketWriter.cs b/MQTTnet.Core/Serializer/MqttPacketWriter.cs index fcd883c3..4c86f961 100644 --- a/MQTTnet.Core/Serializer/MqttPacketWriter.cs +++ b/MQTTnet.Core/Serializer/MqttPacketWriter.cs @@ -9,7 +9,7 @@ namespace MQTTnet.Core.Serializer public sealed class MqttPacketWriter : BinaryWriter { public MqttPacketWriter(Stream stream) - : base(stream) + : base(stream, Encoding.UTF8, true) { } From 522a38552310e911e605e7edf117872c07363cd9 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Wed, 8 Nov 2017 20:26:33 +0100 Subject: [PATCH 029/149] Add methods for client options builder --- .../Client/MqttClientOptionsBuilder.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs b/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs index 1eb2a347..b3525670 100644 --- a/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs +++ b/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using MQTTnet.Core.Serializer; namespace MQTTnet.Core.Client @@ -79,6 +80,24 @@ namespace MQTTnet.Core.Client return this; } + public MqttClientOptionsBuilder WithTls( + bool allowUntrustedCertificates = false, + bool ignoreCertificateChainErrors = false, + bool ignoreCertificateRevocationErrors = false, + params byte[][] certificates) + { + _tlsOptions = new MqttClientTlsOptions + { + UseTls = true, + AllowUntrustedCertificates = allowUntrustedCertificates, + IgnoreCertificateChainErrors = ignoreCertificateChainErrors, + IgnoreCertificateRevocationErrors = ignoreCertificateRevocationErrors, + Certificates = certificates.ToList() + }; + + return this; + } + public MqttClientOptionsBuilder WithTls() { _tlsOptions = new MqttClientTlsOptions From 1c78cd4c319464547543cf6a93030a7a62153607 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Wed, 8 Nov 2017 23:36:52 +0100 Subject: [PATCH 030/149] Update documentation --- .../Client/MqttClientOptionsBuilder.cs | 26 ++++--- .../MQTTnet.TestApp.UniversalWindows.csproj | 6 ++ .../MainPage.xaml.cs | 77 ++++++++++++++++--- 3 files changed, 90 insertions(+), 19 deletions(-) diff --git a/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs b/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs index b3525670..29a2d64f 100644 --- a/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs +++ b/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs @@ -12,15 +12,21 @@ namespace MQTTnet.Core.Client private MqttClientTlsOptions _tlsOptions; - public MqttClientOptionsBuilder WithProtocolVersion(MqttProtocolVersion protocolVersion) + public MqttClientOptionsBuilder WithLogId(string value) { - _options.ProtocolVersion = protocolVersion; + _options.LogId = value; return this; } - public MqttClientOptionsBuilder WithCommunicationTimeout(TimeSpan communicationTimeout) + public MqttClientOptionsBuilder WithProtocolVersion(MqttProtocolVersion value) { - _options.CommunicationTimeout = communicationTimeout; + _options.ProtocolVersion = value; + return this; + } + + public MqttClientOptionsBuilder WithCommunicationTimeout(TimeSpan value) + { + _options.CommunicationTimeout = value; return this; } @@ -30,21 +36,21 @@ namespace MQTTnet.Core.Client return this; } - public MqttClientOptionsBuilder WithKeepAlivePeriod(TimeSpan keepAlivePeriod) + public MqttClientOptionsBuilder WithKeepAlivePeriod(TimeSpan value) { - _options.KeepAlivePeriod = keepAlivePeriod; + _options.KeepAlivePeriod = value; return this; } - public MqttClientOptionsBuilder WithClientId(string clientId) + public MqttClientOptionsBuilder WithClientId(string value) { - _options.ClientId = clientId; + _options.ClientId = value; return this; } - public MqttClientOptionsBuilder WithWillMessage(MqttApplicationMessage applicationMessage) + public MqttClientOptionsBuilder WithWillMessage(MqttApplicationMessage value) { - _options.WillMessage = applicationMessage; + _options.WillMessage = value; return this; } diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj index fa0763c7..f8c1ce9d 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj @@ -137,6 +137,12 @@ + + 1.1.2 + + + 1.1.2 + 5.4.0 diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index bcea348e..47ee2586 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -5,6 +5,7 @@ using Windows.Security.Cryptography.Certificates; using Windows.UI.Core; using Windows.UI.Xaml; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using MQTTnet.Core; using MQTTnet.Core.Client; using MQTTnet.Core.Diagnostics; @@ -111,7 +112,7 @@ namespace MQTTnet.TestApp.UniversalWindows { ReceivedMessages.Items.Add(item); }); - + } private async void Publish(object sender, RoutedEventArgs e) @@ -227,16 +228,50 @@ namespace MQTTnet.TestApp.UniversalWindows private async Task WikiCode() { { - // Create a new MQTT client + // Write all trace messages to the console window. + MqttNetTrace.TraceMessagePublished += (s, e) => + { + Console.WriteLine($">> [{e.TraceMessage.Timestamp:O}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}"); + if (e.TraceMessage.Exception != null) + { + Console.WriteLine(e.TraceMessage.Exception); + } + }; + } + + { + // Add the console logger to the logger factory. var services = new ServiceCollection() .AddMqttClient() .BuildServiceProvider(); - var factory = new MqttFactory(services); - var client = factory.CreateMqttClient(); + services.GetRequiredService() + .AddConsole(); + } + + { + // Use a custom identifier for the trace messages. + var clientOptions = new MqttClientOptionsBuilder() + .WithLogId("ClientX") + .Build(); + } + + { + // Create a client from the service provider manually. + var serviceProvider = new ServiceCollection() + .AddMqttClient() + .BuildServiceProvider(); + + var mqttClient = serviceProvider.GetRequiredService(); + } + + { + // Create a new MQTT client. + var factory = new MqttFactory(); + var mqttClient = factory.CreateMqttClient(); { - // Create TCP based options using the builder + // Create TCP based options using the builder. var options = new MqttClientOptionsBuilder() .WithClientId("Client1") .WithTcpServer("broker.hivemq.com") @@ -245,7 +280,31 @@ namespace MQTTnet.TestApp.UniversalWindows .WithCleanSession() .Build(); - await client.ConnectAsync(options); + await mqttClient.ConnectAsync(options); + } + + { + // Use TCP connection. + var options = new MqttClientOptionsBuilder() + .WithTcpServer("broker.hivemq.com", 1883) // Port is optional + .Build(); + } + + { + // Use secure TCP connection. + var options = new MqttClientOptionsBuilder() + .WithTcpServer("broker.hivemq.com") + .WithTls() + .Build(); + } + + { + // Use WebSocket connection. + var options = new MqttClientOptionsBuilder() + .WithWebSocketServer("broker.hivemq.com:8000/mqtt") + .Build(); + + await mqttClient.ConnectAsync(options); } { @@ -271,10 +330,10 @@ namespace MQTTnet.TestApp.UniversalWindows { // Subscribe to a topic - await client.SubscribeAsync(new TopicFilterBuilder().WithTopic("my/topic").Build()); + await mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic("my/topic").Build()); // Unsubscribe from a topic - await client.UnsubscribeAsync("my/topic"); + await mqttClient.UnsubscribeAsync("my/topic"); // Publish an application message var applicationMessage = new MqttApplicationMessageBuilder() @@ -283,7 +342,7 @@ namespace MQTTnet.TestApp.UniversalWindows .WithAtLeastOnceQoS() .Build(); - await client.PublishAsync(applicationMessage); + await mqttClient.PublishAsync(applicationMessage); } } From eaf27c1e1268a9417d96fd4d8925969aaaf19fcb Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Thu, 9 Nov 2017 00:03:22 +0100 Subject: [PATCH 031/149] Update documentation --- MQTTnet.Core/Server/IMqttServer.cs | 1 - MQTTnet.Core/Server/MqttServer.cs | 1 - Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs | 10 ++-- Tests/MQTTnet.TestApp.NetCore/ServerTest.cs | 23 +++++-- .../MainPage.xaml.cs | 60 ++++++++++++++++++- 5 files changed, 84 insertions(+), 11 deletions(-) diff --git a/MQTTnet.Core/Server/IMqttServer.cs b/MQTTnet.Core/Server/IMqttServer.cs index 7d76c23c..71af0ee3 100644 --- a/MQTTnet.Core/Server/IMqttServer.cs +++ b/MQTTnet.Core/Server/IMqttServer.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using MQTTnet.Core.Client; namespace MQTTnet.Core.Server { diff --git a/MQTTnet.Core/Server/MqttServer.cs b/MQTTnet.Core/Server/MqttServer.cs index f5a9527c..1e05764c 100644 --- a/MQTTnet.Core/Server/MqttServer.cs +++ b/MQTTnet.Core/Server/MqttServer.cs @@ -6,7 +6,6 @@ using MQTTnet.Core.Adapter; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System.Linq; -using Microsoft.Extensions.DependencyInjection; namespace MQTTnet.Core.Server { diff --git a/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs b/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs index 18d121cf..d321fd1e 100644 --- a/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs +++ b/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs @@ -8,17 +8,19 @@ using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Logging; using MQTTnet.AspNetCore; using MQTTnet.Core; -using MQTTnet.Core.Client; namespace MQTTnet.TestApp.AspNetCore2 { public class Startup { + // In class _Startup_ of the ASP.NET Core 2.0 project. + public void ConfigureServices(IServiceCollection services) { services.AddHostedMqttServer(); } + // In class _Startup_ of the ASP.NET Core 2.0 project. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { app.UseMqttEndpoint(); @@ -49,11 +51,11 @@ namespace MQTTnet.TestApp.AspNetCore2 app.UseStaticFiles(); - app.UseStaticFiles( new StaticFileOptions() + app.UseStaticFiles(new StaticFileOptions { RequestPath = "/node_modules", - FileProvider = new PhysicalFileProvider( Path.Combine(env.ContentRootPath, "node_modules" ) ) - } ); + FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "node_modules")) + }); } } } diff --git a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs index 0a7d5575..f4a18cd5 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs @@ -35,14 +35,29 @@ namespace MQTTnet.TestApp.NetCore options.Storage = new RetainedMessageHandler(); + // Extend the timestamp for all messages from clients. options.ApplicationMessageInterceptor = context => { if (MqttTopicFilterComparer.IsMatch(context.ApplicationMessage.Topic, "/myTopic/WithTimestamp/#")) { - // Replace the payload with the timestamp. But also extending a JSON - // based payload with the timestamp is a suitable use case. - context.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O")); - } + // Replace the payload with the timestamp. But also extending a JSON + // based payload with the timestamp is a suitable use case. + context.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O")); + } + }; + // Protect several topics from being subscribed from every client. + options.SubscriptionsInterceptor = context => + { + if (context.TopicFilter.Topic.StartsWith("admin/foo/bar") && context.ClientId != "theAdmin") + { + context.AcceptSubscription = false; + } + + if (context.TopicFilter.Topic.StartsWith("the/secret/stuff") && context.ClientId != "Imperator") + { + context.AcceptSubscription = false; + context.CloseConnection = true; + } }; }); diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index 47ee2586..1a12f950 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -264,7 +264,7 @@ namespace MQTTnet.TestApp.UniversalWindows var mqttClient = serviceProvider.GetRequiredService(); } - + { // Create a new MQTT client. var factory = new MqttFactory(); @@ -396,6 +396,64 @@ namespace MQTTnet.TestApp.UniversalWindows return new ChainValidationResult[0]; }; + { + // Start a MQTT server. + var mqttServer = new MqttFactory().CreateMqttServer(); + await mqttServer.StartAsync(); + Console.WriteLine("Press any key to exit."); + Console.ReadLine(); + await mqttServer.StopAsync(); + } + + { + // Configure MQTT server. + var mqttServer = new MqttFactory().CreateMqttServer(options => + { + options.ConnectionBacklog = 100; + options.DefaultEndpointOptions.Port = 1884; + options.ConnectionValidator = packet => + { + if (packet.ClientId != "Highlander") + { + return MqttConnectReturnCode.ConnectionRefusedIdentifierRejected; + } + + return MqttConnectReturnCode.ConnectionAccepted; + }; + }); + } + + { + // Setup client validator. + var mqttServer = new MqttFactory().CreateMqttServer(options => + { + options.ConnectionValidator = c => + { + if (c.ClientId.Length < 10) + { + return MqttConnectReturnCode.ConnectionRefusedIdentifierRejected; + } + + if (c.Username != "mySecretUser") + { + return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; + } + + if (c.Password != "mySecretPassword") + { + return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; + } + + return MqttConnectReturnCode.ConnectionAccepted; + }; + }); + } + + { + // Create a new MQTT server. + var mqttServer = new MqttFactory().CreateMqttServer(); + } + } private async void StartServer(object sender, RoutedEventArgs e) From 587622af81c6e03e5972d9bf194405c9100e8943 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Thu, 9 Nov 2017 08:23:40 +0100 Subject: [PATCH 032/149] Refactoring --- Frameworks/MQTTnet.NetStandard/MqttFactory.cs | 28 +++++++++---------- .../MainPage.xaml.cs | 16 +++++++++++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs index 394374de..1729350c 100644 --- a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs @@ -16,20 +16,6 @@ namespace MQTTnet { private readonly IServiceProvider _serviceProvider; - private static IServiceProvider BuildServiceProvider() - { - var serviceProvider = new ServiceCollection() - .AddMqttClient() - .AddMqttServer() - .AddLogging() - .BuildServiceProvider(); - - serviceProvider.GetRequiredService() - .AddMqttTrace(); - - return serviceProvider; - } - public MqttFactory() : this(BuildServiceProvider()) { @@ -128,5 +114,19 @@ namespace MQTTnet return _serviceProvider.GetRequiredService(); } + + private static IServiceProvider BuildServiceProvider() + { + var serviceProvider = new ServiceCollection() + .AddMqttClient() + .AddMqttServer() + .AddLogging() + .BuildServiceProvider(); + + serviceProvider.GetRequiredService() + .AddMqttTrace(); + + return serviceProvider; + } } } \ No newline at end of file diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index 1a12f950..6ae711be 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging; using MQTTnet.Core; using MQTTnet.Core.Client; using MQTTnet.Core.Diagnostics; +using MQTTnet.Core.ManagedClient; using MQTTnet.Core.Protocol; using MQTTnet.Core.Server; using MQTTnet.Implementations; @@ -454,6 +455,21 @@ namespace MQTTnet.TestApp.UniversalWindows var mqttServer = new MqttFactory().CreateMqttServer(); } + { + // Setup and start a managed MQTT client. + var options = new ManagedMqttClientOptionsBuilder() + .WithAutoReconnectDelay(TimeSpan.FromSeconds(5)) + .WithClientOptions(new MqttClientOptionsBuilder() + .WithClientId("Client1") + .WithTcpServer("broker.hivemq.com") + .WithTls().Build()) + .Build(); + + var mqttClient = new MqttFactory().CreateManagedMqttClient(); + await mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic("my/topic").Build()); + await mqttClient.StartAsync(options); + } + } private async void StartServer(object sender, RoutedEventArgs e) From ad77dc0bea6067298b9fb44f0542e0e9d3da7133 Mon Sep 17 00:00:00 2001 From: Jan Eggers Date: Thu, 9 Nov 2017 10:22:44 +0100 Subject: [PATCH 033/149] improved server usage in aspnet so no exceptions are thrown on startup --- MQTTnet.Core/Server/IMqttServer.cs | 1 + MQTTnet.Core/Server/MqttServer.cs | 3 ++ .../Server/MqttServerStartedEventArgs.cs | 8 +++++ Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs | 36 ++++++++++++------- 4 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 MQTTnet.Core/Server/MqttServerStartedEventArgs.cs diff --git a/MQTTnet.Core/Server/IMqttServer.cs b/MQTTnet.Core/Server/IMqttServer.cs index 71af0ee3..13c614fc 100644 --- a/MQTTnet.Core/Server/IMqttServer.cs +++ b/MQTTnet.Core/Server/IMqttServer.cs @@ -8,6 +8,7 @@ namespace MQTTnet.Core.Server { event EventHandler ClientConnected; event EventHandler ClientDisconnected; + event EventHandler Started; IList GetConnectedClients(); void Publish(IEnumerable applicationMessages); diff --git a/MQTTnet.Core/Server/MqttServer.cs b/MQTTnet.Core/Server/MqttServer.cs index 1e05764c..bd06a3a6 100644 --- a/MQTTnet.Core/Server/MqttServer.cs +++ b/MQTTnet.Core/Server/MqttServer.cs @@ -49,6 +49,7 @@ namespace MQTTnet.Core.Server return _clientSessionsManager.GetConnectedClients(); } + public event EventHandler Started; public event EventHandler ClientConnected; public event EventHandler ClientDisconnected; public event EventHandler ApplicationMessageReceived; @@ -96,6 +97,8 @@ namespace MQTTnet.Core.Server } _logger.LogInformation("Started."); + + Started?.Invoke(this, new MqttServerStartedEventArgs()); } public async Task StopAsync() diff --git a/MQTTnet.Core/Server/MqttServerStartedEventArgs.cs b/MQTTnet.Core/Server/MqttServerStartedEventArgs.cs new file mode 100644 index 00000000..8f46bde8 --- /dev/null +++ b/MQTTnet.Core/Server/MqttServerStartedEventArgs.cs @@ -0,0 +1,8 @@ +using System; + +namespace MQTTnet.Core.Server +{ + public class MqttServerStartedEventArgs : EventArgs + { + } +} diff --git a/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs b/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs index d321fd1e..55c57a18 100644 --- a/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs +++ b/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs @@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; -using Microsoft.Extensions.Logging; using MQTTnet.AspNetCore; using MQTTnet.Core; @@ -21,21 +20,34 @@ namespace MQTTnet.TestApp.AspNetCore2 } // In class _Startup_ of the ASP.NET Core 2.0 project. - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseMqttEndpoint(); - app.UseMqttServer(async server => + app.UseMqttServer(server => { - var msg = new MqttApplicationMessageBuilder() - .WithPayload("Mqtt is awesome") - .WithTopic("message"); - - while (true) + server.Started += async (sender, args) => { - server.PublishAsync(msg.Build()).Wait(); - await Task.Delay(TimeSpan.FromSeconds(2)); - msg.WithPayload("Mqtt is still awesome at " + DateTime.Now); - } + var msg = new MqttApplicationMessageBuilder() + .WithPayload("Mqtt is awesome") + .WithTopic("message"); + + while (true) + { + try + { + await server.PublishAsync(msg.Build()); + msg.WithPayload("Mqtt is still awesome at " + DateTime.Now); + } + catch (Exception e) + { + Console.WriteLine(e); + } + finally + { + await Task.Delay(TimeSpan.FromSeconds(2)); + } + } + }; }); app.Use((context, next) => From 683d97dc14baa4b03f4d89272aaf3bfe3f3d9585 Mon Sep 17 00:00:00 2001 From: Jan Eggers Date: Thu, 9 Nov 2017 10:24:49 +0100 Subject: [PATCH 034/149] added another platform to overcome breaking change in ms.extensions.di 2.0.0 --- Build/MQTTnet.nuspec | 15 ++++++++++++ Build/build.ps1 | 1 + .../Implementations/MqttServerAdapter.cs | 2 +- .../Implementations/MqttTcpChannel.cs | 2 +- .../MQTTnet.Netstandard.csproj | 23 ++++++++++++++++--- .../MQTTnet.Core.Tests.csproj | 2 -- .../MQTTnet.TestApp.NetCore.csproj | 2 -- 7 files changed, 38 insertions(+), 9 deletions(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 5fdc919a..3f26a870 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -41,6 +41,17 @@ + + + + + + + + + + + @@ -62,6 +73,10 @@ + + + + diff --git a/Build/build.ps1 b/Build/build.ps1 index e7d86d70..3efa1577 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -10,6 +10,7 @@ if ($path) { &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m + &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m &$msbuild ..\Frameworks\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs index f894233a..a6e6251e 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs @@ -1,4 +1,4 @@ -#if NET452 || NETSTANDARD1_3 +#if NET452 || NETSTANDARD1_3 || NETSTANDARD2_0 using System; using System.Net; using System.Net.Security; diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs index 0d6180c7..2bf418bc 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs @@ -1,4 +1,4 @@ -#if NET452 || NETSTANDARD1_3 +#if NET452 || NETSTANDARD1_3 || NETSTANDARD2_0 using System; using System.Net.Security; using System.Net.Sockets; diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj index f981d604..266864d1 100644 --- a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -1,7 +1,7 @@  - netstandard1.3;net452;uap10.0 + netstandard1.3;netstandard2.0;net452;uap10.0 MQTTnet MQTTnet 2.5.0.0 @@ -32,23 +32,40 @@ - - + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/MQTTnet.Core.Tests/MQTTnet.Core.Tests.csproj b/Tests/MQTTnet.Core.Tests/MQTTnet.Core.Tests.csproj index 802d96d8..88ffbe41 100644 --- a/Tests/MQTTnet.Core.Tests/MQTTnet.Core.Tests.csproj +++ b/Tests/MQTTnet.Core.Tests/MQTTnet.Core.Tests.csproj @@ -7,7 +7,6 @@ - @@ -15,7 +14,6 @@ - \ No newline at end of file diff --git a/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj b/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj index c4a2bac2..80d6a260 100644 --- a/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj +++ b/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj @@ -7,13 +7,11 @@
- - From b6cd4638b9871af7a9bbff74bac0afd6bc3e747a Mon Sep 17 00:00:00 2001 From: Jan Eggers Date: Thu, 9 Nov 2017 10:40:05 +0100 Subject: [PATCH 035/149] fixed another retain msg test timing issue --- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 39 +++++++++++++-------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index b7098353..fc252678 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -9,6 +9,7 @@ using MQTTnet.Core.Client; using MQTTnet.Core.Protocol; using MQTTnet.Core.Server; using Microsoft.Extensions.DependencyInjection; +using MQTTnet.Core.Internal; using MQTTnet.Core.Packets; namespace MQTTnet.Core.Tests @@ -212,7 +213,6 @@ namespace MQTTnet.Core.Tests .BuildServiceProvider(); var s = new MqttFactory(services).CreateMqttServer(); - var retainMessagemanager = services.GetRequiredService(); var receivedMessagesCount = 0; try @@ -223,19 +223,7 @@ namespace MQTTnet.Core.Tests await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build()); await c1.DisconnectAsync(); - var subscribe = new MqttSubscribePacket() - { - TopicFilters = new List() - { - new TopicFilter("retained", MqttQualityOfServiceLevel.AtMostOnce) - } - }; - - //make shure the retainedMessageManagerreceived the package - while (!(await retainMessagemanager.GetSubscribedMessagesAsync(subscribe)).Any()) - { - await Task.Delay(TimeSpan.FromMilliseconds(10)); - } + await services.WaitForRetainedMessage("retained").TimeoutAfter(TimeSpan.FromSeconds(5)); var c2 = await serverAdapter.ConnectTestClient(s, "c2"); c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++; @@ -314,6 +302,8 @@ namespace MQTTnet.Core.Tests await s.StopAsync(); } + await services.WaitForRetainedMessage("retained").TimeoutAfter(TimeSpan.FromSeconds(5)); + s = new MqttFactory(services).CreateMqttServer(options => options.Storage = storage); var receivedMessagesCount = 0; @@ -436,4 +426,25 @@ namespace MQTTnet.Core.Tests Assert.AreEqual(expectedReceivedMessagesCount, receivedMessagesCount); } } + + public static class TestExtensions + { + public static async Task WaitForRetainedMessage(this IServiceProvider services, string topic) + { + var retainMessagemanager = services.GetRequiredService(); + + var subscribe = new MqttSubscribePacket() + { + TopicFilters = new List() + { + new TopicFilter(topic, MqttQualityOfServiceLevel.AtMostOnce) + } + }; + + while (!(await retainMessagemanager.GetSubscribedMessagesAsync(subscribe)).Any()) + { + await Task.Delay(TimeSpan.FromMilliseconds(10)); + } + } + } } From acbf9153f43b96c956e28bf41a6bf05cfa4da7a4 Mon Sep 17 00:00:00 2001 From: Jan Eggers Date: Thu, 9 Nov 2017 11:06:50 +0100 Subject: [PATCH 036/149] fixed the other timing issue --- MQTTnet.Core/Server/MqttClientSession.cs | 6 ++++-- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/MQTTnet.Core/Server/MqttClientSession.cs b/MQTTnet.Core/Server/MqttClientSession.cs index fb859b8f..cbdfc73f 100644 --- a/MQTTnet.Core/Server/MqttClientSession.cs +++ b/MQTTnet.Core/Server/MqttClientSession.cs @@ -94,9 +94,11 @@ namespace MQTTnet.Core.Server } finally { - if (_willMessage != null) + var willMessage = _willMessage; + if (willMessage != null) { - _sessionsManager.DispatchApplicationMessage(this, _willMessage); + _willMessage = null; //clear willmessage so it is send just once + _sessionsManager.DispatchApplicationMessage(this, willMessage); } } } diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index fc252678..7fdaa3d3 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -76,6 +76,8 @@ namespace MQTTnet.Core.Tests await c2.DisconnectAsync(); await Task.Delay(1000); + + await c1.DisconnectAsync(); } finally { From c01edb192ff65e659b1c3d53e44f59aa953a4bd5 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Thu, 9 Nov 2017 13:26:03 +0100 Subject: [PATCH 037/149] Refactoring --- Build/MQTTnet.nuspec | 19 ++----------------- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 4 +++- .../TestMqttCommunicationAdapter.cs | 4 ++-- ...=> TestMqttCommunicationAdapterFactory.cs} | 4 ++-- .../TestMqttServerAdapter.cs | 8 +++++--- 5 files changed, 14 insertions(+), 25 deletions(-) rename Tests/MQTTnet.Core.Tests/{MqttCommunicationAdapterFactory.cs => TestMqttCommunicationAdapterFactory.cs} (76%) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 5fdc919a..62630c12 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -2,7 +2,7 @@ MQTTnet - 2.5.0 + 2.5.1 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,22 +10,7 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * [Core] Merged the platform specific projects (Thanks to @JanEggers) -* [Core] Migrated the trace to a non-static approach (Breaking Change!) -* [Core] Added a builder for application messages using a fluent API -* [Core] Introduced CI and DI (Thanks to @JanEggers) -* [Core] Added interfaces for publishing and receiving which applies to every client and server (Thanks to @ChristianRiedl) -* [Core] Fixed an issue when reading from closed streams -* [Client] Added a first version of a managed client which will manage the connection, subscription etc. automatically (Thanks to @JTrotta) -* [Client] The session state response from the server is now returned in the _ConnectAsync_ method and also part of the _Connected_ event args -* [Client] Added a _TopicFilterBuilder_ using a fluent API (Namespace Changes!) -* [Client] Added several new options for the WebSocket channel (Thanks to @ChristianRiedl) -* [Client] Refactored the options and added a builder using a fluent API (Breaking Change!) -* [Client] Added more options for WebSocket connections like RequestHeaders, SubProtocol etc. -* [Server] Added support for WebSockets via ASP.NET Core 2.0 (additional nuget) (Thanks to @ChristianRiedl, @JanEggers) -* [Server] Added support for a custom application message interceptor -* [Server] Fixed an issue with dropped connections on UWP (Thanks to @haeberle) -* [Server] Added support for a custom subscription interceptor which allows denying of subscriptions and closing the connection + * Copyright Christian Kratky 2016-2017 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/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index b7098353..fa826c55 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -53,6 +53,7 @@ namespace MQTTnet.Core.Tests public async Task MqttServer_WillMessage() { var serverAdapter = new TestMqttServerAdapter(); + var services = new ServiceCollection() .AddLogging() .AddMqttServer() @@ -70,7 +71,7 @@ namespace MQTTnet.Core.Tests var c2 = await serverAdapter.ConnectTestClient(s, "c2", willMessage); c1.ApplicationMessageReceived += (_, __) => receivedMessagesCount++; - await c1.SubscribeAsync(new TopicFilter("#", MqttQualityOfServiceLevel.AtMostOnce)); + await c1.SubscribeAsync(new TopicFilter("#")); await c2.DisconnectAsync(); @@ -80,6 +81,7 @@ namespace MQTTnet.Core.Tests { await s.StopAsync(); } + Assert.AreEqual(1, receivedMessagesCount); } diff --git a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs index 9e71f8a4..ecde0f14 100644 --- a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs +++ b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs @@ -33,7 +33,7 @@ namespace MQTTnet.Core.Tests foreach (var packet in packets) { - Partner.SendPacketInternal(packet); + Partner.EnqueuePacketInternal(packet); } return Task.FromResult(0); @@ -46,7 +46,7 @@ namespace MQTTnet.Core.Tests return Task.Run(() => _incomingPackets.Take(), cancellationToken); } - private void SendPacketInternal(MqttBasePacket packet) + private void EnqueuePacketInternal(MqttBasePacket packet) { if (packet == null) throw new ArgumentNullException(nameof(packet)); diff --git a/Tests/MQTTnet.Core.Tests/MqttCommunicationAdapterFactory.cs b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs similarity index 76% rename from Tests/MQTTnet.Core.Tests/MqttCommunicationAdapterFactory.cs rename to Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs index 0e56411c..4a0acadd 100644 --- a/Tests/MQTTnet.Core.Tests/MqttCommunicationAdapterFactory.cs +++ b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs @@ -4,11 +4,11 @@ using MQTTnet.Core.Client; namespace MQTTnet.Core.Tests { - public class MqttCommunicationAdapterFactory : IMqttCommunicationAdapterFactory + public class TestMqttCommunicationAdapterFactory : IMqttCommunicationAdapterFactory { private readonly IMqttCommunicationAdapter _adapter; - public MqttCommunicationAdapterFactory(IMqttCommunicationAdapter adapter) + public TestMqttCommunicationAdapterFactory(IMqttCommunicationAdapter adapter) { _adapter = adapter; } diff --git a/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs b/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs index 067d08fd..cac3b1c0 100644 --- a/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs +++ b/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs @@ -17,7 +17,11 @@ namespace MQTTnet.Core.Tests adapterA.Partner = adapterB; adapterB.Partner = adapterA; - var client = new MqttClient(new MqttCommunicationAdapterFactory(adapterA), new TestLogger(), new MqttPacketDispatcher(new TestLogger())); + var client = new MqttClient( + new TestMqttCommunicationAdapterFactory(adapterA), + new TestLogger(), + new MqttPacketDispatcher(new TestLogger())); + var connected = WaitForClientToConnect(server, clientId); FireClientAcceptedEvent(adapterB); @@ -29,8 +33,6 @@ namespace MQTTnet.Core.Tests ChannelOptions = new MqttClientTcpOptions() }; - options.ChannelOptions = new MqttClientTcpOptions(); - await client.ConnectAsync(options); await connected; From 3625363fcfb5bef40c84ee5b75647d381adf654a Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sat, 11 Nov 2017 13:17:54 +0100 Subject: [PATCH 038/149] Fix references. Fix certificate handing issue --- Build/MQTTnet.AspNetCore.nuspec | 6 +++--- Build/MQTTnet.nuspec | 7 ++++--- MQTTnet.Core/Client/MqttClientOptionsBuilder.cs | 2 +- MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs | 5 +++++ MQTTnet.Core/Server/MqttClientSession.cs | 8 +++++--- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index 9cf4005e..30717332 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -2,7 +2,7 @@ MQTTnet.AspNetCore - 2.5.0 + 2.5.1 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,13 +10,13 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false This is a support library to integrate MQTTnet into AspNetCore. - initial version + * Updated to MQTTnet 2.5.1. Copyright Christian Kratky 2016-2017 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/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 771f5365..348ca796 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -10,14 +10,15 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * + * Fixed several library reference issues. +* [Client] Fixed issue in _MqttClientOptionsBuilder_ when using no certificates (Thanks to 1iveowl). Copyright Christian Kratky 2016-2017 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 - + @@ -45,7 +46,7 @@ - + diff --git a/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs b/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs index 29a2d64f..fb18cc09 100644 --- a/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs +++ b/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs @@ -98,7 +98,7 @@ namespace MQTTnet.Core.Client AllowUntrustedCertificates = allowUntrustedCertificates, IgnoreCertificateChainErrors = ignoreCertificateChainErrors, IgnoreCertificateRevocationErrors = ignoreCertificateRevocationErrors, - Certificates = certificates.ToList() + Certificates = certificates?.ToList() }; return this; diff --git a/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs b/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs index 6b370db6..1e0fc760 100644 --- a/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs +++ b/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs @@ -28,6 +28,11 @@ namespace MQTTnet.Core.Server { if (adapter == null) throw new ArgumentNullException(nameof(adapter)); + if (cancellationToken.IsCancellationRequested) + { + return; + } + Task.Run(async () => await SendPendingPublishPacketsAsync(adapter, cancellationToken), cancellationToken).ConfigureAwait(false); } diff --git a/MQTTnet.Core/Server/MqttClientSession.cs b/MQTTnet.Core/Server/MqttClientSession.cs index cbdfc73f..93b422ff 100644 --- a/MQTTnet.Core/Server/MqttClientSession.cs +++ b/MQTTnet.Core/Server/MqttClientSession.cs @@ -60,12 +60,14 @@ namespace MQTTnet.Core.Server try { + var cancellationTokenSource = new CancellationTokenSource(); + _willMessage = willMessage; _adapter = adapter; - _cancellationTokenSource = new CancellationTokenSource(); + _cancellationTokenSource = cancellationTokenSource; - _pendingMessagesQueue.Start(adapter, _cancellationTokenSource.Token); - await ReceivePacketsAsync(adapter, _cancellationTokenSource.Token).ConfigureAwait(false); + _pendingMessagesQueue.Start(adapter, cancellationTokenSource.Token); + await ReceivePacketsAsync(adapter, cancellationTokenSource.Token).ConfigureAwait(false); } catch (OperationCanceledException) { From 0844abd7e568fd38ffa5464d964b5e089b53abe2 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sat, 11 Nov 2017 13:23:11 +0100 Subject: [PATCH 039/149] Fix wrong version in nuget --- Build/MQTTnet.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 348ca796..2e56aa32 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -18,7 +18,7 @@ - + From afd56a7f6fdc9d54119b48484db58dfa1975f794 Mon Sep 17 00:00:00 2001 From: JanEggers Date: Sun, 12 Nov 2017 09:22:17 +0100 Subject: [PATCH 040/149] added indication of what Mqtt TargetFramework is used --- .../TargetFrameworkInfoProvider.cs | 23 +++++++++++++++++++ .../MQTTnet.TestApp.NetCore.csproj | 2 +- Tests/MQTTnet.TestApp.NetCore/Program.cs | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 Frameworks/MQTTnet.NetStandard/TargetFrameworkInfoProvider.cs diff --git a/Frameworks/MQTTnet.NetStandard/TargetFrameworkInfoProvider.cs b/Frameworks/MQTTnet.NetStandard/TargetFrameworkInfoProvider.cs new file mode 100644 index 00000000..22369d9c --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/TargetFrameworkInfoProvider.cs @@ -0,0 +1,23 @@ +namespace MQTTnet +{ + public static class TargetFrameworkInfoProvider + { + public static string TargetFramework + { + get + { +#if NET452 + return "net452"; +#elif NET461 + return "net461"; +#elif NETSTANDARD1_3 + return "netstandard1.3"; +#elif NETSTANDARD2_0 + return "netstandard2.0"; +#elif WINDOWS_UWP + return "uap10.0"; +#endif + } + } + } +} \ No newline at end of file diff --git a/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj b/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj index 80d6a260..d89bdd31 100644 --- a/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj +++ b/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj @@ -3,7 +3,7 @@ Exe Full - netcoreapp2.0;net452 + netcoreapp2.0;net452;net461 diff --git a/Tests/MQTTnet.TestApp.NetCore/Program.cs b/Tests/MQTTnet.TestApp.NetCore/Program.cs index 42830870..d1c010fe 100644 --- a/Tests/MQTTnet.TestApp.NetCore/Program.cs +++ b/Tests/MQTTnet.TestApp.NetCore/Program.cs @@ -15,7 +15,7 @@ namespace MQTTnet.TestApp.NetCore { public static void Main() { - Console.WriteLine("MQTTnet - TestApp.NetFramework"); + Console.WriteLine($"MQTTnet - TestApp.{TargetFrameworkInfoProvider.TargetFramework}"); Console.WriteLine("1 = Start client"); Console.WriteLine("2 = Start server"); Console.WriteLine("3 = Start performance test"); From bc9757576090b16d7117c4271dc2d434f6ac6ba5 Mon Sep 17 00:00:00 2001 From: JanEggers Date: Sun, 12 Nov 2017 12:28:55 +0100 Subject: [PATCH 041/149] downgrade dependencies to be netstandard 1.3 compliant and remove net461 shim requirement --- Build/MQTTnet.nuspec | 14 +++++++------- .../MQTTnet.NetStandard/MQTTnet.Netstandard.csproj | 8 ++++---- MQTTnet.Core/MQTTnet.Core.csproj | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 2e56aa32..1b01bfdf 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -18,10 +18,10 @@ - - - - + + + + @@ -47,9 +47,9 @@ - - - + + + diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj index 266864d1..19d1ce05 100644 --- a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -53,8 +53,8 @@ - - + + @@ -64,8 +64,8 @@ - - + + \ No newline at end of file diff --git a/MQTTnet.Core/MQTTnet.Core.csproj b/MQTTnet.Core/MQTTnet.Core.csproj index 71a518d5..522b3fb8 100644 --- a/MQTTnet.Core/MQTTnet.Core.csproj +++ b/MQTTnet.Core/MQTTnet.Core.csproj @@ -23,8 +23,8 @@ - - + + From 5cbbfedcce237d286ed18a7515037377d99a7b93 Mon Sep 17 00:00:00 2001 From: JanEggers Date: Sun, 12 Nov 2017 12:33:56 +0100 Subject: [PATCH 042/149] added testproject for importing mqtt nugets and verify bin folder --- MQTTnet.sln | 21 ++++++++++++++++++- .../MQTTnet.Test.NugetConsumption.csproj | 12 +++++++++++ .../MQTTnet.Test.NugetConsumption/Program.cs | 12 +++++++++++ .../nuget.config | 15 +++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 Tests/MQTTnet.Test.NugetConsumption/MQTTnet.Test.NugetConsumption.csproj create mode 100644 Tests/MQTTnet.Test.NugetConsumption/Program.cs create mode 100644 Tests/MQTTnet.Test.NugetConsumption/nuget.config diff --git a/MQTTnet.sln b/MQTTnet.sln index 86fee978..1aeecd64 100644 --- a/MQTTnet.sln +++ b/MQTTnet.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27004.2006 +VisualStudioVersion = 15.0.27004.2008 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Core.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Core.Tests.csproj", "{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}" EndProject @@ -35,6 +35,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.TestApp.AspNetCore2 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.AspNetCore", "Frameworks\MQTTnet.AspnetCore\MQTTnet.AspNetCore.csproj", "{F10C4060-F7EE-4A83-919F-FF723E72F94A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Test.NugetConsumption", "Tests\MQTTnet.Test.NugetConsumption\MQTTnet.Test.NugetConsumption.csproj", "{21AD2970-A8C7-4689-A35B-88082AFDABF8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -165,6 +167,22 @@ Global {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 + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|ARM.ActiveCfg = Debug|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|ARM.Build.0 = Debug|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|x64.ActiveCfg = Debug|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|x64.Build.0 = Debug|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|x86.ActiveCfg = Debug|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|x86.Build.0 = Debug|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|Any CPU.Build.0 = Release|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|ARM.ActiveCfg = Release|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|ARM.Build.0 = Release|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|x64.ActiveCfg = Release|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|x64.Build.0 = Release|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|x86.ActiveCfg = Release|Any CPU + {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -176,6 +194,7 @@ Global {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} + {21AD2970-A8C7-4689-A35B-88082AFDABF8} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {07536672-5CBC-4BE3-ACE0-708A431A7894} diff --git a/Tests/MQTTnet.Test.NugetConsumption/MQTTnet.Test.NugetConsumption.csproj b/Tests/MQTTnet.Test.NugetConsumption/MQTTnet.Test.NugetConsumption.csproj new file mode 100644 index 00000000..3844ef83 --- /dev/null +++ b/Tests/MQTTnet.Test.NugetConsumption/MQTTnet.Test.NugetConsumption.csproj @@ -0,0 +1,12 @@ + + + + Exe + netcoreapp2.0;net452;net461 + + + + + + + diff --git a/Tests/MQTTnet.Test.NugetConsumption/Program.cs b/Tests/MQTTnet.Test.NugetConsumption/Program.cs new file mode 100644 index 00000000..09ff6c95 --- /dev/null +++ b/Tests/MQTTnet.Test.NugetConsumption/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace MQTTnet.Test.NugetConsumption +{ + class Program + { + static void Main(string[] args) + { + var server = new MqttFactory().CreateMqttServer(); + } + } +} diff --git a/Tests/MQTTnet.Test.NugetConsumption/nuget.config b/Tests/MQTTnet.Test.NugetConsumption/nuget.config new file mode 100644 index 00000000..65d399f1 --- /dev/null +++ b/Tests/MQTTnet.Test.NugetConsumption/nuget.config @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file From bdadfa1c264f6ddf6e787a35868af4da80b97394 Mon Sep 17 00:00:00 2001 From: JanEggers Date: Sun, 12 Nov 2017 14:07:33 +0100 Subject: [PATCH 043/149] added net461 build --- Build/MQTTnet.nuspec | 9 +++++++++ Build/build.ps1 | 1 + .../Implementations/MqttServerAdapter.cs | 6 +++--- .../Implementations/MqttTcpChannel.cs | 8 ++++---- .../MQTTnet.Netstandard.csproj | 8 +++++++- .../MQTTnet.Test.NugetConsumption.csproj | 2 +- Tests/MQTTnet.Test.NugetConsumption/nuget.config | 15 --------------- 7 files changed, 25 insertions(+), 24 deletions(-) delete mode 100644 Tests/MQTTnet.Test.NugetConsumption/nuget.config diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 1b01bfdf..453c3522 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -52,6 +52,12 @@ + + + + + + @@ -71,6 +77,9 @@ + + + \ No newline at end of file diff --git a/Build/build.ps1 b/Build/build.ps1 index 3efa1577..1e47727c 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -9,6 +9,7 @@ if ($path) { $msbuild = join-path $path 'MSBuild\15.0\Bin\MSBuild.exe' &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m + &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs index a6e6251e..e3f048db 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs @@ -1,4 +1,4 @@ -#if NET452 || NETSTANDARD1_3 || NETSTANDARD2_0 +#if NET452 || NET461 || NETSTANDARD1_3 || NETSTANDARD2_0 using System; using System.Net; using System.Net.Security; @@ -98,7 +98,7 @@ namespace MQTTnet.Implementations try { //todo: else branch can be used with min dependency NET46 -#if NET452 +#if NET452 || NET461 var clientSocket = await Task.Factory.FromAsync(_defaultEndpointSocket.BeginAccept, _defaultEndpointSocket.EndAccept, null).ConfigureAwait(false); #else var clientSocket = await _defaultEndpointSocket.AcceptAsync().ConfigureAwait(false); @@ -122,7 +122,7 @@ namespace MQTTnet.Implementations { try { -#if NET452 +#if NET452 || NET461 var clientSocket = await Task.Factory.FromAsync(_tlsEndpointSocket.BeginAccept, _tlsEndpointSocket.EndAccept, null).ConfigureAwait(false); #else var clientSocket = await _tlsEndpointSocket.AcceptAsync().ConfigureAwait(false); diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs index 2bf418bc..a7e40268 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs @@ -1,4 +1,4 @@ -#if NET452 || NETSTANDARD1_3 || NETSTANDARD2_0 +#if NET452 || NET461 || NETSTANDARD1_3 || NETSTANDARD2_0 using System; using System.Net.Security; using System.Net.Sockets; @@ -17,7 +17,7 @@ namespace MQTTnet.Implementations private readonly MqttClientTcpOptions _options; //todo: this can be used with min dependency NetStandard1.6 -#if NET452 +#if NET452 || NET461 // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global public static int BufferSize { get; set; } = 4096 * 20; // Can be changed for fine tuning by library user. @@ -59,7 +59,7 @@ namespace MQTTnet.Implementations } //todo: else brach can be used with min dependency NET46 -#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); @@ -144,7 +144,7 @@ namespace MQTTnet.Implementations //need two streams otherwise read and write have to be synchronized //todo: if branch can be used with min dependency NetStandard1.6 -#if NET452 +#if NET452 || NET461 SendStream = new BufferedStream(stream, BufferSize); ReceiveStream = new BufferedStream(stream, BufferSize); #else diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj index 19d1ce05..41c30d39 100644 --- a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -1,7 +1,7 @@  - netstandard1.3;netstandard2.0;net452;uap10.0 + netstandard1.3;netstandard2.0;net452;net461;uap10.0 MQTTnet MQTTnet 2.5.0.0 @@ -68,4 +68,10 @@ + + + + + + \ No newline at end of file diff --git a/Tests/MQTTnet.Test.NugetConsumption/MQTTnet.Test.NugetConsumption.csproj b/Tests/MQTTnet.Test.NugetConsumption/MQTTnet.Test.NugetConsumption.csproj index 3844ef83..53680050 100644 --- a/Tests/MQTTnet.Test.NugetConsumption/MQTTnet.Test.NugetConsumption.csproj +++ b/Tests/MQTTnet.Test.NugetConsumption/MQTTnet.Test.NugetConsumption.csproj @@ -6,7 +6,7 @@ - + diff --git a/Tests/MQTTnet.Test.NugetConsumption/nuget.config b/Tests/MQTTnet.Test.NugetConsumption/nuget.config deleted file mode 100644 index 65d399f1..00000000 --- a/Tests/MQTTnet.Test.NugetConsumption/nuget.config +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - \ No newline at end of file From 38904a62136d20ef0ead983ef9d764f3e7f7f9ef Mon Sep 17 00:00:00 2001 From: JanEggers Date: Sun, 12 Nov 2017 14:13:39 +0100 Subject: [PATCH 044/149] removed testapp again --- MQTTnet.sln | 19 ------------------- .../MQTTnet.Test.NugetConsumption.csproj | 12 ------------ .../MQTTnet.Test.NugetConsumption/Program.cs | 12 ------------ 3 files changed, 43 deletions(-) delete mode 100644 Tests/MQTTnet.Test.NugetConsumption/MQTTnet.Test.NugetConsumption.csproj delete mode 100644 Tests/MQTTnet.Test.NugetConsumption/Program.cs diff --git a/MQTTnet.sln b/MQTTnet.sln index 1aeecd64..326fe7ea 100644 --- a/MQTTnet.sln +++ b/MQTTnet.sln @@ -35,8 +35,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.TestApp.AspNetCore2 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.AspNetCore", "Frameworks\MQTTnet.AspnetCore\MQTTnet.AspNetCore.csproj", "{F10C4060-F7EE-4A83-919F-FF723E72F94A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Test.NugetConsumption", "Tests\MQTTnet.Test.NugetConsumption\MQTTnet.Test.NugetConsumption.csproj", "{21AD2970-A8C7-4689-A35B-88082AFDABF8}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -167,22 +165,6 @@ Global {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 - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|ARM.ActiveCfg = Debug|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|ARM.Build.0 = Debug|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|x64.ActiveCfg = Debug|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|x64.Build.0 = Debug|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|x86.ActiveCfg = Debug|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Debug|x86.Build.0 = Debug|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|Any CPU.Build.0 = Release|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|ARM.ActiveCfg = Release|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|ARM.Build.0 = Release|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|x64.ActiveCfg = Release|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|x64.Build.0 = Release|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|x86.ActiveCfg = Release|Any CPU - {21AD2970-A8C7-4689-A35B-88082AFDABF8}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -194,7 +176,6 @@ Global {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} - {21AD2970-A8C7-4689-A35B-88082AFDABF8} = {9248C2E1-B9D6-40BF-81EC-86004D7765B4} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {07536672-5CBC-4BE3-ACE0-708A431A7894} diff --git a/Tests/MQTTnet.Test.NugetConsumption/MQTTnet.Test.NugetConsumption.csproj b/Tests/MQTTnet.Test.NugetConsumption/MQTTnet.Test.NugetConsumption.csproj deleted file mode 100644 index 53680050..00000000 --- a/Tests/MQTTnet.Test.NugetConsumption/MQTTnet.Test.NugetConsumption.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - Exe - netcoreapp2.0;net452;net461 - - - - - - - diff --git a/Tests/MQTTnet.Test.NugetConsumption/Program.cs b/Tests/MQTTnet.Test.NugetConsumption/Program.cs deleted file mode 100644 index 09ff6c95..00000000 --- a/Tests/MQTTnet.Test.NugetConsumption/Program.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace MQTTnet.Test.NugetConsumption -{ - class Program - { - static void Main(string[] args) - { - var server = new MqttFactory().CreateMqttServer(); - } - } -} From 8672fb2792e8e2c72b243c7b0179e2d4b721f6ce Mon Sep 17 00:00:00 2001 From: JanEggers Date: Sun, 12 Nov 2017 16:46:32 +0100 Subject: [PATCH 045/149] fixed websocket subprotocol negotiation --- .../ApplicationBuilderExtensions.cs | 16 +++++++++++++++- Tests/MQTTnet.TestApp.NetCore/ClientTest.cs | 8 ++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Frameworks/MQTTnet.AspnetCore/ApplicationBuilderExtensions.cs b/Frameworks/MQTTnet.AspnetCore/ApplicationBuilderExtensions.cs index 06ca74d4..210f8a4b 100644 --- a/Frameworks/MQTTnet.AspnetCore/ApplicationBuilderExtensions.cs +++ b/Frameworks/MQTTnet.AspnetCore/ApplicationBuilderExtensions.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using MQTTnet.Core.Server; +using System.Linq; namespace MQTTnet.AspNetCore { @@ -14,8 +15,21 @@ namespace MQTTnet.AspNetCore { if (context.Request.Path == path && context.WebSockets.IsWebSocketRequest) { + string subprotocol = null; + + if (context.Request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues)) + { + if (requestedSubProtocolValues.Count > 0) + { + if (requestedSubProtocolValues.Any(v => v.ToLower() == "mqtt")) + { + subprotocol = "mqtt"; + } + } + } + var adapter = app.ApplicationServices.GetRequiredService(); - using (var webSocket = await context.WebSockets.AcceptWebSocketAsync("mqtt")) + using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(subprotocol)) { await adapter.AcceptWebSocketAsync(webSocket); } diff --git a/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs b/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs index df3cd760..bc644e54 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs @@ -21,10 +21,10 @@ namespace MQTTnet.TestApp.NetCore { Server = "localhost" }, - ////ChannelOptions = new MqttClientWebSocketOptions - ////{ - //// Uri = "localhost" - ////} + //ChannelOptions = new MqttClientWebSocketOptions + //{ + // Uri = "ws://localhost:59690/mqtt" + //} }; var factory = new MqttFactory(); From c775867db49a68243cd798c5ee5759d75e6d17eb Mon Sep 17 00:00:00 2001 From: JanEggers Date: Sun, 12 Nov 2017 16:58:13 +0100 Subject: [PATCH 046/149] merged if statements --- .../ApplicationBuilderExtensions.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Frameworks/MQTTnet.AspnetCore/ApplicationBuilderExtensions.cs b/Frameworks/MQTTnet.AspnetCore/ApplicationBuilderExtensions.cs index 210f8a4b..831392da 100644 --- a/Frameworks/MQTTnet.AspnetCore/ApplicationBuilderExtensions.cs +++ b/Frameworks/MQTTnet.AspnetCore/ApplicationBuilderExtensions.cs @@ -17,15 +17,12 @@ namespace MQTTnet.AspNetCore { string subprotocol = null; - if (context.Request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues)) + if (context.Request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues) + && requestedSubProtocolValues.Count > 0 + && requestedSubProtocolValues.Any(v => v.ToLower() == "mqtt") + ) { - if (requestedSubProtocolValues.Count > 0) - { - if (requestedSubProtocolValues.Any(v => v.ToLower() == "mqtt")) - { - subprotocol = "mqtt"; - } - } + subprotocol = "mqtt"; } var adapter = app.ApplicationServices.GetRequiredService(); From 0c4c93784d0732c862ae00318d677dbf0a86117a Mon Sep 17 00:00:00 2001 From: 1iveowl Date: Sun, 12 Nov 2017 22:59:06 +0100 Subject: [PATCH 047/149] Reference to MQTT Tester --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 985c2837..9fb91672 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ This library is used in the following projects: * MQTT Client Rx (Wrapper for Reactive Extensions, ) * Wirehome (Open Source Home Automation system for .NET, ) +* MQTT Tester app (for [Android](https://play.google.com/store/apps/details?id=com.liveowl.mqtttester), [iOS](https://itunes.apple.com/us/app/mqtt-tester/id1278621826?mt=8), and [Windows 10](https://www.microsoft.com/en-us/store/p/mqtt-tester/9wzdncrd272c)) If you use this library and want to see your project here please let me know. @@ -101,4 +102,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. From c322817cb15ee575761721807327e4d0fca10b03 Mon Sep 17 00:00:00 2001 From: 1iveowl Date: Sun, 12 Nov 2017 23:16:54 +0100 Subject: [PATCH 048/149] Reference to MQTT Tester --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9fb91672..3fcbeaa6 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,9 @@ If you want to contribute to this project just create a pull request. But only p This library is used in the following projects: * MQTT Client Rx (Wrapper for Reactive Extensions, ) +* MQTT Tester (MQTT test appfor [Android](https://play.google.com/store/apps/details?id=com.liveowl.mqtttester), [iOS](https://itunes.apple.com/us/app/mqtt-tester/id1278621826?mt=8), and [Windows 10](https://www.microsoft.com/en-us/store/p/mqtt-tester/9wzdncrd272c)) * Wirehome (Open Source Home Automation system for .NET, ) -* MQTT Tester app (for [Android](https://play.google.com/store/apps/details?id=com.liveowl.mqtttester), [iOS](https://itunes.apple.com/us/app/mqtt-tester/id1278621826?mt=8), and [Windows 10](https://www.microsoft.com/en-us/store/p/mqtt-tester/9wzdncrd272c)) + If you use this library and want to see your project here please let me know. From 9d971003d58647721c5865fdf6111f674f1e3110 Mon Sep 17 00:00:00 2001 From: 1iveowl Date: Sun, 12 Nov 2017 23:17:26 +0100 Subject: [PATCH 049/149] Reference to MQTT Tester --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3fcbeaa6..75fa488e 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ If you want to contribute to this project just create a pull request. But only p This library is used in the following projects: * MQTT Client Rx (Wrapper for Reactive Extensions, ) -* MQTT Tester (MQTT test appfor [Android](https://play.google.com/store/apps/details?id=com.liveowl.mqtttester), [iOS](https://itunes.apple.com/us/app/mqtt-tester/id1278621826?mt=8), and [Windows 10](https://www.microsoft.com/en-us/store/p/mqtt-tester/9wzdncrd272c)) +* MQTT Tester (MQTT test app for [Android](https://play.google.com/store/apps/details?id=com.liveowl.mqtttester), [iOS](https://itunes.apple.com/us/app/mqtt-tester/id1278621826?mt=8), and [Windows 10](https://www.microsoft.com/en-us/store/p/mqtt-tester/9wzdncrd272c)) * Wirehome (Open Source Home Automation system for .NET, ) From c4b706f8ad363f6f8b2da6d403774a653cd2143e Mon Sep 17 00:00:00 2001 From: 1iveowl Date: Sun, 12 Nov 2017 23:19:37 +0100 Subject: [PATCH 050/149] Reference to MQTT Tester --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 75fa488e..6db587aa 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ If you want to contribute to this project just create a pull request. But only p This library is used in the following projects: * MQTT Client Rx (Wrapper for Reactive Extensions, ) -* MQTT Tester (MQTT test app for [Android](https://play.google.com/store/apps/details?id=com.liveowl.mqtttester), [iOS](https://itunes.apple.com/us/app/mqtt-tester/id1278621826?mt=8), and [Windows 10](https://www.microsoft.com/en-us/store/p/mqtt-tester/9wzdncrd272c)) +* MQTT Tester (MQTT client test app for [Android](https://play.google.com/store/apps/details?id=com.liveowl.mqtttester), [iOS](https://itunes.apple.com/us/app/mqtt-tester/id1278621826?mt=8), and [Windows 10](https://www.microsoft.com/en-us/store/p/mqtt-tester/9wzdncrd272c)) * Wirehome (Open Source Home Automation system for .NET, ) From 6e615f85eb640c813bcff4ddcc290ad0a2136847 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Wed, 15 Nov 2017 20:59:03 +0100 Subject: [PATCH 051/149] Update docs --- Build/MQTTnet.nuspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 2e56aa32..519ebc25 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -2,7 +2,7 @@ MQTTnet - 2.5.1 + 2.5.1.1 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,8 +10,8 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * Fixed several library reference issues. -* [Client] Fixed issue in _MqttClientOptionsBuilder_ when using no certificates (Thanks to 1iveowl). + * [Client] Fixed WebSocket sub protocol negotiation (Thanks to @JanEggers) + Copyright Christian Kratky 2016-2017 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 8de87c8772a94c249b1a90fcd04ff0711a73a5e3 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Thu, 16 Nov 2017 00:28:56 +0100 Subject: [PATCH 052/149] Wrap COM exceptions, close client connection when server stops, process retained messages from server --- Build/MQTTnet.nuspec | 7 +- .../Implementations/MqttWebSocketChannel.cs | 15 +- .../Implementations/WebSocketStream.cs | 2 +- Frameworks/MQTTnet.NetStandard/MqttFactory.cs | 4 +- .../MqttChannelCommunicationAdapter.cs | 231 ++++++++---------- MQTTnet.Core/Server/IMqttServer.cs | 3 +- .../Server/MqttClientPendingMessagesQueue.cs | 2 +- MQTTnet.Core/Server/MqttClientSession.cs | 53 ++-- .../Server/MqttClientSessionsManager.cs | 85 +++++-- MQTTnet.Core/Server/MqttServer.cs | 30 +-- 10 files changed, 204 insertions(+), 228 deletions(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 8bdd4a17..c1cd3718 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -10,8 +10,11 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * [Client] Fixed WebSocket sub protocol negotiation (Thanks to @JanEggers) - + * [Core] Fixed library reference issues for .NET 4.6 (Thanks to @JanEggers). +* [Core] Several COM exceptions are now wrapped properly resulting in less warnings in the trace. +* [Client] Fixed WebSocket sub protocol negotiation for ASP.NET Core 2 servers (Thanks to @JanEggers). +* [Server] Client connections are now closed when the server is stopped (Thanks to @zhudanfei). +* [Server] Published messages from the server are now retained (if set) (Thanks to @ChristianRiedl). BREAKING CHANGE! Copyright Christian Kratky 2016-2017 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/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs index 1314a1c3..c7cd3d02 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs @@ -19,9 +19,8 @@ namespace MQTTnet.Implementations _options = options ?? throw new ArgumentNullException(nameof(options)); } - public Stream SendStream => RawReceiveStream; - public Stream ReceiveStream => RawReceiveStream; - public Stream RawReceiveStream { get; private set; } + public Stream SendStream { get; private set; } + public Stream ReceiveStream { get; private set; } public async Task ConnectAsync() { @@ -32,7 +31,7 @@ namespace MQTTnet.Implementations } _webSocket = new ClientWebSocket(); - + if (_options.RequestHeaders != null) { foreach (var requestHeader in _options.RequestHeaders) @@ -64,13 +63,13 @@ namespace MQTTnet.Implementations } await _webSocket.ConnectAsync(new Uri(uri), CancellationToken.None).ConfigureAwait(false); - RawReceiveStream = new WebSocketStream(_webSocket); + + SendStream = new WebSocketStream(_webSocket); + ReceiveStream = SendStream; } public async Task DisconnectAsync() { - RawReceiveStream = null; - if (_webSocket == null) { return; @@ -80,6 +79,8 @@ namespace MQTTnet.Implementations { await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).ConfigureAwait(false); } + + _webSocket = null; } public void Dispose() diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs b/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs index c27e4801..fb2d8121 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs @@ -43,7 +43,7 @@ namespace MQTTnet.Implementations var response = await _webSocket.ReceiveAsync(new ArraySegment(buffer, currentOffset, count), cancellationToken).ConfigureAwait(false); currentOffset += response.Count; count -= response.Count; - + if (response.MessageType == WebSocketMessageType.Close) { await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken).ConfigureAwait(false); diff --git a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs index 1729350c..c8b7968e 100644 --- a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs @@ -85,9 +85,7 @@ namespace MQTTnet clientSessionsManager, _serviceProvider.GetRequiredService(), _serviceProvider.GetRequiredService>(), - _serviceProvider.GetRequiredService>(), - _serviceProvider.GetRequiredService() - ); + _serviceProvider.GetRequiredService>()); } public IMqttClient CreateMqttClient() diff --git a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs index 35573023..c859ec0d 100644 --- a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs +++ b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using MQTTnet.Core.Channel; @@ -14,10 +15,12 @@ namespace MQTTnet.Core.Adapter { public class MqttChannelCommunicationAdapter : IMqttCommunicationAdapter { + private const uint ErrorOperationAborted = 0x800703E3; + private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly ILogger _logger; private readonly IMqttCommunicationChannel _channel; - + public MqttChannelCommunicationAdapter(IMqttCommunicationChannel channel, IMqttPacketSerializer serializer, ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -29,166 +32,87 @@ namespace MQTTnet.Core.Adapter public async Task ConnectAsync(TimeSpan timeout) { - try - { - await _channel.ConnectAsync().TimeoutAfter(timeout).ConfigureAwait(false); - } - catch (TaskCanceledException) - { - throw; - } - catch (OperationCanceledException) - { - throw; - } - catch (MqttCommunicationTimedOutException) - { - throw; - } - catch (MqttCommunicationException) - { - throw; - } - catch (Exception exception) - { - throw new MqttCommunicationException(exception); - } + await ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout)); } public async Task DisconnectAsync(TimeSpan timeout) { - try - { - await _channel.DisconnectAsync().TimeoutAfter(timeout).ConfigureAwait(false); - } - catch (TaskCanceledException) - { - throw; - } - catch (OperationCanceledException) - { - throw; - } - catch (MqttCommunicationTimedOutException) - { - throw; - } - catch (MqttCommunicationException) - { - throw; - } - catch (Exception exception) - { - throw new MqttCommunicationException(exception); - } + await ExecuteAndWrapExceptionAsync(() => _channel.DisconnectAsync().TimeoutAfter(timeout)); } public async Task SendPacketsAsync(TimeSpan timeout, CancellationToken cancellationToken, IEnumerable packets) { - try + await ExecuteAndWrapExceptionAsync(async () => { await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - - foreach (var packet in packets) + try { - if (packet == null) + foreach (var packet in packets) { - continue; + if (packet == null) + { + continue; + } + + _logger.LogInformation("TX >>> {0} [Timeout={1}]", packet, timeout); + + var writeBuffer = PacketSerializer.Serialize(packet); + await _channel.SendStream.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken).ConfigureAwait(false); } - _logger.LogInformation("TX >>> {0} [Timeout={1}]", packet, timeout); - - var writeBuffer = PacketSerializer.Serialize(packet); - await _channel.SendStream.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken).ConfigureAwait(false); + if (timeout > TimeSpan.Zero) + { + await _channel.SendStream.FlushAsync(cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false); + } + else + { + await _channel.SendStream.FlushAsync(cancellationToken).ConfigureAwait(false); + } } - - if (timeout > TimeSpan.Zero) + finally { - await _channel.SendStream.FlushAsync(cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false); + _semaphore.Release(); } - else - { - await _channel.SendStream.FlushAsync(cancellationToken).ConfigureAwait(false); - } - } - catch (TaskCanceledException) - { - throw; - } - catch (OperationCanceledException) - { - throw; - } - catch (MqttCommunicationTimedOutException) - { - throw; - } - catch (MqttCommunicationException) - { - throw; - } - catch (Exception exception) - { - throw new MqttCommunicationException(exception); - } - finally - { - _semaphore.Release(); - } + }); } public async Task ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken) { - ReceivedMqttPacket receivedMqttPacket = null; - try + MqttBasePacket packet = null; + await ExecuteAndWrapExceptionAsync(async () => { - if (timeout > TimeSpan.Zero) + ReceivedMqttPacket receivedMqttPacket = null; + try { - receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false); - } - else - { - receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).ConfigureAwait(false); - } + if (timeout > TimeSpan.Zero) + { + receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false); + } + else + { + receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).ConfigureAwait(false); + } - if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested) - { - throw new TaskCanceledException(); - } + if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested) + { + throw new TaskCanceledException(); + } - var packet = PacketSerializer.Deserialize(receivedMqttPacket); - if (packet == null) - { - throw new MqttProtocolViolationException("Received malformed packet."); - } + packet = PacketSerializer.Deserialize(receivedMqttPacket); + if (packet == null) + { + throw new MqttProtocolViolationException("Received malformed packet."); + } - _logger.LogInformation("RX <<< {0}", packet); - return packet; - } - catch (TaskCanceledException) - { - throw; - } - catch (OperationCanceledException) - { - throw; - } - catch (MqttCommunicationTimedOutException) - { - throw; - } - catch (MqttCommunicationException) - { - throw; - } - catch (Exception exception) - { - throw new MqttCommunicationException(exception); - } - finally - { - receivedMqttPacket?.Dispose(); - } + _logger.LogInformation("RX <<< {0}", packet); + } + finally + { + receivedMqttPacket?.Dispose(); + } + }); + + return packet; } private static async Task ReceiveAsync(Stream stream, CancellationToken cancellationToken) @@ -215,5 +139,42 @@ namespace MQTTnet.Core.Adapter return new ReceivedMqttPacket(header, new MemoryStream(body, 0, body.Length)); } + + private static async Task ExecuteAndWrapExceptionAsync(Func action) + { + try + { + await action().ConfigureAwait(false); + } + catch (TaskCanceledException) + { + throw; + } + catch (OperationCanceledException) + { + throw; + } + catch (MqttCommunicationTimedOutException) + { + throw; + } + catch (MqttCommunicationException) + { + throw; + } + catch (COMException comException) + { + if ((uint)comException.HResult == ErrorOperationAborted) + { + throw new OperationCanceledException(); + } + + throw new MqttCommunicationException(comException); + } + catch (Exception exception) + { + throw new MqttCommunicationException(exception); + } + } } } diff --git a/MQTTnet.Core/Server/IMqttServer.cs b/MQTTnet.Core/Server/IMqttServer.cs index 13c614fc..8d860777 100644 --- a/MQTTnet.Core/Server/IMqttServer.cs +++ b/MQTTnet.Core/Server/IMqttServer.cs @@ -10,8 +10,7 @@ namespace MQTTnet.Core.Server event EventHandler ClientDisconnected; event EventHandler Started; - IList GetConnectedClients(); - void Publish(IEnumerable applicationMessages); + Task> GetConnectedClientsAsync(); Task StartAsync(); Task StopAsync(); diff --git a/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs b/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs index 1e0fc760..16c90944 100644 --- a/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs +++ b/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs @@ -96,7 +96,7 @@ namespace MQTTnet.Core.Server _pendingPublishPackets.Add(packet, CancellationToken.None); } - _session.Stop(); + await _session.StopAsync(); } } } diff --git a/MQTTnet.Core/Server/MqttClientSession.cs b/MQTTnet.Core/Server/MqttClientSession.cs index 93b422ff..42451dd0 100644 --- a/MQTTnet.Core/Server/MqttClientSession.cs +++ b/MQTTnet.Core/Server/MqttClientSession.cs @@ -17,7 +17,6 @@ namespace MQTTnet.Core.Server { private readonly HashSet _unacknowledgedPublishPackets = new HashSet(); - private readonly IMqttClientRetainedMessageManager _clientRetainedMessageManager; private readonly MqttClientSubscriptionsManager _subscriptionsManager; private readonly MqttClientSessionsManager _sessionsManager; private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue; @@ -34,10 +33,8 @@ namespace MQTTnet.Core.Server MqttClientSessionsManager sessionsManager, MqttClientSubscriptionsManager subscriptionsManager, ILogger logger, - ILogger messageQueueLogger, - IMqttClientRetainedMessageManager clientRetainedMessageManager) + ILogger messageQueueLogger) { - _clientRetainedMessageManager = clientRetainedMessageManager ?? throw new ArgumentNullException(nameof(clientRetainedMessageManager)); _sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager)); _subscriptionsManager = subscriptionsManager ?? throw new ArgumentNullException(nameof(subscriptionsManager)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -82,7 +79,7 @@ namespace MQTTnet.Core.Server } } - public void Stop() + public async Task StopAsync() { try { @@ -90,17 +87,21 @@ namespace MQTTnet.Core.Server _cancellationTokenSource?.Dispose(); _cancellationTokenSource = null; - _adapter = null; + if (_adapter != null) + { + await _adapter.DisconnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false); + _adapter = null; + } - _logger.LogInformation("Client '{0}': Disconnected.", ClientId); + _logger.LogInformation("Client '{0}': Session stopped.", ClientId); } finally { - var willMessage = _willMessage; + var willMessage = _willMessage; if (willMessage != null) { _willMessage = null; //clear willmessage so it is send just once - _sessionsManager.DispatchApplicationMessage(this, willMessage); + await _sessionsManager.DispatchApplicationMessageAsync(this, willMessage); } } } @@ -133,12 +134,12 @@ namespace MQTTnet.Core.Server catch (MqttCommunicationException exception) { _logger.LogWarning(new EventId(), exception, "Client '{0}': Communication exception while processing client packets.", ClientId); - Stop(); + await StopAsync(); } catch (Exception exception) { _logger.LogError(new EventId(), exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId); - Stop(); + await StopAsync(); } } @@ -182,14 +183,11 @@ namespace MQTTnet.Core.Server if (packet is MqttDisconnectPacket || packet is MqttConnectPacket) { - Stop(); - return Task.FromResult(0); + return StopAsync(); } _logger.LogWarning("Client '{0}': Received not supported packet ({1}). Closing connection.", ClientId, packet); - Stop(); - - return Task.FromResult(0); + return StopAsync(); } private async Task HandleIncomingSubscribePacketAsync(IMqttCommunicationAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken) @@ -202,13 +200,13 @@ namespace MQTTnet.Core.Server if (subscribeResult.CloseConnection) { await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttDisconnectPacket()).ConfigureAwait(false); - Stop(); + await StopAsync(); } } private async Task EnqueueSubscribedRetainedMessagesAsync(MqttSubscribePacket subscribePacket) { - var retainedMessages = await _clientRetainedMessageManager.GetSubscribedMessagesAsync(subscribePacket).ConfigureAwait(false); + var retainedMessages = await _sessionsManager.GetRetainedMessagesAsync(subscribePacket).ConfigureAwait(false); foreach (var publishPacket in retainedMessages) { EnqueuePublishPacket(publishPacket.ToPublishPacket()); @@ -219,29 +217,16 @@ namespace MQTTnet.Core.Server { var applicationMessage = publishPacket.ToApplicationMessage(); - var interceptorContext = new MqttApplicationMessageInterceptorContext - { - ApplicationMessage = applicationMessage - }; - - _options.ApplicationMessageInterceptor?.Invoke(interceptorContext); - applicationMessage = interceptorContext.ApplicationMessage; - - if (applicationMessage.Retain) - { - await _clientRetainedMessageManager.HandleMessageAsync(ClientId, applicationMessage).ConfigureAwait(false); - } - switch (applicationMessage.QualityOfServiceLevel) { case MqttQualityOfServiceLevel.AtMostOnce: { - _sessionsManager.DispatchApplicationMessage(this, applicationMessage); + await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage); return; } case MqttQualityOfServiceLevel.AtLeastOnce: { - _sessionsManager.DispatchApplicationMessage(this, applicationMessage); + await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage); await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }); @@ -256,7 +241,7 @@ namespace MQTTnet.Core.Server _unacknowledgedPublishPackets.Add(publishPacket.PacketIdentifier); } - _sessionsManager.DispatchApplicationMessage(this, applicationMessage); + await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage); await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }).ConfigureAwait(false); diff --git a/MQTTnet.Core/Server/MqttClientSessionsManager.cs b/MQTTnet.Core/Server/MqttClientSessionsManager.cs index 48fd33ec..80722ab7 100644 --- a/MQTTnet.Core/Server/MqttClientSessionsManager.cs +++ b/MQTTnet.Core/Server/MqttClientSessionsManager.cs @@ -16,19 +16,24 @@ namespace MQTTnet.Core.Server { public sealed class MqttClientSessionsManager { - private readonly Dictionary _clientSessions = new Dictionary(); + private readonly Dictionary _sessions = new Dictionary(); + private readonly SemaphoreSlim _sessionsSemaphore = new SemaphoreSlim(1, 1); + + private readonly MqttServerOptions _options; private readonly ILogger _logger; private readonly IMqttClientSesssionFactory _clientSesssionFactory; - private readonly MqttServerOptions _options; + private readonly IMqttClientRetainedMessageManager _clientRetainedMessageManager; public MqttClientSessionsManager( - IOptions options, + IOptions options, ILogger logger, - IMqttClientSesssionFactory clientSesssionFactory) + IMqttClientSesssionFactory clientSesssionFactory, + IMqttClientRetainedMessageManager clientRetainedMessageManager) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _options = options.Value ?? throw new ArgumentNullException(nameof(options)); _clientSesssionFactory = clientSesssionFactory ?? throw new ArgumentNullException(nameof(clientSesssionFactory)); + _clientRetainedMessageManager = clientRetainedMessageManager ?? throw new ArgumentNullException(nameof(clientRetainedMessageManager)); } public event EventHandler ClientConnected; @@ -61,7 +66,7 @@ namespace MQTTnet.Core.Server return; } - var clientSession = GetOrCreateClientSession(connectPacket); + var clientSession = await GetOrCreateClientSessionAsync(connectPacket); await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttConnAckPacket { @@ -92,7 +97,7 @@ namespace MQTTnet.Core.Server } catch (Exception) { - //ignored + // ignored } ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(new ConnectedMqttClient @@ -103,30 +108,58 @@ namespace MQTTnet.Core.Server } } - public void Clear() + public async Task StopAsync() { - lock (_clientSessions) + await _sessionsSemaphore.WaitAsync().ConfigureAwait(false); + try { - _clientSessions.Clear(); + foreach (var session in _sessions) + { + await session.Value.StopAsync(); + } + + _sessions.Clear(); + } + finally + { + _sessionsSemaphore.Release(); } } - public IList GetConnectedClients() + public async Task> GetConnectedClientsAsync() { - lock (_clientSessions) + await _sessionsSemaphore.WaitAsync().ConfigureAwait(false); + try { - return _clientSessions.Where(s => s.Value.IsConnected).Select(s => new ConnectedMqttClient + return _sessions.Where(s => s.Value.IsConnected).Select(s => new ConnectedMqttClient { ClientId = s.Value.ClientId, ProtocolVersion = s.Value.ProtocolVersion ?? MqttProtocolVersion.V311 }).ToList(); } + finally + { + _sessionsSemaphore.Release(); + } } - public void DispatchApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage) + public async Task DispatchApplicationMessageAsync(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage) { try { + var interceptorContext = new MqttApplicationMessageInterceptorContext + { + ApplicationMessage = applicationMessage + }; + + _options.ApplicationMessageInterceptor?.Invoke(interceptorContext); + applicationMessage = interceptorContext.ApplicationMessage; + + if (applicationMessage.Retain) + { + await _clientRetainedMessageManager.HandleMessageAsync(senderClientSession?.ClientId, applicationMessage).ConfigureAwait(false); + } + var eventArgs = new MqttApplicationMessageReceivedEventArgs(senderClientSession?.ClientId, applicationMessage); ApplicationMessageReceived?.Invoke(this, eventArgs); } @@ -135,15 +168,20 @@ namespace MQTTnet.Core.Server _logger.LogError(new EventId(), exception, "Error while processing application message"); } - lock (_clientSessions) + lock (_sessions) { - foreach (var clientSession in _clientSessions.Values.ToList()) + foreach (var clientSession in _sessions.Values.ToList()) { clientSession.EnqueuePublishPacket(applicationMessage.ToPublishPacket()); } } } + public Task> GetRetainedMessagesAsync(MqttSubscribePacket subscribePacket) + { + return _clientRetainedMessageManager.GetSubscribedMessagesAsync(subscribePacket); + } + private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket) { if (_options.ConnectionValidator != null) @@ -154,17 +192,18 @@ namespace MQTTnet.Core.Server return MqttConnectReturnCode.ConnectionAccepted; } - private GetOrCreateClientSessionResult GetOrCreateClientSession(MqttConnectPacket connectPacket) + private async Task GetOrCreateClientSessionAsync(MqttConnectPacket connectPacket) { - lock (_clientSessions) + await _sessionsSemaphore.WaitAsync().ConfigureAwait(false); + try { - var isSessionPresent = _clientSessions.TryGetValue(connectPacket.ClientId, out var clientSession); + var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var clientSession); if (isSessionPresent) { if (connectPacket.CleanSession) { - _clientSessions.Remove(connectPacket.ClientId); - clientSession.Stop(); + _sessions.Remove(connectPacket.ClientId); + await clientSession.StopAsync(); clientSession = null; _logger.LogTrace("Stopped existing session of client '{0}'.", connectPacket.ClientId); @@ -181,13 +220,17 @@ namespace MQTTnet.Core.Server isExistingSession = false; clientSession = _clientSesssionFactory.CreateClientSession(connectPacket.ClientId, this); - _clientSessions[connectPacket.ClientId] = clientSession; + _sessions[connectPacket.ClientId] = clientSession; _logger.LogTrace("Created a new session for client '{0}'.", connectPacket.ClientId); } return new GetOrCreateClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession }; } + finally + { + _sessionsSemaphore.Release(); + } } } } \ No newline at end of file diff --git a/MQTTnet.Core/Server/MqttServer.cs b/MQTTnet.Core/Server/MqttServer.cs index bd06a3a6..c671907e 100644 --- a/MQTTnet.Core/Server/MqttServer.cs +++ b/MQTTnet.Core/Server/MqttServer.cs @@ -20,12 +20,11 @@ namespace MQTTnet.Core.Server private CancellationTokenSource _cancellationTokenSource; public MqttServer( - IOptions options, + IOptions options, IEnumerable adapters, ILogger logger, MqttClientSessionsManager clientSessionsManager, - IMqttClientRetainedMessageManager clientRetainedMessageManager - ) + IMqttClientRetainedMessageManager clientRetainedMessageManager) { _options = options.Value ?? throw new ArgumentNullException(nameof(options)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -35,7 +34,7 @@ namespace MQTTnet.Core.Server if (adapters == null) { throw new ArgumentNullException(nameof(adapters)); - } + } _adapters = adapters.ToList(); @@ -44,9 +43,9 @@ namespace MQTTnet.Core.Server _clientSessionsManager.ClientDisconnected += OnClientDisconnected; } - public IList GetConnectedClients() + public Task> GetConnectedClientsAsync() { - return _clientSessionsManager.GetConnectedClients(); + return _clientSessionsManager.GetConnectedClientsAsync(); } public event EventHandler Started; @@ -54,7 +53,7 @@ namespace MQTTnet.Core.Server public event EventHandler ClientDisconnected; public event EventHandler ApplicationMessageReceived; - public void Publish(IEnumerable applicationMessages) + public async Task PublishAsync(IEnumerable applicationMessages) { if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages)); @@ -65,23 +64,10 @@ namespace MQTTnet.Core.Server foreach (var applicationMessage in applicationMessages) { - var interceptorContext = new MqttApplicationMessageInterceptorContext - { - ApplicationMessage = applicationMessage - }; - - _options.ApplicationMessageInterceptor?.Invoke(interceptorContext); - - _clientSessionsManager.DispatchApplicationMessage(null, interceptorContext.ApplicationMessage); + await _clientSessionsManager.DispatchApplicationMessageAsync(null, applicationMessage); } } - public Task PublishAsync(IEnumerable applicationMessages) - { - Publish(applicationMessages); - return Task.FromResult(0); - } - public async Task StartAsync() { if (_cancellationTokenSource != null) throw new InvalidOperationException("The MQTT server is already started."); @@ -113,7 +99,7 @@ namespace MQTTnet.Core.Server await adapter.StopAsync(); } - _clientSessionsManager.Clear(); + await _clientSessionsManager.StopAsync(); _logger.LogInformation("Stopped."); } From 5bcda12ca930038e1a10c512daedfda077c156f8 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Thu, 16 Nov 2017 14:17:58 +0100 Subject: [PATCH 053/149] Fix QoS handling in server --- .../Server/CheckSubscriptionsResult.cs | 11 ++++++ MQTTnet.Core/Server/MqttClientSession.cs | 4 ++- .../Server/MqttClientSubscriptionsManager.cs | 34 ++++++++++++------- .../MqttSubscriptionsManagerTests.cs | 14 ++++---- 4 files changed, 42 insertions(+), 21 deletions(-) create mode 100644 MQTTnet.Core/Server/CheckSubscriptionsResult.cs diff --git a/MQTTnet.Core/Server/CheckSubscriptionsResult.cs b/MQTTnet.Core/Server/CheckSubscriptionsResult.cs new file mode 100644 index 00000000..625457ff --- /dev/null +++ b/MQTTnet.Core/Server/CheckSubscriptionsResult.cs @@ -0,0 +1,11 @@ +using MQTTnet.Core.Protocol; + +namespace MQTTnet.Core.Server +{ + public class CheckSubscriptionsResult + { + public bool IsSubscribed { get; set; } + + public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; } + } +} diff --git a/MQTTnet.Core/Server/MqttClientSession.cs b/MQTTnet.Core/Server/MqttClientSession.cs index 42451dd0..ad1416ed 100644 --- a/MQTTnet.Core/Server/MqttClientSession.cs +++ b/MQTTnet.Core/Server/MqttClientSession.cs @@ -110,11 +110,13 @@ namespace MQTTnet.Core.Server { if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket)); - if (!_subscriptionsManager.IsSubscribed(publishPacket)) + var result = _subscriptionsManager.CheckSubscriptions(publishPacket); + if (!result.IsSubscribed) { return; } + publishPacket.QualityOfServiceLevel = result.QualityOfServiceLevel; _pendingMessagesQueue.Enqueue(publishPacket); } diff --git a/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs b/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs index 1b0d6c4c..5af3a2de 100644 --- a/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs +++ b/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs @@ -8,7 +8,7 @@ namespace MQTTnet.Core.Server { public sealed class MqttClientSubscriptionsManager { - private readonly Dictionary _subscribedTopics = new Dictionary(); + private readonly Dictionary _subscriptions = new Dictionary(); private readonly MqttServerOptions _options; public MqttClientSubscriptionsManager(IOptions options) @@ -23,7 +23,7 @@ namespace MQTTnet.Core.Server var responsePacket = subscribePacket.CreateResponse(); var closeConnection = false; - lock (_subscribedTopics) + lock (_subscriptions) { foreach (var topicFilter in subscribePacket.TopicFilters) { @@ -38,7 +38,7 @@ namespace MQTTnet.Core.Server if (interceptorContext.AcceptSubscription) { - _subscribedTopics[topicFilter.Topic] = topicFilter.QualityOfServiceLevel; + _subscriptions[topicFilter.Topic] = topicFilter.QualityOfServiceLevel; } } } @@ -54,40 +54,48 @@ namespace MQTTnet.Core.Server { if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket)); - lock (_subscribedTopics) + lock (_subscriptions) { foreach (var topicFilter in unsubscribePacket.TopicFilters) { - _subscribedTopics.Remove(topicFilter); + _subscriptions.Remove(topicFilter); } } return unsubscribePacket.CreateResponse(); } - public bool IsSubscribed(MqttPublishPacket publishPacket) + public CheckSubscriptionsResult CheckSubscriptions(MqttPublishPacket publishPacket) { if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket)); - lock (_subscribedTopics) + lock (_subscriptions) { - foreach (var subscribedTopic in _subscribedTopics) + foreach (var subscription in _subscriptions) { - if (publishPacket.QualityOfServiceLevel > subscribedTopic.Value) + if (!MqttTopicFilterComparer.IsMatch(publishPacket.Topic, subscription.Key)) { continue; } - if (!MqttTopicFilterComparer.IsMatch(publishPacket.Topic, subscribedTopic.Key)) + var effectiveQos = subscription.Value; + if (publishPacket.QualityOfServiceLevel < effectiveQos) { - continue; + effectiveQos = publishPacket.QualityOfServiceLevel; } - return true; + return new CheckSubscriptionsResult + { + IsSubscribed = true, + QualityOfServiceLevel = effectiveQos + }; } } - return false; + return new CheckSubscriptionsResult + { + IsSubscribed = false + }; } } } diff --git a/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs b/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs index d46354c7..44bad993 100644 --- a/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs @@ -15,7 +15,7 @@ namespace MQTTnet.Core.Tests var sm = new MqttClientSubscriptionsManager(new OptionsWrapper(new MqttServerOptions())); var sp = new MqttSubscribePacket(); - sp.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.AtMostOnce)); + sp.TopicFilters.Add(new TopicFilter("A/B/C")); sm.Subscribe(sp, ""); @@ -25,7 +25,7 @@ namespace MQTTnet.Core.Tests QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce }; - Assert.IsTrue(sm.IsSubscribed(pp)); + Assert.IsTrue(sm.CheckSubscriptions(pp).IsSubscribed); } [TestMethod] @@ -34,7 +34,7 @@ namespace MQTTnet.Core.Tests var sm = new MqttClientSubscriptionsManager(new OptionsWrapper(new MqttServerOptions())); var sp = new MqttSubscribePacket(); - sp.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.AtMostOnce)); + sp.TopicFilters.Add(new TopicFilter("A/B/C")); sm.Subscribe(sp, ""); @@ -44,7 +44,7 @@ namespace MQTTnet.Core.Tests QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce }; - Assert.IsFalse(sm.IsSubscribed(pp)); + Assert.IsFalse(sm.CheckSubscriptions(pp).IsSubscribed); } [TestMethod] @@ -53,7 +53,7 @@ namespace MQTTnet.Core.Tests var sm = new MqttClientSubscriptionsManager(new OptionsWrapper(new MqttServerOptions())); var sp = new MqttSubscribePacket(); - sp.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.AtMostOnce)); + sp.TopicFilters.Add(new TopicFilter("A/B/C")); sm.Subscribe(sp, ""); @@ -63,13 +63,13 @@ namespace MQTTnet.Core.Tests QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce }; - Assert.IsTrue(sm.IsSubscribed(pp)); + Assert.IsTrue(sm.CheckSubscriptions(pp).IsSubscribed); var up = new MqttUnsubscribePacket(); up.TopicFilters.Add("A/B/C"); sm.Unsubscribe(up); - Assert.IsFalse(sm.IsSubscribed(pp)); + Assert.IsFalse(sm.CheckSubscriptions(pp).IsSubscribed); } } } From acc269e702d148a33bdb40329fb7fbdaa0d72b59 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Fri, 17 Nov 2017 21:13:01 +0100 Subject: [PATCH 054/149] Fixed WebSocket client stream --- Build/MQTTnet.nuspec | 4 +- .../MqttWebSocketServerAdapter.cs | 46 ------- .../MqttWebSocketServerChannel.cs | 60 +++++++++ .../Implementations/MqttWebSocketChannel.cs | 6 +- .../Implementations/WebSocketStream.cs | 97 ++++++++++---- Frameworks/MQTTnet.NetStandard/MqttFactory.cs | 2 +- MQTTnet.Core/Client/MqttClient.cs | 124 ++++++++++-------- MQTTnet.Core/Packets/MqttPublishPacket.cs | 5 +- MQTTnet.Core/Serializer/MqttPacketReader.cs | 2 +- .../MainPage.xaml | 1 + .../MainPage.xaml.cs | 22 ++-- 11 files changed, 225 insertions(+), 144 deletions(-) create mode 100644 Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerChannel.cs diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index c1cd3718..6b111fc0 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -10,9 +10,11 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * [Core] Fixed library reference issues for .NET 4.6 (Thanks to @JanEggers). + * [Core] Fixed library reference issues for .NET 4.6 and netstandard 2.0 (Thanks to @JanEggers). * [Core] Several COM exceptions are now wrapped properly resulting in less warnings in the trace. +* [Core] Removed application message payload from trace to reduce trace size and increase performance. * [Client] Fixed WebSocket sub protocol negotiation for ASP.NET Core 2 servers (Thanks to @JanEggers). +* [Client] Fixed broken connection after 30 seconds then using WebSocket protocol (Thanks to @ChristianRiedl). * [Server] Client connections are now closed when the server is stopped (Thanks to @zhudanfei). * [Server] Published messages from the server are now retained (if set) (Thanks to @ChristianRiedl). BREAKING CHANGE! diff --git a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs index 45bf5457..0e3a3d5f 100644 --- a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs +++ b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs @@ -1,12 +1,8 @@ using System; -using System.IO; using System.Net.WebSockets; -using System.Threading; using System.Threading.Tasks; using MQTTnet.Core.Adapter; -using MQTTnet.Core.Channel; using MQTTnet.Core.Server; -using MQTTnet.Implementations; namespace MQTTnet.AspNetCore { @@ -47,47 +43,5 @@ namespace MQTTnet.AspNetCore { StopAsync(); } - - private class MqttWebSocketServerChannel : IMqttCommunicationChannel, IDisposable - { - private readonly WebSocket _webSocket; - - public MqttWebSocketServerChannel(WebSocket webSocket) - { - _webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket)); - - RawReceiveStream = new WebSocketStream(_webSocket); - } - - public Stream SendStream => RawReceiveStream; - public Stream ReceiveStream => RawReceiveStream; - public Stream RawReceiveStream { get; } - - public Task ConnectAsync() - { - return Task.CompletedTask; - } - - public Task DisconnectAsync() - { - RawReceiveStream?.Dispose(); - - if (_webSocket == null) - { - return Task.CompletedTask; - } - - return _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); - } - - public void Dispose() - { - RawReceiveStream?.Dispose(); - SendStream?.Dispose(); - ReceiveStream?.Dispose(); - - _webSocket?.Dispose(); - } - } } } \ No newline at end of file diff --git a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerChannel.cs b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerChannel.cs new file mode 100644 index 00000000..54cfb0b9 --- /dev/null +++ b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerChannel.cs @@ -0,0 +1,60 @@ +using System; +using System.IO; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; +using MQTTnet.Core.Channel; +using MQTTnet.Implementations; + +namespace MQTTnet.AspNetCore +{ + public class MqttWebSocketServerChannel : IMqttCommunicationChannel, IDisposable + { + private WebSocket _webSocket; + + public MqttWebSocketServerChannel(WebSocket webSocket) + { + _webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket)); + + SendStream = new WebSocketStream(_webSocket); + ReceiveStream = SendStream; + } + + public Stream SendStream { get; private set; } + public Stream ReceiveStream { get; private set; } + + public Task ConnectAsync() + { + return Task.CompletedTask; + } + + public async Task DisconnectAsync() + { + if (_webSocket == null) + { + return; + } + + try + { + await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); + } + finally + { + Dispose(); + } + } + + public void Dispose() + { + SendStream?.Dispose(); + ReceiveStream?.Dispose(); + + _webSocket?.Dispose(); + + SendStream = null; + ReceiveStream = null; + _webSocket = null; + } + } +} \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs index c7cd3d02..8f56c945 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs @@ -11,6 +11,10 @@ namespace MQTTnet.Implementations { public sealed class MqttWebSocketChannel : IMqttCommunicationChannel, IDisposable { + // ReSharper disable once MemberCanBePrivate.Global + // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global + public static int BufferSize { get; set; } = 4096 * 20; // Can be changed for fine tuning by library user. + private readonly MqttClientWebSocketOptions _options; private ClientWebSocket _webSocket; @@ -80,7 +84,7 @@ namespace MQTTnet.Implementations await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).ConfigureAwait(false); } - _webSocket = null; + Dispose(); } public void Dispose() diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs b/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs index fb2d8121..4ff11dad 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; @@ -10,7 +12,9 @@ namespace MQTTnet.Implementations public class WebSocketStream : Stream { private readonly WebSocket _webSocket; - + private readonly byte[] _chunkBuffer = new byte[MqttWebSocketChannel.BufferSize]; + private readonly Queue _buffer = new Queue(MqttWebSocketChannel.BufferSize); + public WebSocketStream(WebSocket webSocket) { _webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket)); @@ -34,33 +38,9 @@ namespace MQTTnet.Implementations { } - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + public override Task FlushAsync(CancellationToken cancellationToken) { - var currentOffset = offset; - var targetOffset = offset + count; - while (_webSocket.State == WebSocketState.Open && currentOffset < targetOffset) - { - var response = await _webSocket.ReceiveAsync(new ArraySegment(buffer, currentOffset, count), cancellationToken).ConfigureAwait(false); - currentOffset += response.Count; - count -= response.Count; - - if (response.MessageType == WebSocketMessageType.Close) - { - await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken).ConfigureAwait(false); - } - } - - if (_webSocket.State == WebSocketState.Closed) - { - throw new MqttCommunicationException( "connection closed" ); - } - - return currentOffset - offset; - } - - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - return _webSocket.SendAsync(new ArraySegment(buffer, offset, count), WebSocketMessageType.Binary, true, cancellationToken); + return Task.FromResult(0); } public override int Read(byte[] buffer, int offset, int count) @@ -68,11 +48,58 @@ namespace MQTTnet.Implementations return ReadAsync(buffer, offset, count).GetAwaiter().GetResult(); } + public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + var bytesRead = 0; + + // Use existing date from buffer. + while (count > 0 && _buffer.Any()) + { + buffer[offset++] = _buffer.Dequeue(); + count--; + bytesRead++; + } + + if (count == 0) + { + return bytesRead; + } + + while (_webSocket.State == WebSocketState.Open) + { + await FetchChunkAsync(cancellationToken); + + while (count > 0 && _buffer.Any()) + { + buffer[offset++] = _buffer.Dequeue(); + count--; + bytesRead++; + } + + if (count == 0) + { + return bytesRead; + } + } + + if (_webSocket.State == WebSocketState.Closed) + { + throw new MqttCommunicationException("WebSocket connection closed."); + } + + return bytesRead; + } + public override void Write(byte[] buffer, int offset, int count) { WriteAsync(buffer, offset, count).GetAwaiter().GetResult(); } + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + return _webSocket.SendAsync(new ArraySegment(buffer, offset, count), WebSocketMessageType.Binary, true, cancellationToken); + } + public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); @@ -82,5 +109,21 @@ namespace MQTTnet.Implementations { throw new NotSupportedException(); } + + private async Task FetchChunkAsync(CancellationToken cancellationToken) + { + var response = await _webSocket.ReceiveAsync(new ArraySegment(_chunkBuffer, 0, _chunkBuffer.Length), cancellationToken).ConfigureAwait(false); + + for (var i = 0; i < response.Count; i++) + { + var @byte = _chunkBuffer[i]; + _buffer.Enqueue(@byte); + } + + if (response.MessageType == WebSocketMessageType.Close) + { + await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken).ConfigureAwait(false); + } + } } } diff --git a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs index c8b7968e..6037929e 100644 --- a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs @@ -23,7 +23,7 @@ namespace MQTTnet public MqttFactory(IServiceProvider serviceProvider) { - _serviceProvider = serviceProvider; + _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); } public ILoggerFactory GetLoggerFactory() diff --git a/MQTTnet.Core/Client/MqttClient.cs b/MQTTnet.Core/Client/MqttClient.cs index 202cbc58..fcab3fba 100644 --- a/MQTTnet.Core/Client/MqttClient.cs +++ b/MQTTnet.Core/Client/MqttClient.cs @@ -60,14 +60,14 @@ namespace MQTTnet.Core.Client await _adapter.ConnectAsync(_options.CommunicationTimeout).ConfigureAwait(false); _logger.LogTrace("Connection with server established."); - await SetupIncomingPacketProcessingAsync().ConfigureAwait(false); + await StartReceivingPacketsAsync(_cancellationTokenSource.Token).ConfigureAwait(false); var connectResponse = await AuthenticateAsync(options.WillMessage).ConfigureAwait(false); _logger.LogTrace("MQTT connection with server established."); if (_options.KeepAlivePeriod != TimeSpan.Zero) { - StartSendKeepAliveMessages(_cancellationTokenSource.Token); + StartSendingKeepAliveMessages(_cancellationTokenSource.Token); } IsConnected = true; @@ -96,7 +96,6 @@ namespace MQTTnet.Core.Client finally { await DisconnectInternalAsync().ConfigureAwait(false); - _scopeHandle.Dispose(); } } @@ -149,36 +148,36 @@ namespace MQTTnet.Core.Client switch (qosGroup.Key) { case MqttQualityOfServiceLevel.AtMostOnce: - { - // No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier] - await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, qosPackets).ConfigureAwait(false); - break; - } + { + // No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier] + await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, qosPackets).ConfigureAwait(false); + break; + } case MqttQualityOfServiceLevel.AtLeastOnce: - { - foreach (var publishPacket in qosPackets) { - publishPacket.PacketIdentifier = GetNewPacketIdentifier(); - await SendAndReceiveAsync(publishPacket).ConfigureAwait(false); - } + foreach (var publishPacket in qosPackets) + { + publishPacket.PacketIdentifier = GetNewPacketIdentifier(); + await SendAndReceiveAsync(publishPacket).ConfigureAwait(false); + } - break; - } + break; + } case MqttQualityOfServiceLevel.ExactlyOnce: - { - foreach (var publishPacket in qosPackets) { - publishPacket.PacketIdentifier = GetNewPacketIdentifier(); - var pubRecPacket = await SendAndReceiveAsync(publishPacket).ConfigureAwait(false); - await SendAndReceiveAsync(pubRecPacket.CreateResponse()).ConfigureAwait(false); - } + foreach (var publishPacket in qosPackets) + { + publishPacket.PacketIdentifier = GetNewPacketIdentifier(); + var pubRecPacket = await SendAndReceiveAsync(publishPacket).ConfigureAwait(false); + await SendAndReceiveAsync(pubRecPacket.CreateResponse()).ConfigureAwait(false); + } - break; - } + break; + } default: - { - throw new InvalidOperationException(); - } + { + throw new InvalidOperationException(); + } } } } @@ -191,7 +190,7 @@ namespace MQTTnet.Core.Client Username = _options.Credentials?.Username, Password = _options.Credentials?.Password, CleanSession = _options.CleanSession, - KeepAlivePeriod = (ushort) _options.KeepAlivePeriod.TotalSeconds, + KeepAlivePeriod = (ushort)_options.KeepAlivePeriod.TotalSeconds, WillMessage = willApplicationMessage }; @@ -204,24 +203,6 @@ namespace MQTTnet.Core.Client return response; } - private async Task SetupIncomingPacketProcessingAsync() - { - _isReceivingPackets = false; - -#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - Task.Factory.StartNew( - () => ReceivePackets(_cancellationTokenSource.Token), - _cancellationTokenSource.Token, - TaskCreationOptions.LongRunning, - TaskScheduler.Default).ConfigureAwait(false); -#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - - while (!_isReceivingPackets && _cancellationTokenSource != null && !_cancellationTokenSource.IsCancellationRequested) - { - await Task.Delay(TimeSpan.FromMilliseconds(100)).ConfigureAwait(false); - } - } - private void ThrowIfNotConnected() { if (!IsConnected) throw new MqttCommunicationException("The client is not connected."); @@ -234,6 +215,8 @@ namespace MQTTnet.Core.Client private async Task DisconnectInternalAsync() { + _scopeHandle?.Dispose(); + var clientWasConnected = IsConnected; IsConnected = false; @@ -258,6 +241,7 @@ namespace MQTTnet.Core.Client } finally { + _logger.LogInformation("Disconnected."); Disconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(clientWasConnected)); } } @@ -324,7 +308,7 @@ namespace MQTTnet.Core.Client if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce) { FireApplicationMessageReceivedEvent(publishPacket); - await SendAsync(new MqttPubAckPacket {PacketIdentifier = publishPacket.PacketIdentifier}); + await SendAsync(new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }); return; } @@ -337,7 +321,7 @@ namespace MQTTnet.Core.Client } FireApplicationMessageReceivedEvent(publishPacket); - await SendAsync(new MqttPubRecPacket {PacketIdentifier = publishPacket.PacketIdentifier}); + await SendAsync(new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }); return; } @@ -363,12 +347,12 @@ namespace MQTTnet.Core.Client { var packetAwaiter = _packetDispatcher.WaitForPacketAsync(requestPacket, typeof(TResponsePacket), _options.CommunicationTimeout); await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, requestPacket).ConfigureAwait(false); - return (TResponsePacket) await packetAwaiter.ConfigureAwait(false); + return (TResponsePacket)await packetAwaiter.ConfigureAwait(false); } private ushort GetNewPacketIdentifier() { - return (ushort) Interlocked.Increment(ref _latestPacketIdentifier); + return (ushort)Interlocked.Increment(ref _latestPacketIdentifier); } private async Task SendKeepAliveMessagesAsync(CancellationToken cancellationToken) @@ -390,6 +374,12 @@ namespace MQTTnet.Core.Client } catch (OperationCanceledException) { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await DisconnectInternalAsync().ConfigureAwait(false); } catch (MqttCommunicationException exception) { @@ -412,7 +402,7 @@ namespace MQTTnet.Core.Client } } - private async Task ReceivePackets(CancellationToken cancellationToken) + private async Task ReceivePacketsAsync(CancellationToken cancellationToken) { _logger.LogInformation("Start receiving packets."); @@ -423,6 +413,7 @@ namespace MQTTnet.Core.Client _isReceivingPackets = true; var packet = await _adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(false); + if (cancellationToken.IsCancellationRequested) { return; @@ -433,6 +424,12 @@ namespace MQTTnet.Core.Client } catch (OperationCanceledException) { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await DisconnectInternalAsync().ConfigureAwait(false); } catch (MqttCommunicationException exception) { @@ -458,15 +455,34 @@ namespace MQTTnet.Core.Client private void StartProcessReceivedPacket(MqttBasePacket packet, CancellationToken cancellationToken) { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - Task.Run(() => ProcessReceivedPacketAsync(packet), cancellationToken).ConfigureAwait(false); + Task.Run( + () => ProcessReceivedPacketAsync(packet), + cancellationToken).ConfigureAwait(false); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } - private void StartSendKeepAliveMessages(CancellationToken cancellationToken) + private async Task StartReceivingPacketsAsync(CancellationToken cancellationToken) + { + _isReceivingPackets = false; + +#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + Task.Run( + async () => await ReceivePacketsAsync(cancellationToken), + cancellationToken).ConfigureAwait(false); +#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + + while (!_isReceivingPackets && !cancellationToken.IsCancellationRequested) + { + await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken).ConfigureAwait(false); + } + } + + private void StartSendingKeepAliveMessages(CancellationToken cancellationToken) { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - Task.Factory.StartNew(() => SendKeepAliveMessagesAsync(cancellationToken), cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default) - .ConfigureAwait(false); + Task.Run( + async () => await SendKeepAliveMessagesAsync(cancellationToken), + cancellationToken).ConfigureAwait(false); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } } diff --git a/MQTTnet.Core/Packets/MqttPublishPacket.cs b/MQTTnet.Core/Packets/MqttPublishPacket.cs index 447aaed7..b7d10d11 100644 --- a/MQTTnet.Core/Packets/MqttPublishPacket.cs +++ b/MQTTnet.Core/Packets/MqttPublishPacket.cs @@ -1,5 +1,4 @@ -using System; -using MQTTnet.Core.Protocol; +using MQTTnet.Core.Protocol; namespace MQTTnet.Core.Packets { @@ -19,7 +18,7 @@ namespace MQTTnet.Core.Packets { return nameof(MqttPublishPacket) + ": [Topic=" + Topic + "]" + - " [Payload=" + Convert.ToBase64String(Payload) + "]" + + " [PayloadLength=" + Payload?.Length + "]" + " [QoSLevel=" + QualityOfServiceLevel + "]" + " [Dup=" + Dup + "]" + " [Retain=" + Retain + "]" + diff --git a/MQTTnet.Core/Serializer/MqttPacketReader.cs b/MQTTnet.Core/Serializer/MqttPacketReader.cs index 97b6478c..9fcae9e5 100644 --- a/MQTTnet.Core/Serializer/MqttPacketReader.cs +++ b/MQTTnet.Core/Serializer/MqttPacketReader.cs @@ -91,7 +91,7 @@ namespace MQTTnet.Core.Serializer if (buffer == -1) { - break; + throw new MqttCommunicationException("Connection closed while reading remaining length data."); } encodedByte = (byte)buffer; diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml index 4fdbd2e6..43b26c7a 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml @@ -78,6 +78,7 @@ Received messages: + Add received messages to list diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index 6ae711be..5e1a1261 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -30,14 +30,14 @@ namespace MQTTnet.TestApp.UniversalWindows private async void OnTraceMessagePublished(object sender, MqttNetTraceMessagePublishedEventArgs e) { - await Trace.Dispatcher.RunAsync(CoreDispatcherPriority.High, () => + var text = $"[{e.TraceMessage.Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{e.TraceMessage.Level}] [{e.TraceMessage.Source}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Message}]{Environment.NewLine}"; + if (e.TraceMessage.Exception != null) + { + text += $"{e.TraceMessage.Exception}{Environment.NewLine}"; + } + + await Trace.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () => { - var text = $"[{e.TraceMessage.Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{e.TraceMessage.Level}] [{e.TraceMessage.Source}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Message}]{Environment.NewLine}"; - if (e.TraceMessage.Exception != null) - { - text += $"{e.TraceMessage.Exception}{Environment.NewLine}"; - } - Trace.Text += text; }); } @@ -109,11 +109,13 @@ namespace MQTTnet.TestApp.UniversalWindows { var item = $"Timestamp: {DateTime.Now:O} | Topic: {eventArgs.ApplicationMessage.Topic} | Payload: {Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload)} | QoS: {eventArgs.ApplicationMessage.QualityOfServiceLevel}"; - await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + await Dispatcher.RunAsync(CoreDispatcherPriority.Low, () => { - ReceivedMessages.Items.Add(item); + if (AddReceivedMessagesToList.IsChecked == true) + { + ReceivedMessages.Items.Add(item); + } }); - } private async void Publish(object sender, RoutedEventArgs e) From f8078a68941236b15e3dc6b09ba08a448e5cc6d0 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Fri, 17 Nov 2017 21:26:43 +0100 Subject: [PATCH 055/149] Update version info --- Build/MQTTnet.nuspec | 2 +- Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj | 2 ++ Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj | 4 ++-- MQTTnet.Core/MQTTnet.Core.csproj | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 6b111fc0..cd218576 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -2,7 +2,7 @@ MQTTnet - 2.5.1.1 + 2.5.2-rc1 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE diff --git a/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj b/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj index 5142cc15..5556b11c 100644 --- a/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj +++ b/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj @@ -2,6 +2,8 @@ netstandard2.0 + 2.5.2.0 + 2.5.2.0 diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj index 41c30d39..6349d3ea 100644 --- a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -4,8 +4,8 @@ netstandard1.3;netstandard2.0;net452;net461;uap10.0 MQTTnet MQTTnet - 2.5.0.0 - 2.5.0.0 + 2.5.2.0 + 2.5.2.0 0.0.0.0 diff --git a/MQTTnet.Core/MQTTnet.Core.csproj b/MQTTnet.Core/MQTTnet.Core.csproj index 522b3fb8..d50466f1 100644 --- a/MQTTnet.Core/MQTTnet.Core.csproj +++ b/MQTTnet.Core/MQTTnet.Core.csproj @@ -17,8 +17,8 @@ - 2.5.0.0 - 2.5.0.0 + 2.5.2.0 + 2.5.2.0 From 8411382c42768be59728a942d0880ae739d2e437 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Fri, 17 Nov 2017 21:29:37 +0100 Subject: [PATCH 056/149] Update build script --- Build/build.ps1 | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Build/build.ps1 b/Build/build.ps1 index 1e47727c..09eabf25 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -1,4 +1,4 @@ -param([string]$version) +param([string]$assemblyVersion, [string]$nugetVersion) if ([string]::IsNullOrEmpty($version)) {$version = "0.0.1"} @@ -8,17 +8,16 @@ $path = &$vswhere -latest -products * -requires Microsoft.Component.MSBuild -pro if ($path) { $msbuild = join-path $path 'MSBuild\15.0\Bin\MSBuild.exe' - &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m - &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m - &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m - &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m - &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m + &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m + &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m + &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m + &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m + &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m - &$msbuild ..\Frameworks\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$version /p:AssemblyVersion=$version /verbosity:m + &$msbuild ..\Frameworks\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m Remove-Item .\NuGet -Force -Recurse New-Item -ItemType Directory -Force -Path .\NuGet - .\NuGet.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $version - .\NuGet.exe pack MQTTnet.AspNetCore.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $version -} - + .\NuGet.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion + .\NuGet.exe pack MQTTnet.AspNetCore.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion +} \ No newline at end of file From e0235aedff1614927491342ca5fee96f80bc3b02 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 21 Nov 2017 20:55:57 +0100 Subject: [PATCH 057/149] Refactor trace messages --- Build/MQTTnet.nuspec | 10 +-- .../MqttChannelCommunicationAdapter.cs | 4 + MQTTnet.Core/Packets/MqttConnAckPacket.cs | 2 +- MQTTnet.Core/Packets/MqttConnectPacket.cs | 2 +- MQTTnet.Core/Packets/MqttDisconnectPacket.cs | 4 + MQTTnet.Core/Packets/MqttPingReqPacket.cs | 2 +- MQTTnet.Core/Packets/MqttPingRespPacket.cs | 2 +- MQTTnet.Core/Packets/MqttPubAckPacket.cs | 4 + MQTTnet.Core/Packets/MqttPubCompPacket.cs | 4 + MQTTnet.Core/Packets/MqttPubRecPacket.cs | 4 + MQTTnet.Core/Packets/MqttPubRelPacket.cs | 4 + MQTTnet.Core/Packets/MqttPublishPacket.cs | 5 +- MQTTnet.Core/Packets/MqttSubAckPacket.cs | 2 +- MQTTnet.Core/Packets/MqttSubscribePacket.cs | 2 +- MQTTnet.Core/Packets/MqttUnsubAckPacket.cs | 5 ++ MQTTnet.Core/Packets/MqttUnsubscribe.cs | 6 ++ .../MqttClientRetainedMessagesManager.cs | 77 ++++++++++--------- .../MainPage.xaml.cs | 30 ++++++-- 18 files changed, 111 insertions(+), 58 deletions(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index cd218576..faccaefb 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -2,7 +2,7 @@ MQTTnet - 2.5.2-rc1 + 2.5.2 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,13 +10,7 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * [Core] Fixed library reference issues for .NET 4.6 and netstandard 2.0 (Thanks to @JanEggers). -* [Core] Several COM exceptions are now wrapped properly resulting in less warnings in the trace. -* [Core] Removed application message payload from trace to reduce trace size and increase performance. -* [Client] Fixed WebSocket sub protocol negotiation for ASP.NET Core 2 servers (Thanks to @JanEggers). -* [Client] Fixed broken connection after 30 seconds then using WebSocket protocol (Thanks to @ChristianRiedl). -* [Server] Client connections are now closed when the server is stopped (Thanks to @zhudanfei). -* [Server] Published messages from the server are now retained (if set) (Thanks to @ChristianRiedl). BREAKING CHANGE! + * [Core] Refactored trace messages. Copyright Christian Kratky 2016-2017 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/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs index c859ec0d..5b0038d1 100644 --- a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs +++ b/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs @@ -32,11 +32,15 @@ namespace MQTTnet.Core.Adapter public async Task ConnectAsync(TimeSpan timeout) { + _logger.LogInformation("Connecting [Timeout={0}]", timeout); + await ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout)); } public async Task DisconnectAsync(TimeSpan timeout) { + _logger.LogInformation("Disconnecting [Timeout={0}]", timeout); + await ExecuteAndWrapExceptionAsync(() => _channel.DisconnectAsync().TimeoutAfter(timeout)); } diff --git a/MQTTnet.Core/Packets/MqttConnAckPacket.cs b/MQTTnet.Core/Packets/MqttConnAckPacket.cs index e80a0af5..0410e669 100644 --- a/MQTTnet.Core/Packets/MqttConnAckPacket.cs +++ b/MQTTnet.Core/Packets/MqttConnAckPacket.cs @@ -10,7 +10,7 @@ namespace MQTTnet.Core.Packets public override string ToString() { - return nameof(MqttConnAckPacket) + ": [ConnectReturnCode=" + ConnectReturnCode + "] [IsSessionPresent=" + IsSessionPresent + "]"; + return "ConnAck: [ConnectReturnCode=" + ConnectReturnCode + "] [IsSessionPresent=" + IsSessionPresent + "]"; } } } diff --git a/MQTTnet.Core/Packets/MqttConnectPacket.cs b/MQTTnet.Core/Packets/MqttConnectPacket.cs index b1d6e3b9..48817120 100644 --- a/MQTTnet.Core/Packets/MqttConnectPacket.cs +++ b/MQTTnet.Core/Packets/MqttConnectPacket.cs @@ -20,7 +20,7 @@ namespace MQTTnet.Core.Packets public override string ToString() { - return nameof(MqttConnectPacket) + ": [ClientId=" + ClientId + "] [Username=" + Username + "] [Password=" + Password + "] [KeepAlivePeriod=" + KeepAlivePeriod + "] [CleanSession=" + CleanSession + "]"; + return "Connect: [ClientId=" + ClientId + "] [Username=" + Username + "] [Password=" + Password + "] [KeepAlivePeriod=" + KeepAlivePeriod + "] [CleanSession=" + CleanSession + "]"; } } } diff --git a/MQTTnet.Core/Packets/MqttDisconnectPacket.cs b/MQTTnet.Core/Packets/MqttDisconnectPacket.cs index 5be8407f..4db7f795 100644 --- a/MQTTnet.Core/Packets/MqttDisconnectPacket.cs +++ b/MQTTnet.Core/Packets/MqttDisconnectPacket.cs @@ -2,5 +2,9 @@ { public sealed class MqttDisconnectPacket : MqttBasePacket { + public override string ToString() + { + return "Disconnect"; + } } } diff --git a/MQTTnet.Core/Packets/MqttPingReqPacket.cs b/MQTTnet.Core/Packets/MqttPingReqPacket.cs index 3df1c3ae..9836b5aa 100644 --- a/MQTTnet.Core/Packets/MqttPingReqPacket.cs +++ b/MQTTnet.Core/Packets/MqttPingReqPacket.cs @@ -4,7 +4,7 @@ { public override string ToString() { - return nameof(MqttPingReqPacket); + return "PingReq"; } } } diff --git a/MQTTnet.Core/Packets/MqttPingRespPacket.cs b/MQTTnet.Core/Packets/MqttPingRespPacket.cs index 753a357d..eff12b83 100644 --- a/MQTTnet.Core/Packets/MqttPingRespPacket.cs +++ b/MQTTnet.Core/Packets/MqttPingRespPacket.cs @@ -4,7 +4,7 @@ { public override string ToString() { - return nameof(MqttPingRespPacket); + return "PingResp"; } } } diff --git a/MQTTnet.Core/Packets/MqttPubAckPacket.cs b/MQTTnet.Core/Packets/MqttPubAckPacket.cs index b3e5d3e3..9e07cd32 100644 --- a/MQTTnet.Core/Packets/MqttPubAckPacket.cs +++ b/MQTTnet.Core/Packets/MqttPubAckPacket.cs @@ -2,5 +2,9 @@ { public sealed class MqttPubAckPacket : MqttBasePublishPacket { + public override string ToString() + { + return "PubAck"; + } } } diff --git a/MQTTnet.Core/Packets/MqttPubCompPacket.cs b/MQTTnet.Core/Packets/MqttPubCompPacket.cs index cb6b485f..9b819fd0 100644 --- a/MQTTnet.Core/Packets/MqttPubCompPacket.cs +++ b/MQTTnet.Core/Packets/MqttPubCompPacket.cs @@ -2,5 +2,9 @@ { public sealed class MqttPubCompPacket : MqttBasePublishPacket { + public override string ToString() + { + return "PubComp"; + } } } diff --git a/MQTTnet.Core/Packets/MqttPubRecPacket.cs b/MQTTnet.Core/Packets/MqttPubRecPacket.cs index a8ed3337..3b876559 100644 --- a/MQTTnet.Core/Packets/MqttPubRecPacket.cs +++ b/MQTTnet.Core/Packets/MqttPubRecPacket.cs @@ -2,5 +2,9 @@ { public sealed class MqttPubRecPacket : MqttBasePublishPacket { + public override string ToString() + { + return "PubRec"; + } } } diff --git a/MQTTnet.Core/Packets/MqttPubRelPacket.cs b/MQTTnet.Core/Packets/MqttPubRelPacket.cs index c95d16bf..9d926894 100644 --- a/MQTTnet.Core/Packets/MqttPubRelPacket.cs +++ b/MQTTnet.Core/Packets/MqttPubRelPacket.cs @@ -2,5 +2,9 @@ { public sealed class MqttPubRelPacket : MqttBasePublishPacket { + public override string ToString() + { + return "PubRel"; + } } } diff --git a/MQTTnet.Core/Packets/MqttPublishPacket.cs b/MQTTnet.Core/Packets/MqttPublishPacket.cs index b7d10d11..573ff691 100644 --- a/MQTTnet.Core/Packets/MqttPublishPacket.cs +++ b/MQTTnet.Core/Packets/MqttPublishPacket.cs @@ -16,9 +16,8 @@ namespace MQTTnet.Core.Packets public override string ToString() { - return nameof(MqttPublishPacket) + - ": [Topic=" + Topic + "]" + - " [PayloadLength=" + Payload?.Length + "]" + + return "Publish: [Topic=" + Topic + "]" + + " [Payload.Length=" + Payload?.Length + "]" + " [QoSLevel=" + QualityOfServiceLevel + "]" + " [Dup=" + Dup + "]" + " [Retain=" + Retain + "]" + diff --git a/MQTTnet.Core/Packets/MqttSubAckPacket.cs b/MQTTnet.Core/Packets/MqttSubAckPacket.cs index 5882d4c8..05431a3f 100644 --- a/MQTTnet.Core/Packets/MqttSubAckPacket.cs +++ b/MQTTnet.Core/Packets/MqttSubAckPacket.cs @@ -13,7 +13,7 @@ namespace MQTTnet.Core.Packets public override string ToString() { var subscribeReturnCodesText = string.Join(",", SubscribeReturnCodes.Select(f => f.ToString())); - return nameof(MqttSubAckPacket) + ": [PacketIdentifier=" + PacketIdentifier + "] [SubscribeReturnCodes=" + subscribeReturnCodesText + "]"; + return "SubAck: [PacketIdentifier=" + PacketIdentifier + "] [SubscribeReturnCodes=" + subscribeReturnCodesText + "]"; } } } diff --git a/MQTTnet.Core/Packets/MqttSubscribePacket.cs b/MQTTnet.Core/Packets/MqttSubscribePacket.cs index 5cf1c260..c911efcc 100644 --- a/MQTTnet.Core/Packets/MqttSubscribePacket.cs +++ b/MQTTnet.Core/Packets/MqttSubscribePacket.cs @@ -12,7 +12,7 @@ namespace MQTTnet.Core.Packets public override string ToString() { var topicFiltersText = string.Join(",", TopicFilters.Select(f => f.Topic + "@" + f.QualityOfServiceLevel)); - return nameof(MqttSubscribePacket) + ": [PacketIdentifier=" + PacketIdentifier + "] [TopicFilters=" + topicFiltersText + "]"; + return "Subscribe: [PacketIdentifier=" + PacketIdentifier + "] [TopicFilters=" + topicFiltersText + "]"; } } } diff --git a/MQTTnet.Core/Packets/MqttUnsubAckPacket.cs b/MQTTnet.Core/Packets/MqttUnsubAckPacket.cs index 57a5a7dd..3554fa95 100644 --- a/MQTTnet.Core/Packets/MqttUnsubAckPacket.cs +++ b/MQTTnet.Core/Packets/MqttUnsubAckPacket.cs @@ -3,5 +3,10 @@ public sealed class MqttUnsubAckPacket : MqttBasePacket, IMqttPacketWithIdentifier { public ushort PacketIdentifier { get; set; } + + public override string ToString() + { + return "UnsubAck: [PacketIdentifier=" + PacketIdentifier + "]"; + } } } diff --git a/MQTTnet.Core/Packets/MqttUnsubscribe.cs b/MQTTnet.Core/Packets/MqttUnsubscribe.cs index 269bfcbb..1e06e50e 100644 --- a/MQTTnet.Core/Packets/MqttUnsubscribe.cs +++ b/MQTTnet.Core/Packets/MqttUnsubscribe.cs @@ -7,5 +7,11 @@ namespace MQTTnet.Core.Packets public ushort PacketIdentifier { get; set; } public IList TopicFilters { get; set; } = new List(); + + public override string ToString() + { + var topicFiltersText = string.Join(",", TopicFilters); + return "Subscribe: [PacketIdentifier=" + PacketIdentifier + "] [TopicFilters=" + topicFiltersText + "]"; + } } } diff --git a/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs b/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs index ab1d4871..5fe8522c 100644 --- a/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs +++ b/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs @@ -57,42 +57,7 @@ namespace MQTTnet.Core.Server await _gate.WaitAsync().ConfigureAwait(false); try { - var saveIsRequired = false; - - if (applicationMessage.Payload?.Any() == false) - { - saveIsRequired = _retainedMessages.Remove(applicationMessage.Topic); - _logger.LogInformation("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic); - } - else - { - if (!_retainedMessages.ContainsKey(applicationMessage.Topic)) - { - _retainedMessages[applicationMessage.Topic] = applicationMessage; - saveIsRequired = true; - } - else - { - var existingMessage = _retainedMessages[applicationMessage.Topic]; - if (existingMessage.QualityOfServiceLevel != applicationMessage.QualityOfServiceLevel || !existingMessage.Payload.SequenceEqual(applicationMessage.Payload ?? new byte[0])) - { - _retainedMessages[applicationMessage.Topic] = applicationMessage; - saveIsRequired = true; - } - } - - _logger.LogInformation("Client '{0}' set retained message for topic '{1}'.", clientId, applicationMessage.Topic); - } - - if (!saveIsRequired) - { - _logger.LogTrace("Skipped saving retained messages because no changes were detected."); - } - - if (saveIsRequired && _options.Storage != null) - { - await _options.Storage.SaveRetainedMessagesAsync(_retainedMessages.Values.ToList()); - } + await HandleMessageInternalAsync(clientId, applicationMessage); } catch (Exception exception) { @@ -137,5 +102,45 @@ namespace MQTTnet.Core.Server return retainedMessages; } + + private async Task HandleMessageInternalAsync(string clientId, MqttApplicationMessage applicationMessage) + { + var saveIsRequired = false; + + if (applicationMessage.Payload?.Any() == false) + { + saveIsRequired = _retainedMessages.Remove(applicationMessage.Topic); + _logger.LogInformation("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic); + } + else + { + if (!_retainedMessages.ContainsKey(applicationMessage.Topic)) + { + _retainedMessages[applicationMessage.Topic] = applicationMessage; + saveIsRequired = true; + } + else + { + var existingMessage = _retainedMessages[applicationMessage.Topic]; + if (existingMessage.QualityOfServiceLevel != applicationMessage.QualityOfServiceLevel || !existingMessage.Payload.SequenceEqual(applicationMessage.Payload ?? new byte[0])) + { + _retainedMessages[applicationMessage.Topic] = applicationMessage; + saveIsRequired = true; + } + } + + _logger.LogInformation("Client '{0}' set retained message for topic '{1}'.", clientId, applicationMessage.Topic); + } + + if (!saveIsRequired) + { + _logger.LogTrace("Skipped saving retained messages because no changes were detected."); + } + + if (saveIsRequired && _options.Storage != null) + { + await _options.Storage.SaveRetainedMessagesAsync(_retainedMessages.Values.ToList()); + } + } } } diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index 5e1a1261..fcf6d091 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Text; using System.Threading.Tasks; using Windows.Security.Cryptography.Certificates; @@ -18,6 +19,8 @@ namespace MQTTnet.TestApp.UniversalWindows { public sealed partial class MainPage { + private readonly ConcurrentQueue _traceMessages = new ConcurrentQueue(); + private IMqttClient _mqttClient; private IMqttServer _mqttServer; @@ -30,15 +33,32 @@ namespace MQTTnet.TestApp.UniversalWindows private async void OnTraceMessagePublished(object sender, MqttNetTraceMessagePublishedEventArgs e) { - var text = $"[{e.TraceMessage.Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{e.TraceMessage.Level}] [{e.TraceMessage.Source}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Message}]{Environment.NewLine}"; - if (e.TraceMessage.Exception != null) + _traceMessages.Enqueue(e.TraceMessage); + while (_traceMessages.Count > 100) { - text += $"{e.TraceMessage.Exception}{Environment.NewLine}"; + _traceMessages.TryDequeue(out _); } - + + var logText = new StringBuilder(); + foreach (var traceMessage in _traceMessages) + { + logText.AppendFormat( + "[{0:yyyy-MM-dd HH:mm:ss.fff}] [{1}] [{2}] [{3}] [{4}]{5}", traceMessage.Timestamp, + traceMessage.Level, + traceMessage.Source, + traceMessage.ThreadId, + traceMessage.Message, + Environment.NewLine); + + if (traceMessage.Exception != null) + { + logText.AppendLine(traceMessage.Exception.ToString()); + } + } + await Trace.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () => { - Trace.Text += text; + Trace.Text = logText.ToString(); }); } From 861d3dfa0f4503d9b7cf44612bf5fb5778edba43 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 21 Nov 2017 21:00:48 +0100 Subject: [PATCH 058/149] Fix version info --- Build/MQTTnet.AspNetCore.nuspec | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index 30717332..b29ad5c3 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -2,7 +2,7 @@ MQTTnet.AspNetCore - 2.5.1 + 2.5.2 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,13 +10,14 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false This is a support library to integrate MQTTnet into AspNetCore. - * Updated to MQTTnet 2.5.1. + * Updated to MQTTnet 2.5.2. +* Fixed WebSocket protocol negotiation. Copyright Christian Kratky 2016-2017 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 77b80dc53ea8c24ca2754e90c72f7160a94383a4 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Wed, 22 Nov 2017 22:30:55 +0100 Subject: [PATCH 059/149] Removed 3rd-Party libraries. --- Build/MQTTnet.nuspec | 27 +--- .../MQTTnet.AspnetCore/MqttHostedServer.cs | 16 +- .../MqttWebSocketServerAdapter.cs | 11 +- .../MqttWebSocketServerChannel.cs | 2 +- .../ServiceCollectionExtensions.cs | 2 - .../Diagnostics/MqttNetConsoleTrace.cs | 50 ++++++ .../MqttClientAdapterFactory.cs | 26 ++++ .../Implementations/MqttServerAdapter.Uwp.cs | 13 +- .../Implementations/MqttServerAdapter.cs | 17 +-- .../Implementations/MqttTcpChannel.Uwp.cs | 2 +- .../Implementations/MqttTcpChannel.cs | 2 +- .../Implementations/MqttWebSocketChannel.cs | 13 +- .../MQTTnet.Netstandard.csproj | 25 +-- Frameworks/MQTTnet.NetStandard/MqttFactory.cs | 128 +++------------- .../ServiceCollectionExtensions.cs | 70 --------- ...ationAdapter.cs => IMqttChannelAdapter.cs} | 2 +- .../IMqttCommunicationAdapterFactory.cs | 12 -- ...cationAdapter.cs => MqttChannelAdapter.cs} | 18 +-- ...ons.cs => MqttChannelAdapterExtensions.cs} | 4 +- ...qttServerAdapterClientAcceptedEventArgs.cs | 4 +- ...ommunicationChannel.cs => IMqttChannel.cs} | 2 +- .../Client/IMqttClientAdapterFactory.cs | 10 ++ MQTTnet.Core/Client/IMqttClientFactory.cs | 7 +- MQTTnet.Core/Client/IMqttClientOptions.cs | 4 - MQTTnet.Core/Client/MqttClient.cs | 60 ++++---- MQTTnet.Core/Client/MqttClientOptions.cs | 3 - .../Client/MqttClientOptionsBuilder.cs | 6 - MQTTnet.Core/Client/MqttPacketDispatcher.cs | 8 +- MQTTnet.Core/Diagnostics/IMqttNetLogger.cs | 21 +++ MQTTnet.Core/Diagnostics/MqttNetGlobalLog.cs | 18 +++ MQTTnet.Core/Diagnostics/MqttNetLogLevel.cs | 13 ++ ...ttTraceMessage.cs => MqttNetLogMessage.cs} | 10 +- .../MqttNetLogMessagePublishedEventArgs.cs | 14 ++ MQTTnet.Core/Diagnostics/MqttNetLogger.cs | 87 +++++++---- MQTTnet.Core/Diagnostics/MqttNetTrace.cs | 35 ----- .../MqttNetTraceMessagePublishedEventArgs.cs | 14 -- MQTTnet.Core/MQTTnet.Core.csproj | 10 +- .../ManagedClient/ManagedMqttClient.cs | 38 ++--- .../IMqttClientRetainedMessageManager.cs | 15 -- .../Server/IMqttClientSesssionFactory.cs | 7 - MQTTnet.Core/Server/IMqttServer.cs | 2 +- MQTTnet.Core/Server/IMqttServerFactory.cs | 6 +- .../Server/MqttClientPendingMessagesQueue.cs | 24 +-- MQTTnet.Core/Server/MqttClientSession.cs | 44 +++--- .../Server/MqttClientSessionsManager.cs | 42 ++--- .../Server/MqttClientSubscriptionsManager.cs | 5 +- ...ager.cs => MqttRetainedMessagesManager.cs} | 21 ++- MQTTnet.Core/Server/MqttServer.cs | 105 +++++++------ .../MQTTnet.Core.Tests.csproj | 2 +- .../MqttLoggerProviderTest.cs | 51 ------- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 143 +++++------------- .../MqttSubscriptionsManagerTests.cs | 9 +- .../ServiceCollectionTest.cs | 30 ---- .../TestClientSessionFactory.cs | 14 -- Tests/MQTTnet.Core.Tests/TestLogger.cs | 26 ---- .../TestMqttCommunicationAdapter.cs | 2 +- .../TestMqttCommunicationAdapterFactory.cs | 17 +-- .../TestMqttServerAdapter.cs | 6 +- Tests/MQTTnet.TestApp.NetCore/ClientTest.cs | 4 +- .../MQTTnet.TestApp.NetCore.csproj | 6 - .../ManagedClientTest.cs | 12 +- .../PerformanceTest.cs | 57 ++----- Tests/MQTTnet.TestApp.NetCore/Program.cs | 3 - Tests/MQTTnet.TestApp.NetCore/ServerTest.cs | 47 +++--- .../MQTTnet.TestApp.UniversalWindows.csproj | 6 - .../MainPage.xaml.cs | 121 ++++++--------- 66 files changed, 626 insertions(+), 1005 deletions(-) create mode 100644 Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetConsoleTrace.cs create mode 100644 Frameworks/MQTTnet.NetStandard/Implementations/MqttClientAdapterFactory.cs delete mode 100644 Frameworks/MQTTnet.NetStandard/ServiceCollectionExtensions.cs rename MQTTnet.Core/Adapter/{IMqttCommunicationAdapter.cs => IMqttChannelAdapter.cs} (92%) delete mode 100644 MQTTnet.Core/Adapter/IMqttCommunicationAdapterFactory.cs rename MQTTnet.Core/Adapter/{MqttChannelCommunicationAdapter.cs => MqttChannelAdapter.cs} (89%) rename MQTTnet.Core/Adapter/{MqttCommunicationAdapterExtensions.cs => MqttChannelAdapterExtensions.cs} (58%) rename MQTTnet.Core/Channel/{IMqttCommunicationChannel.cs => IMqttChannel.cs} (83%) create mode 100644 MQTTnet.Core/Client/IMqttClientAdapterFactory.cs create mode 100644 MQTTnet.Core/Diagnostics/IMqttNetLogger.cs create mode 100644 MQTTnet.Core/Diagnostics/MqttNetGlobalLog.cs create mode 100644 MQTTnet.Core/Diagnostics/MqttNetLogLevel.cs rename MQTTnet.Core/Diagnostics/{MqttTraceMessage.cs => MqttNetLogMessage.cs} (61%) create mode 100644 MQTTnet.Core/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs delete mode 100644 MQTTnet.Core/Diagnostics/MqttNetTrace.cs delete mode 100644 MQTTnet.Core/Diagnostics/MqttNetTraceMessagePublishedEventArgs.cs delete mode 100644 MQTTnet.Core/Server/IMqttClientRetainedMessageManager.cs delete mode 100644 MQTTnet.Core/Server/IMqttClientSesssionFactory.cs rename MQTTnet.Core/Server/{MqttClientRetainedMessagesManager.cs => MqttRetainedMessagesManager.cs} (80%) delete mode 100644 Tests/MQTTnet.Core.Tests/MqttLoggerProviderTest.cs delete mode 100644 Tests/MQTTnet.Core.Tests/ServiceCollectionTest.cs delete mode 100644 Tests/MQTTnet.Core.Tests/TestClientSessionFactory.cs delete mode 100644 Tests/MQTTnet.Core.Tests/TestLogger.cs diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index faccaefb..8dd284ea 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -2,7 +2,7 @@ MQTTnet - 2.5.2 + 2.5.3 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,7 +10,9 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * [Core] Refactored trace messages. + * [Core] Removed all dependencies to other libraries (BREAKING CHANGE!). +* [Core] Updated SDK libraries. +* [Client] Fixed broken support for WebSocketSecure connections (Thanks to @StAI). Copyright Christian Kratky 2016-2017 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 @@ -18,43 +20,26 @@ - - - - - + - - - - - - - - + - - - - - - diff --git a/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs b/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs index 8d005187..e21b8fe5 100644 --- a/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs +++ b/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs @@ -2,29 +2,27 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using MQTTnet.Core.Adapter; +using MQTTnet.Core.Diagnostics; using MQTTnet.Core.Server; namespace MQTTnet.AspNetCore { public class MqttHostedServer : MqttServer, IHostedService { + private readonly MqttServerOptions _options; + public MqttHostedServer( - IOptions options, + MqttServerOptions options, IEnumerable adapters, - ILogger logger, - MqttClientSessionsManager clientSessionsManager, - IMqttClientRetainedMessageManager clientRetainedMessageManager - ) - : base(options, adapters, logger, clientSessionsManager, clientRetainedMessageManager) + IMqttNetLogger logger) : base(adapters, logger) { + _options = options; } public Task StartAsync(CancellationToken cancellationToken) { - return StartAsync(); + return StartAsync(_options); } public Task StopAsync(CancellationToken cancellationToken) diff --git a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs index 0e3a3d5f..27810924 100644 --- a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs +++ b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs @@ -2,19 +2,14 @@ using System.Net.WebSockets; using System.Threading.Tasks; using MQTTnet.Core.Adapter; +using MQTTnet.Core.Diagnostics; +using MQTTnet.Core.Serializer; using MQTTnet.Core.Server; namespace MQTTnet.AspNetCore { public class MqttWebSocketServerAdapter : IMqttServerAdapter, IDisposable { - private readonly IMqttCommunicationAdapterFactory _mqttCommunicationAdapterFactory; - - public MqttWebSocketServerAdapter(IMqttCommunicationAdapterFactory mqttCommunicationAdapterFactory) - { - _mqttCommunicationAdapterFactory = mqttCommunicationAdapterFactory ?? throw new ArgumentNullException(nameof(mqttCommunicationAdapterFactory)); - } - public event EventHandler ClientAccepted; public Task StartAsync(MqttServerOptions options) @@ -32,7 +27,7 @@ namespace MQTTnet.AspNetCore if (webSocket == null) throw new ArgumentNullException(nameof(webSocket)); var channel = new MqttWebSocketServerChannel(webSocket); - var clientAdapter = _mqttCommunicationAdapterFactory.CreateServerCommunicationAdapter(channel); + var clientAdapter = new MqttChannelAdapter(channel, new MqttPacketSerializer(), new MqttNetLogger()); var eventArgs = new MqttServerAdapterClientAcceptedEventArgs(clientAdapter); ClientAccepted?.Invoke(this, eventArgs); diff --git a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerChannel.cs b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerChannel.cs index 54cfb0b9..55b49400 100644 --- a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerChannel.cs +++ b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerChannel.cs @@ -8,7 +8,7 @@ using MQTTnet.Implementations; namespace MQTTnet.AspNetCore { - public class MqttWebSocketServerChannel : IMqttCommunicationChannel, IDisposable + public class MqttWebSocketServerChannel : IMqttChannel, IDisposable { private WebSocket _webSocket; diff --git a/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs b/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs index f915ab43..f39b1cf8 100644 --- a/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs +++ b/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs @@ -9,8 +9,6 @@ namespace MQTTnet.AspNetCore { public static IServiceCollection AddHostedMqttServer(this IServiceCollection services) { - services.AddMqttServerServices(); - services.AddSingleton(s => s.GetService()); services.AddSingleton(s => s.GetService()); services.AddSingleton(); diff --git a/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetConsoleTrace.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetConsoleTrace.cs new file mode 100644 index 00000000..d660b17c --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetConsoleTrace.cs @@ -0,0 +1,50 @@ +using System; +using System.Text; +using MQTTnet.Core.Diagnostics; + +namespace MQTTnet.Diagnostics +{ + public static class MqttNetConsoleTrace + { + private static readonly object Lock = new object(); + + public static void ForwardToConsole() + { + MqttNetGlobalLog.LogMessagePublished -= PrintToConsole; + MqttNetGlobalLog.LogMessagePublished += PrintToConsole; + } + + private static void PrintToConsole(object sender, MqttNetLogMessagePublishedEventArgs e) + { + var output = new StringBuilder(); + output.AppendLine($">> [{e.TraceMessage.Timestamp:O}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}"); + if (e.TraceMessage.Exception != null) + { + output.AppendLine(e.TraceMessage.Exception.ToString()); + } + + lock (Lock) + { + var backupColor = Console.ForegroundColor; + switch (e.TraceMessage.Level) + { + case MqttNetLogLevel.Error: + Console.ForegroundColor = ConsoleColor.Red; + break; + case MqttNetLogLevel.Warning: + Console.ForegroundColor = ConsoleColor.Yellow; + break; + case MqttNetLogLevel.Info: + Console.ForegroundColor = ConsoleColor.Green; + break; + case MqttNetLogLevel.Verbose: + Console.ForegroundColor = ConsoleColor.Gray; + break; + } + + Console.Write(output); + Console.ForegroundColor = backupColor; + } + } + } +} \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttClientAdapterFactory.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttClientAdapterFactory.cs new file mode 100644 index 00000000..9884c86f --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttClientAdapterFactory.cs @@ -0,0 +1,26 @@ +using System; +using MQTTnet.Core.Adapter; +using MQTTnet.Core.Client; +using MQTTnet.Core.Diagnostics; +using MQTTnet.Core.Serializer; + +namespace MQTTnet.Implementations +{ + public class MqttClientAdapterFactory : IMqttClientAdapterFactory + { + public IMqttChannelAdapter CreateClientAdapter(IMqttClientChannelOptions options, IMqttNetLogger logger) + { + if (options == null) throw new ArgumentNullException(nameof(options)); + + switch (options) + { + case MqttClientTcpOptions tcpOptions: + return new MqttChannelAdapter(new MqttTcpChannel(tcpOptions), new MqttPacketSerializer(), logger); + case MqttClientWebSocketOptions webSocketOptions: + return new MqttChannelAdapter(new MqttWebSocketChannel(webSocketOptions), new MqttPacketSerializer(), logger); + default: + throw new NotSupportedException(); + } + } + } +} diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs index 658cfe83..1b8a43cd 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs @@ -4,20 +4,19 @@ using System.Threading.Tasks; using MQTTnet.Core.Adapter; using MQTTnet.Core.Server; using Windows.Networking.Sockets; -using Microsoft.Extensions.Logging; +using MQTTnet.Core.Diagnostics; +using MQTTnet.Core.Serializer; namespace MQTTnet.Implementations { public class MqttServerAdapter : IMqttServerAdapter, IDisposable { - private readonly ILogger _logger; - private readonly IMqttCommunicationAdapterFactory _communicationAdapterFactory; + private readonly IMqttNetLogger _logger; private StreamSocketListener _defaultEndpointSocket; - public MqttServerAdapter(ILogger logger, IMqttCommunicationAdapterFactory communicationAdapterFactory) + public MqttServerAdapter(IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _communicationAdapterFactory = communicationAdapterFactory ?? throw new ArgumentNullException(nameof(communicationAdapterFactory)); } public event EventHandler ClientAccepted; @@ -63,12 +62,12 @@ namespace MQTTnet.Implementations { try { - var clientAdapter = _communicationAdapterFactory.CreateServerCommunicationAdapter(new MqttTcpChannel(args.Socket)); + var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket), new MqttPacketSerializer(), _logger); ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Error while accepting connection at default endpoint."); + _logger.Error(exception, "Error while accepting connection at default endpoint."); } } } diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs index e3f048db..3b8515c5 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs @@ -9,24 +9,23 @@ using System.Threading; using System.Threading.Tasks; using MQTTnet.Core.Adapter; using MQTTnet.Core.Server; -using Microsoft.Extensions.Logging; +using MQTTnet.Core.Diagnostics; +using MQTTnet.Core.Serializer; namespace MQTTnet.Implementations { public class MqttServerAdapter : IMqttServerAdapter, IDisposable { - private readonly ILogger _logger; - private readonly IMqttCommunicationAdapterFactory _communicationAdapterFactory; + private readonly IMqttNetLogger _logger; private CancellationTokenSource _cancellationTokenSource; private Socket _defaultEndpointSocket; private Socket _tlsEndpointSocket; private X509Certificate2 _tlsCertificate; - public MqttServerAdapter(ILogger logger, IMqttCommunicationAdapterFactory communicationAdapterFactory) + public MqttServerAdapter(IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _communicationAdapterFactory = communicationAdapterFactory ?? throw new ArgumentNullException(nameof(communicationAdapterFactory)); } public event EventHandler ClientAccepted; @@ -103,12 +102,12 @@ namespace MQTTnet.Implementations #else var clientSocket = await _defaultEndpointSocket.AcceptAsync().ConfigureAwait(false); #endif - var clientAdapter = _communicationAdapterFactory.CreateServerCommunicationAdapter(new MqttTcpChannel(clientSocket, null)); + var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, null), new MqttPacketSerializer(), _logger); ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Error while accepting connection at default endpoint."); + _logger.Error(exception, "Error while accepting connection at default endpoint."); //excessive CPU consumed if in endless loop of socket errors await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); @@ -131,12 +130,12 @@ namespace MQTTnet.Implementations var sslStream = new SslStream(new NetworkStream(clientSocket)); await sslStream.AuthenticateAsServerAsync(_tlsCertificate, false, SslProtocols.Tls12, false).ConfigureAwait(false); - var clientAdapter = _communicationAdapterFactory.CreateServerCommunicationAdapter(new MqttTcpChannel(clientSocket, sslStream)); + var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, sslStream), new MqttPacketSerializer(), _logger); ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Error while accepting connection at TLS endpoint."); + _logger.Error(exception, "Error while accepting connection at TLS endpoint."); //excessive CPU consumed if in endless loop of socket errors await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs index 06fa1377..964bfbfe 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs @@ -13,7 +13,7 @@ using MQTTnet.Core.Client; namespace MQTTnet.Implementations { - public sealed class MqttTcpChannel : IMqttCommunicationChannel, IDisposable + public sealed class MqttTcpChannel : IMqttChannel, IDisposable { private readonly MqttClientTcpOptions _options; private StreamSocket _socket; diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs index a7e40268..ce9dcf6c 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs @@ -12,7 +12,7 @@ using System.Linq; namespace MQTTnet.Implementations { - public sealed class MqttTcpChannel : IMqttCommunicationChannel, IDisposable + public sealed class MqttTcpChannel : IMqttChannel, IDisposable { private readonly MqttClientTcpOptions _options; diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs index 8f56c945..9046bb9c 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; namespace MQTTnet.Implementations { - public sealed class MqttWebSocketChannel : IMqttCommunicationChannel, IDisposable + public sealed class MqttWebSocketChannel : IMqttChannel, IDisposable { // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global @@ -29,9 +29,16 @@ namespace MQTTnet.Implementations public async Task ConnectAsync() { var uri = _options.Uri; - if (!uri.StartsWith("ws://", StringComparison.OrdinalIgnoreCase)) + if (!uri.StartsWith("ws://", StringComparison.OrdinalIgnoreCase) && !uri.StartsWith("wss://", StringComparison.OrdinalIgnoreCase)) { - uri = "ws://" + uri; + if (!_options.TlsOptions.UseTls) + { + uri = "ws://" + uri; + } + else + { + uri = "wss://" + uri; + } } _webSocket = new ClientWebSocket(); diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj index 6349d3ea..9b6211d8 100644 --- a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -4,8 +4,10 @@ netstandard1.3;netstandard2.0;net452;net461;uap10.0 MQTTnet MQTTnet - 2.5.2.0 - 2.5.2.0 + False + Full + 2.5.3.0 + 2.5.3.0 0.0.0.0 @@ -31,9 +33,6 @@ - - - @@ -42,36 +41,22 @@ - - - - - - - - - - + - - - - - \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs index 6037929e..99e57af6 100644 --- a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs @@ -1,130 +1,52 @@ using System; +using System.Collections.Generic; using MQTTnet.Core.Adapter; using MQTTnet.Core.Client; -using MQTTnet.Core.Serializer; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using MQTTnet.Implementations; using MQTTnet.Core.ManagedClient; using MQTTnet.Core.Server; -using MQTTnet.Core.Channel; +using MQTTnet.Core.Diagnostics; namespace MQTTnet { - public class MqttFactory : IMqttCommunicationAdapterFactory, IMqttClientSesssionFactory, IMqttClientFactory, IMqttServerFactory + public class MqttFactory : IMqttClientFactory, IMqttServerFactory { - private readonly IServiceProvider _serviceProvider; - - public MqttFactory() - : this(BuildServiceProvider()) - { - } - - public MqttFactory(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); - } - - public ILoggerFactory GetLoggerFactory() - { - return _serviceProvider.GetRequiredService(); - } - - public IMqttCommunicationAdapter CreateClientCommunicationAdapter(IMqttClientOptions options) - { - var logger = _serviceProvider.GetRequiredService>(); - return new MqttChannelCommunicationAdapter(CreateCommunicationChannel(options.ChannelOptions), CreateSerializer(options.ProtocolVersion), logger); - } - - public IMqttCommunicationAdapter CreateServerCommunicationAdapter(IMqttCommunicationChannel channel) - { - var serializer = _serviceProvider.GetRequiredService(); - var logger = _serviceProvider.GetRequiredService>(); - return new MqttChannelCommunicationAdapter(channel, serializer, logger); - } - - public IMqttCommunicationChannel CreateCommunicationChannel(IMqttClientChannelOptions options) - { - if (options == null) throw new ArgumentNullException(nameof(options)); - - switch (options) - { - case MqttClientTcpOptions tcpOptions: - return CreateTcpChannel(tcpOptions); - case MqttClientWebSocketOptions webSocketOptions: - return CreateWebSocketChannel(webSocketOptions); - default: - throw new NotSupportedException(); - } - } - - public MqttTcpChannel CreateTcpChannel(MqttClientTcpOptions tcpOptions) - { - return new MqttTcpChannel(tcpOptions); - } - - public MqttWebSocketChannel CreateWebSocketChannel(MqttClientWebSocketOptions webSocketOptions) - { - return new MqttWebSocketChannel(webSocketOptions); - } - - public MqttPacketSerializer CreateSerializer(MqttProtocolVersion protocolVersion) - { - return new MqttPacketSerializer - { - ProtocolVersion = protocolVersion - }; - } - - public MqttClientSession CreateClientSession(string clientId, MqttClientSessionsManager clientSessionsManager) - { - return new MqttClientSession( - clientId, - _serviceProvider.GetRequiredService>(), - clientSessionsManager, - _serviceProvider.GetRequiredService(), - _serviceProvider.GetRequiredService>(), - _serviceProvider.GetRequiredService>()); - } - public IMqttClient CreateMqttClient() { - return _serviceProvider.GetRequiredService(); + return CreateMqttClient(new MqttNetLogger()); + } + + public IMqttClient CreateMqttClient(IMqttNetLogger logger) + { + if (logger == null) throw new ArgumentNullException(nameof(logger)); + + return new MqttClient(new MqttClientAdapterFactory(), logger); } public IManagedMqttClient CreateManagedMqttClient() { - return _serviceProvider.GetRequiredService(); + return new ManagedMqttClient(CreateMqttClient(), new MqttNetLogger()); + } + + public IManagedMqttClient CreateManagedMqttClient(IMqttNetLogger logger) + { + if (logger == null) throw new ArgumentNullException(nameof(logger)); + + return new ManagedMqttClient(CreateMqttClient(), logger); } public IMqttServer CreateMqttServer() { - return _serviceProvider.GetRequiredService(); + var logger = new MqttNetLogger(); + return CreateMqttServer(new List { new MqttServerAdapter(logger) }, logger); } - public IMqttServer CreateMqttServer(Action configure) + public IMqttServer CreateMqttServer(IEnumerable adapters, IMqttNetLogger logger) { - if (configure == null) throw new ArgumentNullException(nameof(configure)); + if (adapters == null) throw new ArgumentNullException(nameof(adapters)); + if (logger == null) throw new ArgumentNullException(nameof(logger)); - var options = _serviceProvider.GetRequiredService>(); - configure(options.Value); - - return _serviceProvider.GetRequiredService(); - } - - private static IServiceProvider BuildServiceProvider() - { - var serviceProvider = new ServiceCollection() - .AddMqttClient() - .AddMqttServer() - .AddLogging() - .BuildServiceProvider(); - - serviceProvider.GetRequiredService() - .AddMqttTrace(); - - return serviceProvider; + return new MqttServer(adapters, logger); } } } \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/ServiceCollectionExtensions.cs b/Frameworks/MQTTnet.NetStandard/ServiceCollectionExtensions.cs deleted file mode 100644 index 4e6639a7..00000000 --- a/Frameworks/MQTTnet.NetStandard/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Client; -using MQTTnet.Core.ManagedClient; -using MQTTnet.Core.Serializer; -using MQTTnet.Core.Server; -using MQTTnet.Implementations; -using System; -using Microsoft.Extensions.Logging; -using MQTTnet.Core.Diagnostics; - -namespace MQTTnet -{ - public static class ServiceCollectionExtensions - { - public static IServiceCollection AddMqttServer(this IServiceCollection services) - { - services.AddMqttServerServices(); - - services.AddSingleton(s => s.GetService()); - services.AddSingleton(); - - return services; - } - - public static IServiceCollection AddMqttServerServices(this IServiceCollection services) - { - services.AddOptions(); - services.AddSingleton(); - services.AddSingleton(s => s.GetService()); - services.AddSingleton(s => s.GetService()); - - services.AddTransient(); - services.AddTransient(); - - services.AddSingleton(); - services.AddTransient(); - services.AddSingleton(); - return services; - } - - public static IServiceCollection AddMqttServer(this IServiceCollection services, Action configureOptions) - { - return services - .AddMqttServer() - .Configure(configureOptions); - } - - public static IServiceCollection AddMqttClient(this IServiceCollection services) - { - services.AddSingleton(); - services.AddSingleton(s => s.GetService()); - - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - return services; - } - - public static ILoggerFactory AddMqttTrace(this ILoggerFactory factory) - { - factory.AddProvider(new MqttNetTrace()); - return factory; - } - } -} diff --git a/MQTTnet.Core/Adapter/IMqttCommunicationAdapter.cs b/MQTTnet.Core/Adapter/IMqttChannelAdapter.cs similarity index 92% rename from MQTTnet.Core/Adapter/IMqttCommunicationAdapter.cs rename to MQTTnet.Core/Adapter/IMqttChannelAdapter.cs index 78586f66..13908f62 100644 --- a/MQTTnet.Core/Adapter/IMqttCommunicationAdapter.cs +++ b/MQTTnet.Core/Adapter/IMqttChannelAdapter.cs @@ -7,7 +7,7 @@ using MQTTnet.Core.Serializer; namespace MQTTnet.Core.Adapter { - public interface IMqttCommunicationAdapter + public interface IMqttChannelAdapter { IMqttPacketSerializer PacketSerializer { get; } diff --git a/MQTTnet.Core/Adapter/IMqttCommunicationAdapterFactory.cs b/MQTTnet.Core/Adapter/IMqttCommunicationAdapterFactory.cs deleted file mode 100644 index 96098812..00000000 --- a/MQTTnet.Core/Adapter/IMqttCommunicationAdapterFactory.cs +++ /dev/null @@ -1,12 +0,0 @@ -using MQTTnet.Core.Client; -using MQTTnet.Core.Channel; - -namespace MQTTnet.Core.Adapter -{ - public interface IMqttCommunicationAdapterFactory - { - IMqttCommunicationAdapter CreateClientCommunicationAdapter(IMqttClientOptions options); - - IMqttCommunicationAdapter CreateServerCommunicationAdapter(IMqttCommunicationChannel channel); - } -} \ No newline at end of file diff --git a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs b/MQTTnet.Core/Adapter/MqttChannelAdapter.cs similarity index 89% rename from MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs rename to MQTTnet.Core/Adapter/MqttChannelAdapter.cs index 5b0038d1..5dfcfc01 100644 --- a/MQTTnet.Core/Adapter/MqttChannelCommunicationAdapter.cs +++ b/MQTTnet.Core/Adapter/MqttChannelAdapter.cs @@ -5,23 +5,23 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using MQTTnet.Core.Channel; +using MQTTnet.Core.Diagnostics; using MQTTnet.Core.Exceptions; using MQTTnet.Core.Internal; using MQTTnet.Core.Packets; using MQTTnet.Core.Serializer; -using Microsoft.Extensions.Logging; namespace MQTTnet.Core.Adapter { - public class MqttChannelCommunicationAdapter : IMqttCommunicationAdapter + public class MqttChannelAdapter : IMqttChannelAdapter { private const uint ErrorOperationAborted = 0x800703E3; private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); - private readonly ILogger _logger; - private readonly IMqttCommunicationChannel _channel; + private readonly IMqttNetLogger _logger; + private readonly IMqttChannel _channel; - public MqttChannelCommunicationAdapter(IMqttCommunicationChannel channel, IMqttPacketSerializer serializer, ILogger logger) + public MqttChannelAdapter(IMqttChannel channel, IMqttPacketSerializer serializer, IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _channel = channel ?? throw new ArgumentNullException(nameof(channel)); @@ -32,14 +32,14 @@ namespace MQTTnet.Core.Adapter public async Task ConnectAsync(TimeSpan timeout) { - _logger.LogInformation("Connecting [Timeout={0}]", timeout); + _logger.Info("Connecting [Timeout={0}]", timeout); await ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout)); } public async Task DisconnectAsync(TimeSpan timeout) { - _logger.LogInformation("Disconnecting [Timeout={0}]", timeout); + _logger.Info("Disconnecting [Timeout={0}]", timeout); await ExecuteAndWrapExceptionAsync(() => _channel.DisconnectAsync().TimeoutAfter(timeout)); } @@ -58,7 +58,7 @@ namespace MQTTnet.Core.Adapter continue; } - _logger.LogInformation("TX >>> {0} [Timeout={1}]", packet, timeout); + _logger.Trace("TX >>> {0} [Timeout={1}]", packet, timeout); var writeBuffer = PacketSerializer.Serialize(packet); await _channel.SendStream.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken).ConfigureAwait(false); @@ -108,7 +108,7 @@ namespace MQTTnet.Core.Adapter throw new MqttProtocolViolationException("Received malformed packet."); } - _logger.LogInformation("RX <<< {0}", packet); + _logger.Trace("RX <<< {0}", packet); } finally { diff --git a/MQTTnet.Core/Adapter/MqttCommunicationAdapterExtensions.cs b/MQTTnet.Core/Adapter/MqttChannelAdapterExtensions.cs similarity index 58% rename from MQTTnet.Core/Adapter/MqttCommunicationAdapterExtensions.cs rename to MQTTnet.Core/Adapter/MqttChannelAdapterExtensions.cs index 2142fd07..f271248f 100644 --- a/MQTTnet.Core/Adapter/MqttCommunicationAdapterExtensions.cs +++ b/MQTTnet.Core/Adapter/MqttChannelAdapterExtensions.cs @@ -5,9 +5,9 @@ using MQTTnet.Core.Packets; namespace MQTTnet.Core.Adapter { - public static class MqttCommunicationAdapterExtensions + public static class MqttChannelAdapterExtensions { - public static Task SendPacketsAsync(this IMqttCommunicationAdapter adapter, TimeSpan timeout, CancellationToken cancellationToken, params MqttBasePacket[] packets) + public static Task SendPacketsAsync(this IMqttChannelAdapter adapter, TimeSpan timeout, CancellationToken cancellationToken, params MqttBasePacket[] packets) { if (adapter == null) throw new ArgumentNullException(nameof(adapter)); diff --git a/MQTTnet.Core/Adapter/MqttServerAdapterClientAcceptedEventArgs.cs b/MQTTnet.Core/Adapter/MqttServerAdapterClientAcceptedEventArgs.cs index 6caca0e9..341f6327 100644 --- a/MQTTnet.Core/Adapter/MqttServerAdapterClientAcceptedEventArgs.cs +++ b/MQTTnet.Core/Adapter/MqttServerAdapterClientAcceptedEventArgs.cs @@ -5,12 +5,12 @@ namespace MQTTnet.Core.Adapter { public class MqttServerAdapterClientAcceptedEventArgs : EventArgs { - public MqttServerAdapterClientAcceptedEventArgs(IMqttCommunicationAdapter client) + public MqttServerAdapterClientAcceptedEventArgs(IMqttChannelAdapter client) { Client = client ?? throw new ArgumentNullException(nameof(client)); } - public IMqttCommunicationAdapter Client { get; } + public IMqttChannelAdapter Client { get; } public Task SessionTask { get; set; } } diff --git a/MQTTnet.Core/Channel/IMqttCommunicationChannel.cs b/MQTTnet.Core/Channel/IMqttChannel.cs similarity index 83% rename from MQTTnet.Core/Channel/IMqttCommunicationChannel.cs rename to MQTTnet.Core/Channel/IMqttChannel.cs index e7a74c18..92c0681b 100644 --- a/MQTTnet.Core/Channel/IMqttCommunicationChannel.cs +++ b/MQTTnet.Core/Channel/IMqttChannel.cs @@ -3,7 +3,7 @@ using System.IO; namespace MQTTnet.Core.Channel { - public interface IMqttCommunicationChannel + public interface IMqttChannel { Stream SendStream { get; } Stream ReceiveStream { get; } diff --git a/MQTTnet.Core/Client/IMqttClientAdapterFactory.cs b/MQTTnet.Core/Client/IMqttClientAdapterFactory.cs new file mode 100644 index 00000000..3bd61431 --- /dev/null +++ b/MQTTnet.Core/Client/IMqttClientAdapterFactory.cs @@ -0,0 +1,10 @@ +using MQTTnet.Core.Adapter; +using MQTTnet.Core.Diagnostics; + +namespace MQTTnet.Core.Client +{ + public interface IMqttClientAdapterFactory + { + IMqttChannelAdapter CreateClientAdapter(IMqttClientChannelOptions options, IMqttNetLogger logger); + } +} diff --git a/MQTTnet.Core/Client/IMqttClientFactory.cs b/MQTTnet.Core/Client/IMqttClientFactory.cs index c8b5ef3e..8acdb91a 100644 --- a/MQTTnet.Core/Client/IMqttClientFactory.cs +++ b/MQTTnet.Core/Client/IMqttClientFactory.cs @@ -1,4 +1,5 @@ -using MQTTnet.Core.ManagedClient; +using MQTTnet.Core.Diagnostics; +using MQTTnet.Core.ManagedClient; namespace MQTTnet.Core.Client { @@ -6,6 +7,10 @@ namespace MQTTnet.Core.Client { IMqttClient CreateMqttClient(); + IMqttClient CreateMqttClient(IMqttNetLogger logger); + IManagedMqttClient CreateManagedMqttClient(); + + IManagedMqttClient CreateManagedMqttClient(IMqttNetLogger logger); } } \ No newline at end of file diff --git a/MQTTnet.Core/Client/IMqttClientOptions.cs b/MQTTnet.Core/Client/IMqttClientOptions.cs index ae771922..9139d5cb 100644 --- a/MQTTnet.Core/Client/IMqttClientOptions.cs +++ b/MQTTnet.Core/Client/IMqttClientOptions.cs @@ -7,10 +7,6 @@ namespace MQTTnet.Core.Client { string ClientId { get; } - /// - /// The LogId is used to create a scope to correlate logging. If no value is provided the ClientId is used instead - /// - string LogId { get; } IMqttClientCredentials Credentials { get; } bool CleanSession { get; } MqttApplicationMessage WillMessage { get; } diff --git a/MQTTnet.Core/Client/MqttClient.cs b/MQTTnet.Core/Client/MqttClient.cs index fcab3fba..f270a381 100644 --- a/MQTTnet.Core/Client/MqttClient.cs +++ b/MQTTnet.Core/Client/MqttClient.cs @@ -4,33 +4,34 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MQTTnet.Core.Adapter; +using MQTTnet.Core.Diagnostics; using MQTTnet.Core.Exceptions; using MQTTnet.Core.Internal; using MQTTnet.Core.Packets; using MQTTnet.Core.Protocol; -using Microsoft.Extensions.Logging; namespace MQTTnet.Core.Client { public class MqttClient : IMqttClient { private readonly HashSet _unacknowledgedPublishPackets = new HashSet(); + + private readonly IMqttClientAdapterFactory _adapterFactory; private readonly MqttPacketDispatcher _packetDispatcher; - private readonly IMqttCommunicationAdapterFactory _communicationAdapterFactory; - private readonly ILogger _logger; + private readonly IMqttNetLogger _logger; private IMqttClientOptions _options; private bool _isReceivingPackets; private int _latestPacketIdentifier; private CancellationTokenSource _cancellationTokenSource; - private IMqttCommunicationAdapter _adapter; - private IDisposable _scopeHandle; + private IMqttChannelAdapter _adapter; - public MqttClient(IMqttCommunicationAdapterFactory communicationAdapterFactory, ILogger logger, MqttPacketDispatcher packetDispatcher) + public MqttClient(IMqttClientAdapterFactory channelFactory, IMqttNetLogger logger) { - _communicationAdapterFactory = communicationAdapterFactory ?? throw new ArgumentNullException(nameof(communicationAdapterFactory)); + _adapterFactory = channelFactory ?? throw new ArgumentNullException(nameof(channelFactory)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _packetDispatcher = packetDispatcher ?? throw new ArgumentNullException(nameof(packetDispatcher)); + + _packetDispatcher = new MqttPacketDispatcher(logger); } public event EventHandler Connected; @@ -53,17 +54,16 @@ namespace MQTTnet.Core.Client _latestPacketIdentifier = 0; _packetDispatcher.Reset(); - _adapter = _communicationAdapterFactory.CreateClientCommunicationAdapter(options); - - _scopeHandle = _logger.BeginScope(options.LogId ?? options.ClientId); - _logger.LogTrace("Trying to connect with server."); + _adapter = _adapterFactory.CreateClientAdapter(options.ChannelOptions, _logger); + + _logger.Trace("Trying to connect with server."); await _adapter.ConnectAsync(_options.CommunicationTimeout).ConfigureAwait(false); - _logger.LogTrace("Connection with server established."); + _logger.Trace("Connection with server established."); await StartReceivingPacketsAsync(_cancellationTokenSource.Token).ConfigureAwait(false); var connectResponse = await AuthenticateAsync(options.WillMessage).ConfigureAwait(false); - _logger.LogTrace("MQTT connection with server established."); + _logger.Trace("MQTT connection with server established."); if (_options.KeepAlivePeriod != TimeSpan.Zero) { @@ -76,7 +76,7 @@ namespace MQTTnet.Core.Client } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Error while connecting with server."); + _logger.Error(exception, "Error while connecting with server."); await DisconnectInternalAsync().ConfigureAwait(false); throw; } @@ -215,8 +215,6 @@ namespace MQTTnet.Core.Client private async Task DisconnectInternalAsync() { - _scopeHandle?.Dispose(); - var clientWasConnected = IsConnected; IsConnected = false; @@ -233,15 +231,15 @@ namespace MQTTnet.Core.Client try { await _adapter.DisconnectAsync(_options.CommunicationTimeout).ConfigureAwait(false); - _logger.LogInformation("Disconnected from adapter."); + _logger.Info("Disconnected from adapter."); } catch (Exception exception) { - _logger.LogWarning(new EventId(), exception, "Error while disconnecting from adapter."); + _logger.Warning(exception, "Error while disconnecting from adapter."); } finally { - _logger.LogInformation("Disconnected."); + _logger.Info("Disconnected."); Disconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(clientWasConnected)); } } @@ -250,7 +248,7 @@ namespace MQTTnet.Core.Client { try { - _logger.LogInformation("Received <<< {0}", packet); + _logger.Info("Received <<< {0}", packet); if (packet is MqttPingReqPacket) { @@ -280,7 +278,7 @@ namespace MQTTnet.Core.Client } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Unhandled exception while processing received packet."); + _logger.Error(exception, "Unhandled exception while processing received packet."); } } @@ -293,7 +291,7 @@ namespace MQTTnet.Core.Client } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Unhandled exception while handling application message."); + _logger.Error(exception, "Unhandled exception while handling application message."); } } @@ -357,7 +355,7 @@ namespace MQTTnet.Core.Client private async Task SendKeepAliveMessagesAsync(CancellationToken cancellationToken) { - _logger.LogInformation("Start sending keep alive packets."); + _logger.Info("Start sending keep alive packets."); try { @@ -388,23 +386,23 @@ namespace MQTTnet.Core.Client return; } - _logger.LogWarning(new EventId(), exception, "MQTT communication exception while sending/receiving keep alive packets."); + _logger.Warning(exception, "MQTT communication exception while sending/receiving keep alive packets."); await DisconnectInternalAsync().ConfigureAwait(false); } catch (Exception exception) { - _logger.LogWarning(new EventId(), exception, "Unhandled exception while sending/receiving keep alive packets."); + _logger.Warning(exception, "Unhandled exception while sending/receiving keep alive packets."); await DisconnectInternalAsync().ConfigureAwait(false); } finally { - _logger.LogInformation("Stopped sending keep alive packets."); + _logger.Info("Stopped sending keep alive packets."); } } private async Task ReceivePacketsAsync(CancellationToken cancellationToken) { - _logger.LogInformation("Start receiving packets."); + _logger.Info("Start receiving packets."); try { @@ -438,17 +436,17 @@ namespace MQTTnet.Core.Client return; } - _logger.LogWarning(new EventId(), exception, "MQTT communication exception while receiving packets."); + _logger.Warning(exception, "MQTT communication exception while receiving packets."); await DisconnectInternalAsync().ConfigureAwait(false); } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Unhandled exception while receiving packets."); + _logger.Error(exception, "Unhandled exception while receiving packets."); await DisconnectInternalAsync().ConfigureAwait(false); } finally { - _logger.LogInformation(nameof(MqttClient), "Stopped receiving packets."); + _logger.Info("Stopped receiving packets."); } } diff --git a/MQTTnet.Core/Client/MqttClientOptions.cs b/MQTTnet.Core/Client/MqttClientOptions.cs index 1b1c1bb8..04cf8bdb 100644 --- a/MQTTnet.Core/Client/MqttClientOptions.cs +++ b/MQTTnet.Core/Client/MqttClientOptions.cs @@ -9,9 +9,6 @@ namespace MQTTnet.Core.Client public string ClientId { get; set; } = Guid.NewGuid().ToString("N"); - /// - public string LogId { get; set; } - public bool CleanSession { get; set; } = true; public IMqttClientCredentials Credentials { get; set; } = new MqttClientCredentials(); diff --git a/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs b/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs index fb18cc09..429a3fa7 100644 --- a/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs +++ b/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs @@ -12,12 +12,6 @@ namespace MQTTnet.Core.Client private MqttClientTlsOptions _tlsOptions; - public MqttClientOptionsBuilder WithLogId(string value) - { - _options.LogId = value; - return this; - } - public MqttClientOptionsBuilder WithProtocolVersion(MqttProtocolVersion value) { _options.ProtocolVersion = value; diff --git a/MQTTnet.Core/Client/MqttPacketDispatcher.cs b/MQTTnet.Core/Client/MqttPacketDispatcher.cs index a999d697..dd9c7140 100644 --- a/MQTTnet.Core/Client/MqttPacketDispatcher.cs +++ b/MQTTnet.Core/Client/MqttPacketDispatcher.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Concurrent; using System.Threading.Tasks; +using MQTTnet.Core.Diagnostics; using MQTTnet.Core.Exceptions; using MQTTnet.Core.Internal; using MQTTnet.Core.Packets; -using Microsoft.Extensions.Logging; namespace MQTTnet.Core.Client { @@ -12,9 +12,9 @@ namespace MQTTnet.Core.Client { private readonly ConcurrentDictionary> _packetByResponseType = new ConcurrentDictionary>(); private readonly ConcurrentDictionary>> _packetByResponseTypeAndIdentifier = new ConcurrentDictionary>>(); - private readonly ILogger _logger; + private readonly IMqttNetLogger _logger; - public MqttPacketDispatcher(ILogger logger) + public MqttPacketDispatcher(IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } @@ -30,7 +30,7 @@ namespace MQTTnet.Core.Client } catch (MqttCommunicationTimedOutException) { - _logger.LogWarning("Timeout while waiting for packet of type '{0}'.", responseType.Name); + _logger.Warning("Timeout while waiting for packet of type '{0}'.", responseType.Name); throw; } finally diff --git a/MQTTnet.Core/Diagnostics/IMqttNetLogger.cs b/MQTTnet.Core/Diagnostics/IMqttNetLogger.cs new file mode 100644 index 00000000..99f7b193 --- /dev/null +++ b/MQTTnet.Core/Diagnostics/IMqttNetLogger.cs @@ -0,0 +1,21 @@ +using System; + +namespace MQTTnet.Core.Diagnostics +{ + public interface IMqttNetLogger + { + event EventHandler LogMessagePublished; + + void Trace(string message, params object[] parameters); + + void Info(string message, params object[] parameters); + + void Warning(Exception exception, string message, params object[] parameters); + + void Warning(string message, params object[] parameters); + + void Error(Exception exception, string message, params object[] parameters); + + void Error(string message, params object[] parameters); + } +} diff --git a/MQTTnet.Core/Diagnostics/MqttNetGlobalLog.cs b/MQTTnet.Core/Diagnostics/MqttNetGlobalLog.cs new file mode 100644 index 00000000..64326826 --- /dev/null +++ b/MQTTnet.Core/Diagnostics/MqttNetGlobalLog.cs @@ -0,0 +1,18 @@ +using System; + +namespace MQTTnet.Core.Diagnostics +{ + public static class MqttNetGlobalLog + { + public static event EventHandler LogMessagePublished; + + public static bool HasListeners => LogMessagePublished != null; + + public static void Publish(MqttNetLogMessage logMessage) + { + if (logMessage == null) throw new ArgumentNullException(nameof(logMessage)); + + LogMessagePublished?.Invoke(null, new MqttNetLogMessagePublishedEventArgs(logMessage)); + } + } +} diff --git a/MQTTnet.Core/Diagnostics/MqttNetLogLevel.cs b/MQTTnet.Core/Diagnostics/MqttNetLogLevel.cs new file mode 100644 index 00000000..32e5de17 --- /dev/null +++ b/MQTTnet.Core/Diagnostics/MqttNetLogLevel.cs @@ -0,0 +1,13 @@ +namespace MQTTnet.Core.Diagnostics +{ + public enum MqttNetLogLevel + { + Verbose, + + Info, + + Warning, + + Error + } +} diff --git a/MQTTnet.Core/Diagnostics/MqttTraceMessage.cs b/MQTTnet.Core/Diagnostics/MqttNetLogMessage.cs similarity index 61% rename from MQTTnet.Core/Diagnostics/MqttTraceMessage.cs rename to MQTTnet.Core/Diagnostics/MqttNetLogMessage.cs index 852aae45..e1598eb2 100644 --- a/MQTTnet.Core/Diagnostics/MqttTraceMessage.cs +++ b/MQTTnet.Core/Diagnostics/MqttNetLogMessage.cs @@ -1,12 +1,12 @@ using System; -using Microsoft.Extensions.Logging; namespace MQTTnet.Core.Diagnostics { - public sealed class MqttNetTraceMessage + public sealed class MqttNetLogMessage { - public MqttNetTraceMessage(DateTime timestamp, int threadId, string source, LogLevel level, string message, Exception exception) + public MqttNetLogMessage(string logId, DateTime timestamp, int threadId, string source, MqttNetLogLevel level, string message, Exception exception) { + LogId = logId; Timestamp = timestamp; ThreadId = threadId; Source = source; @@ -15,13 +15,15 @@ namespace MQTTnet.Core.Diagnostics Exception = exception; } + public string LogId { get; } + public DateTime Timestamp { get; } public int ThreadId { get; } public string Source { get; } - public LogLevel Level { get; } + public MqttNetLogLevel Level { get; } public string Message { get; } diff --git a/MQTTnet.Core/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs b/MQTTnet.Core/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs new file mode 100644 index 00000000..46c54685 --- /dev/null +++ b/MQTTnet.Core/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs @@ -0,0 +1,14 @@ +using System; + +namespace MQTTnet.Core.Diagnostics +{ + public sealed class MqttNetLogMessagePublishedEventArgs : EventArgs + { + public MqttNetLogMessagePublishedEventArgs(MqttNetLogMessage logMessage) + { + TraceMessage = logMessage ?? throw new ArgumentNullException(nameof(logMessage)); + } + + public MqttNetLogMessage TraceMessage { get; } + } +} diff --git a/MQTTnet.Core/Diagnostics/MqttNetLogger.cs b/MQTTnet.Core/Diagnostics/MqttNetLogger.cs index 32d96093..a879af1b 100644 --- a/MQTTnet.Core/Diagnostics/MqttNetLogger.cs +++ b/MQTTnet.Core/Diagnostics/MqttNetLogger.cs @@ -1,52 +1,73 @@ using System; -using Microsoft.Extensions.Logging; namespace MQTTnet.Core.Diagnostics { - public class MqttNetLogger : ILogger + public class MqttNetLogger : IMqttNetLogger { - private readonly string _categoryName; - private readonly MqttNetTrace _mqttNetTrace; + private readonly string _logId; - public MqttNetLogger(string categoryName, MqttNetTrace mqttNetTrace) + public MqttNetLogger(string logId = null) { - _categoryName = categoryName; - _mqttNetTrace = mqttNetTrace; + _logId = logId; + } + + public event EventHandler LogMessagePublished; + + public void Trace(string message, params object[] parameters) + { + Publish(MqttNetLogLevel.Verbose, null, message, parameters); } - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + public void Info(string message, params object[] parameters) { - if (formatter == null) - { - throw new ArgumentNullException(nameof(formatter)); - } + Publish(MqttNetLogLevel.Info, null, message, parameters); + } - if (!MqttNetTrace.HasListeners) + public void Warning(Exception exception, string message, params object[] parameters) + { + Publish(MqttNetLogLevel.Warning, exception, message, parameters); + } + + public void Warning(string message, params object[] parameters) + { + Warning(null, message, parameters); + } + + public void Error(Exception exception, string message, params object[] parameters) + { + Publish(MqttNetLogLevel.Error, exception, message, parameters); + } + + public void Error(string message, params object[] parameters) + { + Warning(null, message, parameters); + } + + private void Publish(MqttNetLogLevel logLevel, Exception exception, string message, object[] parameters) + { + var hasLocalListeners = LogMessagePublished != null; + var hasGlobalListeners = MqttNetGlobalLog.HasListeners; + + if (!hasLocalListeners && !hasGlobalListeners) { return; } - var message = formatter(state, exception); - var traceMessage = new MqttNetTraceMessage(DateTime.Now, Environment.CurrentManagedThreadId, _categoryName, logLevel, message, exception); - _mqttNetTrace.Publish(traceMessage); - } - - public bool IsEnabled(LogLevel logLevel) - { - return MqttNetTrace.HasListeners; - } - - //not supported: async local requires netstandard1.3 - //for implementation see https://github.com/aspnet/Logging/blob/dev/src/Microsoft.Extensions.Logging.Console/ConsoleLogScope.cs - public IDisposable BeginScope(TState state) - { - return new DisposableScope(); - } - - private class DisposableScope : IDisposable - { - public void Dispose() + if (parameters.Length > 0) { + message = string.Format(message, parameters); + } + + var traceMessage = new MqttNetLogMessage(_logId, DateTime.Now, Environment.CurrentManagedThreadId, typeof(TSource).Name, logLevel, message, exception); + + if (hasGlobalListeners) + { + MqttNetGlobalLog.Publish(traceMessage); + } + + if (hasLocalListeners) + { + LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(traceMessage)); } } } diff --git a/MQTTnet.Core/Diagnostics/MqttNetTrace.cs b/MQTTnet.Core/Diagnostics/MqttNetTrace.cs deleted file mode 100644 index f75c7a9b..00000000 --- a/MQTTnet.Core/Diagnostics/MqttNetTrace.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Concurrent; -using Microsoft.Extensions.Logging; - -namespace MQTTnet.Core.Diagnostics -{ - public class MqttNetTrace : ILoggerProvider - { - private readonly ConcurrentDictionary _loggers = new ConcurrentDictionary(); - - public static event EventHandler TraceMessagePublished; - - public static bool HasListeners => TraceMessagePublished != null; - - public void Publish(MqttNetTraceMessage traceMessage) - { - TraceMessagePublished?.Invoke(this, new MqttNetTraceMessagePublishedEventArgs(traceMessage)); - } - - public void Dispose() - { - TraceMessagePublished = null; - } - - public ILogger CreateLogger(string categoryName) - { - return _loggers.GetOrAdd(categoryName, CreateLoggerImplementation); - } - - private MqttNetLogger CreateLoggerImplementation(string categoryName) - { - return new MqttNetLogger(categoryName, this); - } - } -} diff --git a/MQTTnet.Core/Diagnostics/MqttNetTraceMessagePublishedEventArgs.cs b/MQTTnet.Core/Diagnostics/MqttNetTraceMessagePublishedEventArgs.cs deleted file mode 100644 index 5b8f796d..00000000 --- a/MQTTnet.Core/Diagnostics/MqttNetTraceMessagePublishedEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace MQTTnet.Core.Diagnostics -{ - public sealed class MqttNetTraceMessagePublishedEventArgs : EventArgs - { - public MqttNetTraceMessagePublishedEventArgs(MqttNetTraceMessage traceMessage) - { - TraceMessage = traceMessage ?? throw new ArgumentNullException(nameof(traceMessage)); - } - - public MqttNetTraceMessage TraceMessage { get; } - } -} diff --git a/MQTTnet.Core/MQTTnet.Core.csproj b/MQTTnet.Core/MQTTnet.Core.csproj index d50466f1..60afc301 100644 --- a/MQTTnet.Core/MQTTnet.Core.csproj +++ b/MQTTnet.Core/MQTTnet.Core.csproj @@ -17,15 +17,9 @@ - 2.5.2.0 - 2.5.2.0 + 2.5.3.0 + 2.5.3.0 - - - - - - \ No newline at end of file diff --git a/MQTTnet.Core/ManagedClient/ManagedMqttClient.cs b/MQTTnet.Core/ManagedClient/ManagedMqttClient.cs index 4eb40b23..c2e40777 100644 --- a/MQTTnet.Core/ManagedClient/ManagedMqttClient.cs +++ b/MQTTnet.Core/ManagedClient/ManagedMqttClient.cs @@ -5,9 +5,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MQTTnet.Core.Client; +using MQTTnet.Core.Diagnostics; using MQTTnet.Core.Exceptions; using MQTTnet.Core.Protocol; -using Microsoft.Extensions.Logging; namespace MQTTnet.Core.ManagedClient { @@ -18,7 +18,7 @@ namespace MQTTnet.Core.ManagedClient private readonly HashSet _subscriptions = new HashSet(); private readonly IMqttClient _mqttClient; - private readonly ILogger _logger; + private readonly IMqttNetLogger _logger; private CancellationTokenSource _connectionCancellationToken; private CancellationTokenSource _publishingCancellationToken; @@ -26,7 +26,7 @@ namespace MQTTnet.Core.ManagedClient private IManagedMqttClientOptions _options; private bool _subscriptionsNotPushed; - public ManagedMqttClient(ILogger logger, IMqttClient mqttClient) + public ManagedMqttClient(IMqttClient mqttClient, IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient)); @@ -52,10 +52,7 @@ namespace MQTTnet.Core.ManagedClient throw new NotSupportedException("The managed client does not support existing sessions."); } - if (_connectionCancellationToken != null) - { - throw new InvalidOperationException("The managed client is already started."); - } + if (_connectionCancellationToken != null) throw new InvalidOperationException("The managed client is already started."); _options = options; await _storageManager.SetStorageAsync(_options.Storage).ConfigureAwait(false); @@ -72,10 +69,10 @@ namespace MQTTnet.Core.ManagedClient _connectionCancellationToken = new CancellationTokenSource(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - Task.Factory.StartNew(() => MaintainConnectionAsync(_connectionCancellationToken.Token), _connectionCancellationToken.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false); + Task.Run(async () => await MaintainConnectionAsync(_connectionCancellationToken.Token), _connectionCancellationToken.Token).ConfigureAwait(false); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - _logger.LogInformation("Started"); + _logger.Info("Started"); } public Task StopAsync() @@ -83,6 +80,9 @@ namespace MQTTnet.Core.ManagedClient _connectionCancellationToken?.Cancel(false); _connectionCancellationToken = null; + _publishingCancellationToken?.Cancel(false); + _publishingCancellationToken = null; + while (_messageQueue.Any()) { _messageQueue.Take(); @@ -159,7 +159,7 @@ namespace MQTTnet.Core.ManagedClient _publishingCancellationToken = new CancellationTokenSource(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - Task.Factory.StartNew(() => PublishQueuedMessagesAsync(_publishingCancellationToken.Token), _publishingCancellationToken.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false); + Task.Run(async () => await PublishQueuedMessagesAsync(_publishingCancellationToken.Token), _publishingCancellationToken.Token).ConfigureAwait(false); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed continue; @@ -167,7 +167,7 @@ namespace MQTTnet.Core.ManagedClient if (connectionState == ReconnectionResult.StillConnected) { - await Task.Delay(100, _connectionCancellationToken.Token).ConfigureAwait(false); // Consider using the _Disconnected_ event here. (TaskCompletionSource) + await Task.Delay(TimeSpan.FromSeconds(1), _connectionCancellationToken.Token).ConfigureAwait(false); } } } @@ -176,16 +176,16 @@ namespace MQTTnet.Core.ManagedClient } catch (MqttCommunicationException exception) { - _logger.LogWarning(new EventId(), exception, "Communication exception while maintaining connection."); + _logger.Warning(exception, "Communication exception while maintaining connection."); } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Unhandled exception while maintaining connection."); + _logger.Error(exception, "Unhandled exception while maintaining connection."); } finally { await _mqttClient.DisconnectAsync().ConfigureAwait(false); - _logger.LogInformation("Stopped"); + _logger.Info("Stopped"); } } @@ -215,7 +215,7 @@ namespace MQTTnet.Core.ManagedClient } finally { - _logger.LogInformation("Stopped publishing messages"); + _logger.Info("Stopped publishing messages"); } } @@ -227,7 +227,7 @@ namespace MQTTnet.Core.ManagedClient } catch (MqttCommunicationException exception) { - _logger.LogWarning(new EventId(), exception, "Publishing application message failed."); + _logger.Warning(exception, "Publishing application message failed."); if (message.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) { @@ -236,13 +236,13 @@ namespace MQTTnet.Core.ManagedClient } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Unhandled exception while publishing queued application message."); + _logger.Error(exception, "Unhandled exception while publishing queued application message."); } } private async Task PushSubscriptionsAsync() { - _logger.LogInformation(nameof(ManagedMqttClient), "Synchronizing subscriptions"); + _logger.Info(nameof(ManagedMqttClient), "Synchronizing subscriptions"); List subscriptions; lock (_subscriptions) @@ -262,7 +262,7 @@ namespace MQTTnet.Core.ManagedClient } catch (Exception exception) { - _logger.LogWarning(new EventId(), exception, "Synchronizing subscriptions failed"); + _logger.Warning(exception, "Synchronizing subscriptions failed"); _subscriptionsNotPushed = true; } } diff --git a/MQTTnet.Core/Server/IMqttClientRetainedMessageManager.cs b/MQTTnet.Core/Server/IMqttClientRetainedMessageManager.cs deleted file mode 100644 index f4008998..00000000 --- a/MQTTnet.Core/Server/IMqttClientRetainedMessageManager.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using MQTTnet.Core.Packets; - -namespace MQTTnet.Core.Server -{ - public interface IMqttClientRetainedMessageManager - { - Task LoadMessagesAsync(); - - Task HandleMessageAsync(string clientId, MqttApplicationMessage applicationMessage); - - Task> GetSubscribedMessagesAsync(MqttSubscribePacket subscribePacket); - } -} diff --git a/MQTTnet.Core/Server/IMqttClientSesssionFactory.cs b/MQTTnet.Core/Server/IMqttClientSesssionFactory.cs deleted file mode 100644 index f58dd5e7..00000000 --- a/MQTTnet.Core/Server/IMqttClientSesssionFactory.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace MQTTnet.Core.Server -{ - public interface IMqttClientSesssionFactory - { - MqttClientSession CreateClientSession(string sessionId, MqttClientSessionsManager mqttClientSessionsManager); - } -} diff --git a/MQTTnet.Core/Server/IMqttServer.cs b/MQTTnet.Core/Server/IMqttServer.cs index 8d860777..936e897e 100644 --- a/MQTTnet.Core/Server/IMqttServer.cs +++ b/MQTTnet.Core/Server/IMqttServer.cs @@ -12,7 +12,7 @@ namespace MQTTnet.Core.Server Task> GetConnectedClientsAsync(); - Task StartAsync(); + Task StartAsync(MqttServerOptions options); Task StopAsync(); } } \ No newline at end of file diff --git a/MQTTnet.Core/Server/IMqttServerFactory.cs b/MQTTnet.Core/Server/IMqttServerFactory.cs index 500614b0..378dfb01 100644 --- a/MQTTnet.Core/Server/IMqttServerFactory.cs +++ b/MQTTnet.Core/Server/IMqttServerFactory.cs @@ -1,4 +1,6 @@ -using System; +using System.Collections.Generic; +using MQTTnet.Core.Adapter; +using MQTTnet.Core.Diagnostics; namespace MQTTnet.Core.Server { @@ -6,6 +8,6 @@ namespace MQTTnet.Core.Server { IMqttServer CreateMqttServer(); - IMqttServer CreateMqttServer(Action configure); + IMqttServer CreateMqttServer(IEnumerable adapters, IMqttNetLogger logger); } } \ No newline at end of file diff --git a/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs b/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs index 16c90944..bea60397 100644 --- a/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs +++ b/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs @@ -3,10 +3,10 @@ using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; using MQTTnet.Core.Adapter; +using MQTTnet.Core.Diagnostics; using MQTTnet.Core.Exceptions; using MQTTnet.Core.Packets; using MQTTnet.Core.Protocol; -using Microsoft.Extensions.Logging; namespace MQTTnet.Core.Server { @@ -15,16 +15,16 @@ namespace MQTTnet.Core.Server private readonly BlockingCollection _pendingPublishPackets = new BlockingCollection(); private readonly MqttServerOptions _options; private readonly MqttClientSession _session; - private readonly ILogger _logger; + private readonly IMqttNetLogger _logger; - public MqttClientPendingMessagesQueue(MqttServerOptions options, MqttClientSession session, ILogger logger) + public MqttClientPendingMessagesQueue(MqttServerOptions options, MqttClientSession session, IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _session = session ?? throw new ArgumentNullException(nameof(session)); _options = options ?? throw new ArgumentNullException(nameof(options)); } - public void Start(IMqttCommunicationAdapter adapter, CancellationToken cancellationToken) + public void Start(IMqttChannelAdapter adapter, CancellationToken cancellationToken) { if (adapter == null) throw new ArgumentNullException(nameof(adapter)); @@ -41,10 +41,10 @@ namespace MQTTnet.Core.Server if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket)); _pendingPublishPackets.Add(publishPacket); - _logger.LogTrace("Enqueued packet (ClientId: {0}).", _session.ClientId); + _logger.Trace("Enqueued packet (ClientId: {0}).", _session.ClientId); } - private async Task SendPendingPublishPacketsAsync(IMqttCommunicationAdapter adapter, CancellationToken cancellationToken) + private async Task SendPendingPublishPacketsAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken) { try { @@ -58,11 +58,11 @@ namespace MQTTnet.Core.Server } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Unhandled exception while sending enqueued packet (ClientId: {0}).", _session.ClientId); + _logger.Error(exception, "Unhandled exception while sending enqueued packet (ClientId: {0}).", _session.ClientId); } } - private async Task SendPendingPublishPacketAsync(IMqttCommunicationAdapter adapter, CancellationToken cancellationToken) + private async Task SendPendingPublishPacketAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken) { MqttPublishPacket packet = null; try @@ -70,24 +70,24 @@ namespace MQTTnet.Core.Server packet = _pendingPublishPackets.Take(cancellationToken); await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, packet).ConfigureAwait(false); - _logger.LogTrace("Enqueued packet sent (ClientId: {0}).", _session.ClientId); + _logger.Trace("Enqueued packet sent (ClientId: {0}).", _session.ClientId); } catch (Exception exception) { if (exception is MqttCommunicationTimedOutException) { - _logger.LogWarning(new EventId(), exception, "Sending publish packet failed due to timeout (ClientId: {0}).", _session.ClientId); + _logger.Warning(exception, "Sending publish packet failed due to timeout (ClientId: {0}).", _session.ClientId); } else if (exception is MqttCommunicationException) { - _logger.LogWarning(new EventId(), exception, "Sending publish packet failed due to communication exception (ClientId: {0}).", _session.ClientId); + _logger.Warning(exception, "Sending publish packet failed due to communication exception (ClientId: {0}).", _session.ClientId); } else if (exception is OperationCanceledException) { } else { - _logger.LogError(new EventId(), exception, "Sending publish packet failed (ClientId: {0}).", _session.ClientId); + _logger.Error(exception, "Sending publish packet failed (ClientId: {0}).", _session.ClientId); } if (packet != null && packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) diff --git a/MQTTnet.Core/Server/MqttClientSession.cs b/MQTTnet.Core/Server/MqttClientSession.cs index ad1416ed..3646c405 100644 --- a/MQTTnet.Core/Server/MqttClientSession.cs +++ b/MQTTnet.Core/Server/MqttClientSession.cs @@ -3,13 +3,12 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MQTTnet.Core.Adapter; +using MQTTnet.Core.Diagnostics; using MQTTnet.Core.Exceptions; using MQTTnet.Core.Internal; using MQTTnet.Core.Packets; using MQTTnet.Core.Protocol; using MQTTnet.Core.Serializer; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; namespace MQTTnet.Core.Server { @@ -21,28 +20,27 @@ namespace MQTTnet.Core.Server private readonly MqttClientSessionsManager _sessionsManager; private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue; private readonly MqttServerOptions _options; - private readonly ILogger _logger; + private readonly IMqttNetLogger _logger; - private IMqttCommunicationAdapter _adapter; + private IMqttChannelAdapter _adapter; private CancellationTokenSource _cancellationTokenSource; private MqttApplicationMessage _willMessage; public MqttClientSession( string clientId, - IOptions options, + MqttServerOptions options, MqttClientSessionsManager sessionsManager, - MqttClientSubscriptionsManager subscriptionsManager, - ILogger logger, - ILogger messageQueueLogger) + IMqttNetLogger logger) { _sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager)); - _subscriptionsManager = subscriptionsManager ?? throw new ArgumentNullException(nameof(subscriptionsManager)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); ClientId = clientId; - _options = options.Value; - _pendingMessagesQueue = new MqttClientPendingMessagesQueue(_options, this, messageQueueLogger); + _options = options; + + _subscriptionsManager = new MqttClientSubscriptionsManager(_options); + _pendingMessagesQueue = new MqttClientPendingMessagesQueue(_options, this, _logger); } public string ClientId { get; } @@ -51,7 +49,7 @@ namespace MQTTnet.Core.Server public bool IsConnected => _adapter != null; - public async Task RunAsync(MqttApplicationMessage willMessage, IMqttCommunicationAdapter adapter) + public async Task RunAsync(MqttApplicationMessage willMessage, IMqttChannelAdapter adapter) { if (adapter == null) throw new ArgumentNullException(nameof(adapter)); @@ -71,11 +69,11 @@ namespace MQTTnet.Core.Server } catch (MqttCommunicationException exception) { - _logger.LogWarning(new EventId(), exception, "Client '{0}': Communication exception while processing client packets.", ClientId); + _logger.Warning(exception, "Client '{0}': Communication exception while processing client packets.", ClientId); } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId); + _logger.Error(exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId); } } @@ -93,7 +91,7 @@ namespace MQTTnet.Core.Server _adapter = null; } - _logger.LogInformation("Client '{0}': Session stopped.", ClientId); + _logger.Info("Client '{0}': Session stopped.", ClientId); } finally { @@ -120,7 +118,7 @@ namespace MQTTnet.Core.Server _pendingMessagesQueue.Enqueue(publishPacket); } - private async Task ReceivePacketsAsync(IMqttCommunicationAdapter adapter, CancellationToken cancellationToken) + private async Task ReceivePacketsAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken) { try { @@ -135,17 +133,17 @@ namespace MQTTnet.Core.Server } catch (MqttCommunicationException exception) { - _logger.LogWarning(new EventId(), exception, "Client '{0}': Communication exception while processing client packets.", ClientId); + _logger.Warning(exception, "Client '{0}': Communication exception while processing client packets.", ClientId); await StopAsync(); } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId); + _logger.Error(exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId); await StopAsync(); } } - private Task ProcessReceivedPacketAsync(IMqttCommunicationAdapter adapter, MqttBasePacket packet, CancellationToken cancellationToken) + private Task ProcessReceivedPacketAsync(IMqttChannelAdapter adapter, MqttBasePacket packet, CancellationToken cancellationToken) { if (packet is MqttPingReqPacket) { @@ -188,11 +186,11 @@ namespace MQTTnet.Core.Server return StopAsync(); } - _logger.LogWarning("Client '{0}': Received not supported packet ({1}). Closing connection.", ClientId, packet); + _logger.Warning("Client '{0}': Received not supported packet ({1}). Closing connection.", ClientId, packet); return StopAsync(); } - private async Task HandleIncomingSubscribePacketAsync(IMqttCommunicationAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken) + private async Task HandleIncomingSubscribePacketAsync(IMqttChannelAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken) { var subscribeResult = _subscriptionsManager.Subscribe(subscribePacket, ClientId); @@ -215,7 +213,7 @@ namespace MQTTnet.Core.Server } } - private async Task HandleIncomingPublishPacketAsync(IMqttCommunicationAdapter adapter, MqttPublishPacket publishPacket, CancellationToken cancellationToken) + private async Task HandleIncomingPublishPacketAsync(IMqttChannelAdapter adapter, MqttPublishPacket publishPacket, CancellationToken cancellationToken) { var applicationMessage = publishPacket.ToApplicationMessage(); @@ -255,7 +253,7 @@ namespace MQTTnet.Core.Server } } - private Task HandleIncomingPubRelPacketAsync(IMqttCommunicationAdapter adapter, MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken) + private Task HandleIncomingPubRelPacketAsync(IMqttChannelAdapter adapter, MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken) { lock (_unacknowledgedPublishPackets) { diff --git a/MQTTnet.Core/Server/MqttClientSessionsManager.cs b/MQTTnet.Core/Server/MqttClientSessionsManager.cs index 80722ab7..63235220 100644 --- a/MQTTnet.Core/Server/MqttClientSessionsManager.cs +++ b/MQTTnet.Core/Server/MqttClientSessionsManager.cs @@ -4,13 +4,12 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MQTTnet.Core.Adapter; +using MQTTnet.Core.Diagnostics; using MQTTnet.Core.Exceptions; using MQTTnet.Core.Internal; using MQTTnet.Core.Packets; using MQTTnet.Core.Protocol; using MQTTnet.Core.Serializer; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; namespace MQTTnet.Core.Server { @@ -20,27 +19,21 @@ namespace MQTTnet.Core.Server private readonly SemaphoreSlim _sessionsSemaphore = new SemaphoreSlim(1, 1); private readonly MqttServerOptions _options; - private readonly ILogger _logger; - private readonly IMqttClientSesssionFactory _clientSesssionFactory; - private readonly IMqttClientRetainedMessageManager _clientRetainedMessageManager; + private readonly MqttRetainedMessagesManager _retainedMessagesManager; + private readonly IMqttNetLogger _logger; - public MqttClientSessionsManager( - IOptions options, - ILogger logger, - IMqttClientSesssionFactory clientSesssionFactory, - IMqttClientRetainedMessageManager clientRetainedMessageManager) + public MqttClientSessionsManager(MqttServerOptions options, MqttRetainedMessagesManager retainedMessagesManager, IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _options = options.Value ?? throw new ArgumentNullException(nameof(options)); - _clientSesssionFactory = clientSesssionFactory ?? throw new ArgumentNullException(nameof(clientSesssionFactory)); - _clientRetainedMessageManager = clientRetainedMessageManager ?? throw new ArgumentNullException(nameof(clientRetainedMessageManager)); + _options = options ?? throw new ArgumentNullException(nameof(options)); + _retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager)); } public event EventHandler ClientConnected; public event EventHandler ClientDisconnected; public event EventHandler ApplicationMessageReceived; - public async Task RunClientSessionAsync(IMqttCommunicationAdapter clientAdapter, CancellationToken cancellationToken) + public async Task RunClientSessionAsync(IMqttChannelAdapter clientAdapter, CancellationToken cancellationToken) { var clientId = string.Empty; try @@ -80,14 +73,11 @@ namespace MQTTnet.Core.Server ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion })); - using (_logger.BeginScope(clientId)) - { - await clientSession.Session.RunAsync(connectPacket.WillMessage, clientAdapter).ConfigureAwait(false); - } + await clientSession.Session.RunAsync(connectPacket.WillMessage, clientAdapter).ConfigureAwait(false); } catch (Exception exception) { - _logger.LogError(new EventId(), exception, exception.Message); + _logger.Error(exception, exception.Message); } finally { @@ -157,7 +147,7 @@ namespace MQTTnet.Core.Server if (applicationMessage.Retain) { - await _clientRetainedMessageManager.HandleMessageAsync(senderClientSession?.ClientId, applicationMessage).ConfigureAwait(false); + await _retainedMessagesManager.HandleMessageAsync(senderClientSession?.ClientId, applicationMessage).ConfigureAwait(false); } var eventArgs = new MqttApplicationMessageReceivedEventArgs(senderClientSession?.ClientId, applicationMessage); @@ -165,7 +155,7 @@ namespace MQTTnet.Core.Server } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Error while processing application message"); + _logger.Error(exception, "Error while processing application message"); } lock (_sessions) @@ -179,7 +169,7 @@ namespace MQTTnet.Core.Server public Task> GetRetainedMessagesAsync(MqttSubscribePacket subscribePacket) { - return _clientRetainedMessageManager.GetSubscribedMessagesAsync(subscribePacket); + return _retainedMessagesManager.GetSubscribedMessagesAsync(subscribePacket); } private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket) @@ -206,11 +196,11 @@ namespace MQTTnet.Core.Server await clientSession.StopAsync(); clientSession = null; - _logger.LogTrace("Stopped existing session of client '{0}'.", connectPacket.ClientId); + _logger.Trace("Stopped existing session of client '{0}'.", connectPacket.ClientId); } else { - _logger.LogTrace("Reusing existing session of client '{0}'.", connectPacket.ClientId); + _logger.Trace("Reusing existing session of client '{0}'.", connectPacket.ClientId); } } @@ -219,10 +209,10 @@ namespace MQTTnet.Core.Server { isExistingSession = false; - clientSession = _clientSesssionFactory.CreateClientSession(connectPacket.ClientId, this); + clientSession = new MqttClientSession(connectPacket.ClientId, _options, this, _logger); _sessions[connectPacket.ClientId] = clientSession; - _logger.LogTrace("Created a new session for client '{0}'.", connectPacket.ClientId); + _logger.Trace("Created a new session for client '{0}'.", connectPacket.ClientId); } return new GetOrCreateClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession }; diff --git a/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs b/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs index 5af3a2de..8801c012 100644 --- a/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs +++ b/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using Microsoft.Extensions.Options; using MQTTnet.Core.Packets; using MQTTnet.Core.Protocol; @@ -11,9 +10,9 @@ namespace MQTTnet.Core.Server private readonly Dictionary _subscriptions = new Dictionary(); private readonly MqttServerOptions _options; - public MqttClientSubscriptionsManager(IOptions options) + public MqttClientSubscriptionsManager(MqttServerOptions options) { - _options = options?.Value ?? throw new ArgumentNullException(nameof(options)); + _options = options ?? throw new ArgumentNullException(nameof(options)); } public MqttClientSubscribeResult Subscribe(MqttSubscribePacket subscribePacket, string clientId) diff --git a/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs b/MQTTnet.Core/Server/MqttRetainedMessagesManager.cs similarity index 80% rename from MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs rename to MQTTnet.Core/Server/MqttRetainedMessagesManager.cs index 5fe8522c..cf667236 100644 --- a/MQTTnet.Core/Server/MqttClientRetainedMessagesManager.cs +++ b/MQTTnet.Core/Server/MqttRetainedMessagesManager.cs @@ -4,22 +4,21 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MQTTnet.Core.Packets; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; +using MQTTnet.Core.Diagnostics; namespace MQTTnet.Core.Server { - public sealed class MqttClientRetainedMessagesManager : IMqttClientRetainedMessageManager + public sealed class MqttRetainedMessagesManager { private readonly Dictionary _retainedMessages = new Dictionary(); private readonly SemaphoreSlim _gate = new SemaphoreSlim(1, 1); - private readonly ILogger _logger; + private readonly IMqttNetLogger _logger; private readonly MqttServerOptions _options; - public MqttClientRetainedMessagesManager(IOptions options, ILogger logger) + public MqttRetainedMessagesManager(MqttServerOptions options, IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _options = options.Value ?? throw new ArgumentNullException(nameof(options)); + _options = options ?? throw new ArgumentNullException(nameof(options)); } public async Task LoadMessagesAsync() @@ -42,7 +41,7 @@ namespace MQTTnet.Core.Server } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Unhandled exception while loading retained messages."); + _logger.Error(exception, "Unhandled exception while loading retained messages."); } finally { @@ -61,7 +60,7 @@ namespace MQTTnet.Core.Server } catch (Exception exception) { - _logger.LogError(new EventId(), exception, "Unhandled exception while handling retained messages."); + _logger.Error(exception, "Unhandled exception while handling retained messages."); } finally { @@ -110,7 +109,7 @@ namespace MQTTnet.Core.Server if (applicationMessage.Payload?.Any() == false) { saveIsRequired = _retainedMessages.Remove(applicationMessage.Topic); - _logger.LogInformation("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic); + _logger.Info("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic); } else { @@ -129,12 +128,12 @@ namespace MQTTnet.Core.Server } } - _logger.LogInformation("Client '{0}' set retained message for topic '{1}'.", clientId, applicationMessage.Topic); + _logger.Info("Client '{0}' set retained message for topic '{1}'.", clientId, applicationMessage.Topic); } if (!saveIsRequired) { - _logger.LogTrace("Skipped saving retained messages because no changes were detected."); + _logger.Trace("Skipped saving retained messages because no changes were detected."); } if (saveIsRequired && _options.Storage != null) diff --git a/MQTTnet.Core/Server/MqttServer.cs b/MQTTnet.Core/Server/MqttServer.cs index c671907e..f9349284 100644 --- a/MQTTnet.Core/Server/MqttServer.cs +++ b/MQTTnet.Core/Server/MqttServer.cs @@ -3,33 +3,24 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MQTTnet.Core.Adapter; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using System.Linq; +using MQTTnet.Core.Diagnostics; namespace MQTTnet.Core.Server { public class MqttServer : IMqttServer { - private readonly IMqttClientRetainedMessageManager _clientRetainedMessageManager; - private readonly ILogger _logger; - private readonly MqttClientSessionsManager _clientSessionsManager; private readonly ICollection _adapters; - private readonly MqttServerOptions _options; + private readonly IMqttNetLogger _logger; + private MqttClientSessionsManager _clientSessionsManager; + private MqttRetainedMessagesManager _retainedMessagesManager; private CancellationTokenSource _cancellationTokenSource; + private MqttServerOptions _options; - public MqttServer( - IOptions options, - IEnumerable adapters, - ILogger logger, - MqttClientSessionsManager clientSessionsManager, - IMqttClientRetainedMessageManager clientRetainedMessageManager) + public MqttServer(IEnumerable adapters, IMqttNetLogger logger) { - _options = options.Value ?? throw new ArgumentNullException(nameof(options)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _clientSessionsManager = clientSessionsManager ?? throw new ArgumentNullException(nameof(clientSessionsManager)); - _clientRetainedMessageManager = clientRetainedMessageManager ?? throw new ArgumentNullException(nameof(clientRetainedMessageManager)); if (adapters == null) { @@ -37,15 +28,6 @@ namespace MQTTnet.Core.Server } _adapters = adapters.ToList(); - - _clientSessionsManager.ApplicationMessageReceived += (s, e) => ApplicationMessageReceived?.Invoke(s, e); - _clientSessionsManager.ClientConnected += OnClientConnected; - _clientSessionsManager.ClientDisconnected += OnClientDisconnected; - } - - public Task> GetConnectedClientsAsync() - { - return _clientSessionsManager.GetConnectedClientsAsync(); } public event EventHandler Started; @@ -53,14 +35,16 @@ namespace MQTTnet.Core.Server public event EventHandler ClientDisconnected; public event EventHandler ApplicationMessageReceived; + public Task> GetConnectedClientsAsync() + { + return _clientSessionsManager.GetConnectedClientsAsync(); + } + public async Task PublishAsync(IEnumerable applicationMessages) { if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages)); - if (_cancellationTokenSource == null) - { - throw new InvalidOperationException("The server is not started."); - } + if (_cancellationTokenSource == null) throw new InvalidOperationException("The server is not started."); foreach (var applicationMessage in applicationMessages) { @@ -68,13 +52,21 @@ namespace MQTTnet.Core.Server } } - public async Task StartAsync() + public async Task StartAsync(MqttServerOptions options) { - if (_cancellationTokenSource != null) throw new InvalidOperationException("The MQTT server is already started."); + _options = options ?? throw new ArgumentNullException(nameof(options)); + + if (_cancellationTokenSource != null) throw new InvalidOperationException("The server is already started."); _cancellationTokenSource = new CancellationTokenSource(); + _retainedMessagesManager = new MqttRetainedMessagesManager(_options, _logger); - await _clientRetainedMessageManager.LoadMessagesAsync(); + _clientSessionsManager = new MqttClientSessionsManager(_options, _retainedMessagesManager, _logger); + _clientSessionsManager.ApplicationMessageReceived += OnApplicationMessageReceived; + _clientSessionsManager.ClientConnected += OnClientConnected; + _clientSessionsManager.ClientDisconnected += OnClientDisconnected; + + await _retainedMessagesManager.LoadMessagesAsync(); foreach (var adapter in _adapters) { @@ -82,26 +74,48 @@ namespace MQTTnet.Core.Server await adapter.StartAsync(_options); } - _logger.LogInformation("Started."); + _logger.Info("Started."); Started?.Invoke(this, new MqttServerStartedEventArgs()); } public async Task StopAsync() { - _cancellationTokenSource?.Cancel(false); - _cancellationTokenSource?.Dispose(); - _cancellationTokenSource = null; - - foreach (var adapter in _adapters) + try { - adapter.ClientAccepted -= OnClientAccepted; - await adapter.StopAsync(); + if (_cancellationTokenSource == null) + { + return; + } + + _cancellationTokenSource.Cancel(false); + _cancellationTokenSource.Dispose(); + + foreach (var adapter in _adapters) + { + adapter.ClientAccepted -= OnClientAccepted; + await adapter.StopAsync(); + } + + await _clientSessionsManager.StopAsync(); + + _logger.Info("Stopped."); } + finally + { + _cancellationTokenSource = null; - await _clientSessionsManager.StopAsync(); + _retainedMessagesManager = null; - _logger.LogInformation("Stopped."); + if (_clientSessionsManager != null) + { + _clientSessionsManager.ApplicationMessageReceived -= OnApplicationMessageReceived; + _clientSessionsManager.ClientConnected -= OnClientConnected; + _clientSessionsManager.ClientDisconnected -= OnClientDisconnected; + } + + _clientSessionsManager = null; + } } private void OnClientAccepted(object sender, MqttServerAdapterClientAcceptedEventArgs eventArgs) @@ -111,14 +125,19 @@ namespace MQTTnet.Core.Server private void OnClientConnected(object sender, MqttClientConnectedEventArgs eventArgs) { - _logger.LogInformation("Client '{0}': Connected.", eventArgs.Client.ClientId); + _logger.Info("Client '{0}': Connected.", eventArgs.Client.ClientId); ClientConnected?.Invoke(this, eventArgs); } private void OnClientDisconnected(object sender, MqttClientDisconnectedEventArgs eventArgs) { - _logger.LogInformation("Client '{0}': Disconnected.", eventArgs.Client.ClientId); + _logger.Info("Client '{0}': Disconnected.", eventArgs.Client.ClientId); ClientDisconnected?.Invoke(this, eventArgs); } + + private void OnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e) + { + ApplicationMessageReceived?.Invoke(this, e); + } } } diff --git a/Tests/MQTTnet.Core.Tests/MQTTnet.Core.Tests.csproj b/Tests/MQTTnet.Core.Tests/MQTTnet.Core.Tests.csproj index 88ffbe41..b03d0d11 100644 --- a/Tests/MQTTnet.Core.Tests/MQTTnet.Core.Tests.csproj +++ b/Tests/MQTTnet.Core.Tests/MQTTnet.Core.Tests.csproj @@ -9,7 +9,7 @@ - + diff --git a/Tests/MQTTnet.Core.Tests/MqttLoggerProviderTest.cs b/Tests/MQTTnet.Core.Tests/MqttLoggerProviderTest.cs deleted file mode 100644 index bda3195e..00000000 --- a/Tests/MQTTnet.Core.Tests/MqttLoggerProviderTest.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using MQTTnet.Core.Diagnostics; - -namespace MQTTnet.Core.Tests -{ - [TestClass] - public class MqttLoggerProviderTest - { - [TestMethod] - public void TestLoggerCallback() - { - var serviceCollection = new ServiceCollection(); - serviceCollection.AddLogging(); - - var serviceProvider = serviceCollection.BuildServiceProvider(); - using ((IDisposable)serviceProvider) - { - var loggerFactory = serviceProvider.GetRequiredService(); - - loggerFactory.AddMqttTrace(); - - var expectedMsg = "Hello World!"; - MqttNetTraceMessage msg = null; - - MqttNetTrace.TraceMessagePublished += (sender, args) => - { - msg = args.TraceMessage; - }; - - var logger = loggerFactory.CreateLogger(); - - logger.LogInformation(expectedMsg); - - Assert.AreEqual(expectedMsg, msg.Message); - - var expectedException = new Exception("bad stuff"); - - logger.LogError(new EventId(), expectedException, expectedException.Message); - - Assert.AreEqual(expectedException, msg.Exception); - Assert.AreEqual(expectedException.Message, msg.Message); - } - } - } -} diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index faad01c8..89cae3b6 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -1,16 +1,12 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MQTTnet.Core.Adapter; using MQTTnet.Core.Client; +using MQTTnet.Core.Diagnostics; using MQTTnet.Core.Protocol; using MQTTnet.Core.Server; -using Microsoft.Extensions.DependencyInjection; -using MQTTnet.Core.Internal; -using MQTTnet.Core.Packets; namespace MQTTnet.Core.Tests { @@ -54,18 +50,12 @@ namespace MQTTnet.Core.Tests public async Task MqttServer_WillMessage() { var serverAdapter = new TestMqttServerAdapter(); + var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); - var services = new ServiceCollection() - .AddLogging() - .AddMqttServer() - .AddSingleton(serverAdapter) - .BuildServiceProvider(); - - var s = new MqttFactory(services).CreateMqttServer(); var receivedMessagesCount = 0; try { - await s.StartAsync(); + await s.StartAsync(new MqttServerOptions()); var willMessage = new MqttApplicationMessageBuilder().WithTopic("My/last/will").WithAtMostOnceQoS().Build(); var c1 = await serverAdapter.ConnectTestClient(s, "c1"); @@ -92,19 +82,13 @@ namespace MQTTnet.Core.Tests public async Task MqttServer_Unsubscribe() { var serverAdapter = new TestMqttServerAdapter(); - var services = new ServiceCollection() - .AddLogging() - .AddMqttServer() - .AddSingleton(serverAdapter) - .BuildServiceProvider(); - - var s = new MqttFactory(services).CreateMqttServer(); + var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); var receivedMessagesCount = 0; try { - await s.StartAsync(); + await s.StartAsync(new MqttServerOptions()); var c1 = await serverAdapter.ConnectTestClient(s, "c1"); var c2 = await serverAdapter.ConnectTestClient(s, "c2"); @@ -140,18 +124,12 @@ namespace MQTTnet.Core.Tests public async Task MqttServer_Publish() { var serverAdapter = new TestMqttServerAdapter(); - var services = new ServiceCollection() - .AddLogging() - .AddMqttServer() - .AddSingleton(serverAdapter) - .BuildServiceProvider(); - - var s = new MqttFactory(services).CreateMqttServer(); + var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); var receivedMessagesCount = 0; try { - await s.StartAsync(); + await s.StartAsync(new MqttServerOptions()); var c1 = await serverAdapter.ConnectTestClient(s, "c1"); @@ -167,7 +145,7 @@ namespace MQTTnet.Core.Tests { await s.StopAsync(); } - + Assert.AreEqual(1, receivedMessagesCount); } @@ -175,18 +153,13 @@ namespace MQTTnet.Core.Tests public async Task MqttServer_NoRetainedMessage() { var serverAdapter = new TestMqttServerAdapter(); - var services = new ServiceCollection() - .AddLogging() - .AddMqttServer() - .AddSingleton(serverAdapter) - .BuildServiceProvider(); + var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); - var s = new MqttFactory(services).CreateMqttServer(); var receivedMessagesCount = 0; try { - await s.StartAsync(); + await s.StartAsync(new MqttServerOptions()); var c1 = await serverAdapter.ConnectTestClient(s, "c1"); await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).Build()); @@ -194,7 +167,7 @@ namespace MQTTnet.Core.Tests var c2 = await serverAdapter.ConnectTestClient(s, "c2"); c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++; - await c2.SubscribeAsync(new TopicFilter("retained", MqttQualityOfServiceLevel.AtMostOnce)); + await c2.SubscribeAsync(new TopicFilter("retained")); await Task.Delay(500); } @@ -210,28 +183,23 @@ namespace MQTTnet.Core.Tests public async Task MqttServer_RetainedMessage() { var serverAdapter = new TestMqttServerAdapter(); - var services = new ServiceCollection() - .AddLogging() - .AddMqttServer() - .AddSingleton(serverAdapter) - .BuildServiceProvider(); - - var s = new MqttFactory(services).CreateMqttServer(); + var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); var receivedMessagesCount = 0; try { - await s.StartAsync(); + await s.StartAsync(new MqttServerOptions()); var c1 = await serverAdapter.ConnectTestClient(s, "c1"); await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build()); await c1.DisconnectAsync(); - await services.WaitForRetainedMessage("retained").TimeoutAfter(TimeSpan.FromSeconds(5)); + await Task.Delay(TimeSpan.FromSeconds(2)); + // TODO: Find another way to wait for the retained components. var c2 = await serverAdapter.ConnectTestClient(s, "c2"); c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++; - await c2.SubscribeAsync(new TopicFilter("retained", MqttQualityOfServiceLevel.AtMostOnce)); + await c2.SubscribeAsync(new TopicFilter("retained")); await Task.Delay(500); } @@ -239,7 +207,7 @@ namespace MQTTnet.Core.Tests { await s.StopAsync(); } - + Assert.AreEqual(1, receivedMessagesCount); } @@ -247,17 +215,12 @@ namespace MQTTnet.Core.Tests public async Task MqttServer_ClearRetainedMessage() { var serverAdapter = new TestMqttServerAdapter(); - var services = new ServiceCollection() - .AddLogging() - .AddMqttServer() - .AddSingleton(serverAdapter) - .BuildServiceProvider(); + var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); - var s = new MqttFactory(services).CreateMqttServer(); var receivedMessagesCount = 0; try { - await s.StartAsync(); + await s.StartAsync(new MqttServerOptions()); var c1 = await serverAdapter.ConnectTestClient(s, "c1"); await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build()); @@ -284,18 +247,13 @@ namespace MQTTnet.Core.Tests { var storage = new TestStorage(); var serverAdapter = new TestMqttServerAdapter(); - - var services = new ServiceCollection() - .AddLogging() - .AddMqttServer() - .AddSingleton(serverAdapter) - .BuildServiceProvider(); - - var s = new MqttFactory(services).CreateMqttServer(options => options.Storage = storage); + var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); try { - await s.StartAsync(); + var options = new MqttServerOptions { Storage = storage }; + + await s.StartAsync(options); var c1 = await serverAdapter.ConnectTestClient(s, "c1"); await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build()); @@ -306,18 +264,20 @@ namespace MQTTnet.Core.Tests await s.StopAsync(); } - await services.WaitForRetainedMessage("retained").TimeoutAfter(TimeSpan.FromSeconds(5)); + await Task.Delay(TimeSpan.FromSeconds(2)); + // TODO: Find another way to wait for the retained components. - s = new MqttFactory(services).CreateMqttServer(options => options.Storage = storage); + s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); var receivedMessagesCount = 0; try { - await s.StartAsync(); + var options = new MqttServerOptions { Storage = storage }; + await s.StartAsync(options); var c2 = await serverAdapter.ConnectTestClient(s, "c2"); c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++; - await c2.SubscribeAsync(new TopicFilter("retained", MqttQualityOfServiceLevel.AtMostOnce)); + await c2.SubscribeAsync(new TopicFilter("retained")); await Task.Delay(500); } @@ -338,16 +298,13 @@ namespace MQTTnet.Core.Tests } var serverAdapter = new TestMqttServerAdapter(); - var services = new ServiceCollection() - .AddLogging() - .AddMqttServer() - .AddSingleton(serverAdapter) - .BuildServiceProvider(); - - var s = new MqttFactory(services).CreateMqttServer(options => options.ApplicationMessageInterceptor = Interceptor); + var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); + try { - await s.StartAsync(); + var options = new MqttServerOptions { ApplicationMessageInterceptor = Interceptor }; + + await s.StartAsync(options); var c1 = await serverAdapter.ConnectTestClient(s, "c1"); var c2 = await serverAdapter.ConnectTestClient(s, "c2"); @@ -397,17 +354,12 @@ namespace MQTTnet.Core.Tests int expectedReceivedMessagesCount) { var serverAdapter = new TestMqttServerAdapter(); - var services = new ServiceCollection() - .AddMqttServer() - .AddLogging() - .AddSingleton(serverAdapter) - .BuildServiceProvider(); + var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); - var s = services.GetRequiredService(); var receivedMessagesCount = 0; try { - await s.StartAsync(); + await s.StartAsync(new MqttServerOptions()); var c1 = await serverAdapter.ConnectTestClient(s, "c1"); var c2 = await serverAdapter.ConnectTestClient(s, "c2"); @@ -426,29 +378,8 @@ namespace MQTTnet.Core.Tests { await s.StopAsync(); } - + Assert.AreEqual(expectedReceivedMessagesCount, receivedMessagesCount); } } - - public static class TestExtensions - { - public static async Task WaitForRetainedMessage(this IServiceProvider services, string topic) - { - var retainMessagemanager = services.GetRequiredService(); - - var subscribe = new MqttSubscribePacket() - { - TopicFilters = new List() - { - new TopicFilter(topic, MqttQualityOfServiceLevel.AtMostOnce) - } - }; - - while (!(await retainMessagemanager.GetSubscribedMessagesAsync(subscribe)).Any()) - { - await Task.Delay(TimeSpan.FromMilliseconds(10)); - } - } - } } diff --git a/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs b/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs index 44bad993..f4885434 100644 --- a/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.Options; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using MQTTnet.Core.Packets; using MQTTnet.Core.Protocol; using MQTTnet.Core.Server; @@ -12,7 +11,7 @@ namespace MQTTnet.Core.Tests [TestMethod] public void MqttSubscriptionsManager_SubscribeSingleSuccess() { - var sm = new MqttClientSubscriptionsManager(new OptionsWrapper(new MqttServerOptions())); + var sm = new MqttClientSubscriptionsManager(new MqttServerOptions()); var sp = new MqttSubscribePacket(); sp.TopicFilters.Add(new TopicFilter("A/B/C")); @@ -31,7 +30,7 @@ namespace MQTTnet.Core.Tests [TestMethod] public void MqttSubscriptionsManager_SubscribeSingleNoSuccess() { - var sm = new MqttClientSubscriptionsManager(new OptionsWrapper(new MqttServerOptions())); + var sm = new MqttClientSubscriptionsManager(new MqttServerOptions()); var sp = new MqttSubscribePacket(); sp.TopicFilters.Add(new TopicFilter("A/B/C")); @@ -50,7 +49,7 @@ namespace MQTTnet.Core.Tests [TestMethod] public void MqttSubscriptionsManager_SubscribeAndUnsubscribeSingle() { - var sm = new MqttClientSubscriptionsManager(new OptionsWrapper(new MqttServerOptions())); + var sm = new MqttClientSubscriptionsManager(new MqttServerOptions()); var sp = new MqttSubscribePacket(); sp.TopicFilters.Add(new TopicFilter("A/B/C")); diff --git a/Tests/MQTTnet.Core.Tests/ServiceCollectionTest.cs b/Tests/MQTTnet.Core.Tests/ServiceCollectionTest.cs deleted file mode 100644 index 0117ed08..00000000 --- a/Tests/MQTTnet.Core.Tests/ServiceCollectionTest.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace MQTTnet.Core.Tests -{ - [TestClass] - public class ServiceCollectionTest - { - [TestMethod] - public void TestCanConstructAllServices() - { - var services = new ServiceCollection() - .AddLogging() - .AddMqttServer() - .AddMqttClient(); - - var serviceProvider = services - .BuildServiceProvider(); - - foreach (var service in services) - { - if (service.ServiceType.IsGenericType) - { - continue; - } - serviceProvider.GetRequiredService(service.ServiceType); - } - } - } -} diff --git a/Tests/MQTTnet.Core.Tests/TestClientSessionFactory.cs b/Tests/MQTTnet.Core.Tests/TestClientSessionFactory.cs deleted file mode 100644 index 638df85d..00000000 --- a/Tests/MQTTnet.Core.Tests/TestClientSessionFactory.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using MQTTnet.Core.Server; - -namespace MQTTnet.Core.Tests -{ - public class TestClientSessionFactory : IMqttClientSesssionFactory - { - public MqttClientSession CreateClientSession(string clientId, MqttClientSessionsManager mqttClientSessionsManager) - { - throw new NotImplementedException(); - //return new MqttClientSession(clientId, mqttClientSessionsManager, new TestLogger(), new TestLogger()); - } - } -} diff --git a/Tests/MQTTnet.Core.Tests/TestLogger.cs b/Tests/MQTTnet.Core.Tests/TestLogger.cs deleted file mode 100644 index f57c877c..00000000 --- a/Tests/MQTTnet.Core.Tests/TestLogger.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.Extensions.Logging; -using System; - -namespace MQTTnet.Core.Tests -{ - public class TestLogger : IDisposable, ILogger - { - public IDisposable BeginScope(TState state) - { - return this; - } - - public bool IsEnabled(LogLevel logLevel) - { - return true; - } - - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - } - - public void Dispose() - { - } - } -} diff --git a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs index ecde0f14..53a6f0fe 100644 --- a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs +++ b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs @@ -9,7 +9,7 @@ using MQTTnet.Core.Serializer; namespace MQTTnet.Core.Tests { - public class TestMqttCommunicationAdapter : IMqttCommunicationAdapter + public class TestMqttCommunicationAdapter : IMqttChannelAdapter { private readonly BlockingCollection _incomingPackets = new BlockingCollection(); diff --git a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs index 4a0acadd..7da1e167 100644 --- a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs +++ b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs @@ -1,24 +1,19 @@ using MQTTnet.Core.Adapter; -using MQTTnet.Core.Channel; using MQTTnet.Core.Client; +using MQTTnet.Core.Diagnostics; namespace MQTTnet.Core.Tests { - public class TestMqttCommunicationAdapterFactory : IMqttCommunicationAdapterFactory + public class TestMqttCommunicationAdapterFactory : IMqttClientAdapterFactory { - private readonly IMqttCommunicationAdapter _adapter; + private readonly IMqttChannelAdapter _adapter; - public TestMqttCommunicationAdapterFactory(IMqttCommunicationAdapter adapter) + public TestMqttCommunicationAdapterFactory(IMqttChannelAdapter adapter) { _adapter = adapter; } - - public IMqttCommunicationAdapter CreateClientCommunicationAdapter(IMqttClientOptions options) - { - return _adapter; - } - - public IMqttCommunicationAdapter CreateServerCommunicationAdapter(IMqttCommunicationChannel channel) + + public IMqttChannelAdapter CreateClientAdapter(IMqttClientChannelOptions options, IMqttNetLogger logger) { return _adapter; } diff --git a/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs b/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs index cac3b1c0..e65d9f8a 100644 --- a/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs +++ b/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using MQTTnet.Core.Adapter; using MQTTnet.Core.Server; using MQTTnet.Core.Client; +using MQTTnet.Core.Diagnostics; namespace MQTTnet.Core.Tests { @@ -19,8 +20,7 @@ namespace MQTTnet.Core.Tests var client = new MqttClient( new TestMqttCommunicationAdapterFactory(adapterA), - new TestLogger(), - new MqttPacketDispatcher(new TestLogger())); + new MqttNetLogger()); var connected = WaitForClientToConnect(server, clientId); @@ -57,7 +57,7 @@ namespace MQTTnet.Core.Tests return tcs.Task; } - private void FireClientAcceptedEvent(IMqttCommunicationAdapter adapter) + private void FireClientAcceptedEvent(IMqttChannelAdapter adapter) { ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(adapter)); } diff --git a/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs b/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs index bc644e54..dfd7d0d9 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs @@ -1,7 +1,6 @@ using System; using System.Text; using System.Threading.Tasks; -using Microsoft.Extensions.Logging; using MQTTnet.Core; using MQTTnet.Core.Client; @@ -28,8 +27,7 @@ namespace MQTTnet.TestApp.NetCore }; var factory = new MqttFactory(); - factory.GetLoggerFactory().AddConsole(); - + var client = factory.CreateMqttClient(); client.ApplicationMessageReceived += (s, e) => diff --git a/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj b/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj index d89bdd31..8f25448d 100644 --- a/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj +++ b/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj @@ -14,10 +14,4 @@ - - - 1.1.2 - - - diff --git a/Tests/MQTTnet.TestApp.NetCore/ManagedClientTest.cs b/Tests/MQTTnet.TestApp.NetCore/ManagedClientTest.cs index 7f6d430b..7f76b659 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ManagedClientTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ManagedClientTest.cs @@ -4,8 +4,6 @@ using MQTTnet.Core; using MQTTnet.Core.Client; using MQTTnet.Core.ManagedClient; using MQTTnet.Core.Protocol; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using System.IO; using Newtonsoft.Json; using System.Collections.Generic; @@ -16,14 +14,6 @@ namespace MQTTnet.TestApp.NetCore { public static async Task RunAsync() { - var services = new ServiceCollection() - .AddMqttClient() - .AddLogging() - .BuildServiceProvider(); - - services.GetService() - .AddConsole(); - var ms = new ClientRetainedMessageHandler(); var options = new ManagedMqttClientOptions @@ -44,7 +34,7 @@ namespace MQTTnet.TestApp.NetCore try { - var managedClient = services.GetRequiredService(); + var managedClient = new MqttFactory().CreateManagedMqttClient(); managedClient.ApplicationMessageReceived += (s, e) => { Console.WriteLine(">> RECEIVED: " + e.ApplicationMessage.Topic); diff --git a/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs b/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs index e21a7ea3..c6bbe04a 100644 --- a/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs @@ -1,9 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using MQTTnet.Core; +using MQTTnet.Core; using MQTTnet.Core.Client; using MQTTnet.Core.Protocol; -using MQTTnet.Core.Server; using System; using System.Collections.Generic; using System.Diagnostics; @@ -11,6 +8,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using MQTTnet.Core.Server; namespace MQTTnet.TestApp.NetCore { @@ -18,46 +16,21 @@ namespace MQTTnet.TestApp.NetCore { public static async Task RunAsync() { - var services = new ServiceCollection() - .AddMqttServer(options => - { - - options.ConnectionValidator = p => - { - if (p.ClientId == "SpecialClient") - { - if (p.Username != "USER" || p.Password != "PASS") - { - return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; - } - } - - return MqttConnectReturnCode.ConnectionAccepted; - }; - - options.DefaultCommunicationTimeout = TimeSpan.FromMinutes(10); - }) - .AddMqttClient() - .AddLogging() - .BuildServiceProvider(); - - //services.GetService().AddConsole(LogLevel.Warning, true); - Console.WriteLine("Press 'c' for concurrent sends. Otherwise in one batch."); var concurrent = Console.ReadKey(true).KeyChar == 'c'; - var server = Task.Factory.StartNew(() => RunServerAsync(services), TaskCreationOptions.LongRunning); - var client = Task.Factory.StartNew(() => RunClientAsync(2000, TimeSpan.FromMilliseconds(10), services, concurrent), TaskCreationOptions.LongRunning); + var server = Task.Factory.StartNew(async () => await RunServerAsync(), TaskCreationOptions.LongRunning); + var client = Task.Factory.StartNew(async () => await RunClientAsync(2000, TimeSpan.FromMilliseconds(10), concurrent), TaskCreationOptions.LongRunning); await Task.WhenAll(server, client).ConfigureAwait(false); } - private static Task RunClientsAsync(int msgChunkSize, TimeSpan interval, IServiceProvider serviceProvider, bool concurrent) + private static Task RunClientsAsync(int msgChunkSize, TimeSpan interval, bool concurrent) { - return Task.WhenAll(Enumerable.Range(0, 3).Select(i => Task.Run(() => RunClientAsync(msgChunkSize, interval, serviceProvider, concurrent)))); + return Task.WhenAll(Enumerable.Range(0, 3).Select(i => Task.Run(() => RunClientAsync(msgChunkSize, interval, concurrent)))); } - private static async Task RunClientAsync(int msgChunkSize, TimeSpan interval, IServiceProvider serviceProvider, bool concurrent) + private static async Task RunClientAsync(int msgChunkSize, TimeSpan interval, bool concurrent) { try { @@ -69,7 +42,7 @@ namespace MQTTnet.TestApp.NetCore CommunicationTimeout = TimeSpan.FromMinutes(10) }; - var client = serviceProvider.GetRequiredService(); + var client = new MqttFactory().CreateMqttClient(); client.Connected += async (s, e) => { @@ -77,7 +50,7 @@ namespace MQTTnet.TestApp.NetCore await client.SubscribeAsync(new List { - new TopicFilter("#", MqttQualityOfServiceLevel.AtMostOnce) + new TopicFilter("#") }); Console.WriteLine("### SUBSCRIBED ###"); @@ -120,7 +93,6 @@ namespace MQTTnet.TestApp.NetCore stopwatch.Stop(); Console.WriteLine($"Sent 10.000 messages within {stopwatch.ElapsedMilliseconds} ms ({stopwatch.ElapsedMilliseconds / (float)testMessageCount} ms / message)."); - var messages = new[] { message }; var sentMessagesCount = 0; @@ -158,9 +130,7 @@ namespace MQTTnet.TestApp.NetCore msgCount += msgs.Count; //send multiple } - - - + var now = DateTime.Now; if (last < now - TimeSpan.FromSeconds(1)) { @@ -194,11 +164,12 @@ namespace MQTTnet.TestApp.NetCore return Task.Run(() => client.PublishAsync(applicationMessage)); } - private static async Task RunServerAsync(IServiceProvider serviceProvider) + private static async Task RunServerAsync() { try { - var mqttServer = serviceProvider.GetRequiredService(); + var mqttServer = new MqttFactory().CreateMqttServer(); + var msgs = 0; var stopwatch = Stopwatch.StartNew(); mqttServer.ApplicationMessageReceived += (sender, args) => @@ -211,7 +182,7 @@ namespace MQTTnet.TestApp.NetCore stopwatch.Restart(); } }; - await mqttServer.StartAsync(); + await mqttServer.StartAsync(new MqttServerOptions()); Console.WriteLine("Press any key to exit."); Console.ReadLine(); diff --git a/Tests/MQTTnet.TestApp.NetCore/Program.cs b/Tests/MQTTnet.TestApp.NetCore/Program.cs index d1c010fe..fb02de8f 100644 --- a/Tests/MQTTnet.TestApp.NetCore/Program.cs +++ b/Tests/MQTTnet.TestApp.NetCore/Program.cs @@ -7,7 +7,6 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; -using Microsoft.Extensions.Logging; namespace MQTTnet.TestApp.NetCore { @@ -70,8 +69,6 @@ namespace MQTTnet.TestApp.NetCore { var factory = new MqttFactory(); - factory.GetLoggerFactory().AddConsole(); - var client = factory.CreateMqttClient(); } } diff --git a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs index f4a18cd5..a0b16269 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs @@ -3,24 +3,21 @@ using System.Text; using System.Threading.Tasks; using MQTTnet.Core.Protocol; using MQTTnet.Core.Server; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; +using MQTTnet.Diagnostics; namespace MQTTnet.TestApp.NetCore { public static class ServerTest { - public static Task RunAsync() + public static async Task RunAsync() { try { - var services = new ServiceCollection() - .AddMqttServer() - .AddLogging(); + MqttNetConsoleTrace.ForwardToConsole(); - services.Configure(options => + var options = new MqttServerOptions { - options.ConnectionValidator = p => + ConnectionValidator = p => { if (p.ClientId == "SpecialClient") { @@ -31,22 +28,19 @@ namespace MQTTnet.TestApp.NetCore } return MqttConnectReturnCode.ConnectionAccepted; - }; + }, - options.Storage = new RetainedMessageHandler(); - - // Extend the timestamp for all messages from clients. - options.ApplicationMessageInterceptor = context => + Storage = new RetainedMessageHandler(), + ApplicationMessageInterceptor = context => { if (MqttTopicFilterComparer.IsMatch(context.ApplicationMessage.Topic, "/myTopic/WithTimestamp/#")) { - // Replace the payload with the timestamp. But also extending a JSON - // based payload with the timestamp is a suitable use case. - context.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O")); + // Replace the payload with the timestamp. But also extending a JSON + // based payload with the timestamp is a suitable use case. + context.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O")); } - }; - // Protect several topics from being subscribed from every client. - options.SubscriptionsInterceptor = context => + }, + SubscriptionsInterceptor = context => { if (context.TopicFilter.Topic.StartsWith("admin/foo/bar") && context.ClientId != "theAdmin") { @@ -58,11 +52,11 @@ namespace MQTTnet.TestApp.NetCore context.AcceptSubscription = false; context.CloseConnection = true; } - }; - }); + } + }; - var serviceProvider = services.BuildServiceProvider(); - serviceProvider.GetRequiredService().AddConsole(); + // Extend the timestamp for all messages from clients. + // Protect several topics from being subscribed from every client. //var certificate = new X509Certificate(@"C:\certs\test\test.cer", ""); //options.TlsEndpointOptions.Certificate = certificate.Export(X509ContentType.Cert); @@ -70,18 +64,18 @@ namespace MQTTnet.TestApp.NetCore //options.DefaultEndpointOptions.IsEnabled = true; //options.TlsEndpointOptions.IsEnabled = false; - var mqttServer = new MqttFactory(serviceProvider).CreateMqttServer(); + var mqttServer = new MqttFactory().CreateMqttServer(); mqttServer.ClientDisconnected += (s, e) => { Console.Write("Client disconnected event fired."); }; - mqttServer.StartAsync(); + await mqttServer.StartAsync(options); Console.WriteLine("Press any key to exit."); Console.ReadLine(); - mqttServer.StopAsync(); + await mqttServer.StopAsync(); } catch (Exception e) { @@ -89,7 +83,6 @@ namespace MQTTnet.TestApp.NetCore } Console.ReadLine(); - return Task.FromResult(0); } } } diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj index f8c1ce9d..fa0763c7 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj @@ -137,12 +137,6 @@ - - 1.1.2 - - - 1.1.2 - 5.4.0 diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index fcf6d091..6c7258b9 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -5,8 +5,6 @@ using System.Threading.Tasks; using Windows.Security.Cryptography.Certificates; using Windows.UI.Core; using Windows.UI.Xaml; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using MQTTnet.Core; using MQTTnet.Core.Client; using MQTTnet.Core.Diagnostics; @@ -19,7 +17,7 @@ namespace MQTTnet.TestApp.UniversalWindows { public sealed partial class MainPage { - private readonly ConcurrentQueue _traceMessages = new ConcurrentQueue(); + private readonly ConcurrentQueue _traceMessages = new ConcurrentQueue(); private IMqttClient _mqttClient; private IMqttServer _mqttServer; @@ -28,10 +26,10 @@ namespace MQTTnet.TestApp.UniversalWindows { InitializeComponent(); - MqttNetTrace.TraceMessagePublished += OnTraceMessagePublished; + MqttNetGlobalLog.LogMessagePublished += OnTraceMessagePublished; } - private async void OnTraceMessagePublished(object sender, MqttNetTraceMessagePublishedEventArgs e) + private async void OnTraceMessagePublished(object sender, MqttNetLogMessagePublishedEventArgs e) { _traceMessages.Enqueue(e.TraceMessage); while (_traceMessages.Count > 100) @@ -252,7 +250,7 @@ namespace MQTTnet.TestApp.UniversalWindows { { // Write all trace messages to the console window. - MqttNetTrace.TraceMessagePublished += (s, e) => + MqttNetGlobalLog.LogMessagePublished += (s, e) => { Console.WriteLine($">> [{e.TraceMessage.Timestamp:O}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}"); if (e.TraceMessage.Exception != null) @@ -262,32 +260,12 @@ namespace MQTTnet.TestApp.UniversalWindows }; } - { - // Add the console logger to the logger factory. - var services = new ServiceCollection() - .AddMqttClient() - .BuildServiceProvider(); - - services.GetRequiredService() - .AddConsole(); - } - { // Use a custom identifier for the trace messages. var clientOptions = new MqttClientOptionsBuilder() - .WithLogId("ClientX") .Build(); } - { - // Create a client from the service provider manually. - var serviceProvider = new ServiceCollection() - .AddMqttClient() - .BuildServiceProvider(); - - var mqttClient = serviceProvider.GetRequiredService(); - } - { // Create a new MQTT client. var factory = new MqttFactory(); @@ -371,34 +349,31 @@ namespace MQTTnet.TestApp.UniversalWindows // ---------------------------------- { - var services = new ServiceCollection() - .AddMqttServer(options => + var options = new MqttServerOptions(); + + options.ConnectionValidator = c => + { + if (c.ClientId.Length < 10) { - options.ConnectionValidator = c => - { - if (c.ClientId.Length < 10) - { - return MqttConnectReturnCode.ConnectionRefusedIdentifierRejected; - } + return MqttConnectReturnCode.ConnectionRefusedIdentifierRejected; + } - if (c.Username != "mySecretUser") - { - return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; - } + if (c.Username != "mySecretUser") + { + return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; + } - if (c.Password != "mySecretPassword") - { - return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; - } + if (c.Password != "mySecretPassword") + { + return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; + } - return MqttConnectReturnCode.ConnectionAccepted; - }; - }) - .BuildServiceProvider(); + return MqttConnectReturnCode.ConnectionAccepted; + }; - var factory = new MqttFactory(services); + var factory = new MqttFactory(); var mqttServer = factory.CreateMqttServer(); - await mqttServer.StartAsync(); + await mqttServer.StartAsync(options); Console.WriteLine("Press any key to exit."); Console.ReadLine(); @@ -422,7 +397,7 @@ namespace MQTTnet.TestApp.UniversalWindows { // Start a MQTT server. var mqttServer = new MqttFactory().CreateMqttServer(); - await mqttServer.StartAsync(); + await mqttServer.StartAsync(new MqttServerOptions()); Console.WriteLine("Press any key to exit."); Console.ReadLine(); await mqttServer.StopAsync(); @@ -430,27 +405,31 @@ namespace MQTTnet.TestApp.UniversalWindows { // Configure MQTT server. - var mqttServer = new MqttFactory().CreateMqttServer(options => + var options = new MqttServerOptions { - options.ConnectionBacklog = 100; - options.DefaultEndpointOptions.Port = 1884; - options.ConnectionValidator = packet => - { - if (packet.ClientId != "Highlander") - { - return MqttConnectReturnCode.ConnectionRefusedIdentifierRejected; - } + ConnectionBacklog = 100 + }; - return MqttConnectReturnCode.ConnectionAccepted; - }; - }); + options.DefaultEndpointOptions.Port = 1884; + options.ConnectionValidator = packet => + { + if (packet.ClientId != "Highlander") + { + return MqttConnectReturnCode.ConnectionRefusedIdentifierRejected; + } + + return MqttConnectReturnCode.ConnectionAccepted; + }; + + var mqttServer = new MqttFactory().CreateMqttServer(); + await mqttServer.StartAsync(options); } { // Setup client validator. - var mqttServer = new MqttFactory().CreateMqttServer(options => + var options = new MqttServerOptions { - options.ConnectionValidator = c => + ConnectionValidator = c => { if (c.ClientId.Length < 10) { @@ -468,8 +447,8 @@ namespace MQTTnet.TestApp.UniversalWindows } return MqttConnectReturnCode.ConnectionAccepted; - }; - }); + } + }; } { @@ -512,13 +491,13 @@ namespace MQTTnet.TestApp.UniversalWindows } } - _mqttServer = new MqttFactory().CreateMqttServer(o => - { - o.DefaultEndpointOptions.Port = int.Parse(ServerPort.Text); - o.Storage = storage; - }); + _mqttServer = new MqttFactory().CreateMqttServer(); - await _mqttServer.StartAsync(); + var options = new MqttServerOptions(); + options.DefaultEndpointOptions.Port = int.Parse(ServerPort.Text); + options.Storage = storage; + + await _mqttServer.StartAsync(options); } private async void StopServer(object sender, RoutedEventArgs e) From e54b4f58df304701e5c6d4abf533a8eb9a76c91e Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Thu, 23 Nov 2017 22:26:22 +0100 Subject: [PATCH 060/149] Update version info. Fix typo. Add MqttServerOptionsBuilder. --- Build/MQTTnet.AspNetCore.nuspec | 7 +- .../Implementations/MqttWebSocketChannel.cs | 2 +- .../Server/MqttClientSubscriptionsManager.cs | 2 +- .../Server/MqttConnectionValidatorContext.cs | 25 ++++++ MQTTnet.Core/Server/MqttServerOptions.cs | 4 +- .../Server/MqttServerOptionsBuilder.cs | 88 +++++++++++++++++++ .../MQTTnet.TestApp.AspNetCore2.csproj | 2 +- Tests/MQTTnet.TestApp.NetCore/ServerTest.cs | 2 +- 8 files changed, 122 insertions(+), 10 deletions(-) create mode 100644 MQTTnet.Core/Server/MqttConnectionValidatorContext.cs create mode 100644 MQTTnet.Core/Server/MqttServerOptionsBuilder.cs diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index b29ad5c3..b98eec0d 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -2,7 +2,7 @@ MQTTnet.AspNetCore - 2.5.2 + 2.5.3 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,14 +10,13 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false This is a support library to integrate MQTTnet into AspNetCore. - * Updated to MQTTnet 2.5.2. -* Fixed WebSocket protocol negotiation. + * Updated to MQTTnet 2.5.3. Copyright Christian Kratky 2016-2017 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/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs index 9046bb9c..d8e24a47 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs @@ -31,7 +31,7 @@ namespace MQTTnet.Implementations var uri = _options.Uri; if (!uri.StartsWith("ws://", StringComparison.OrdinalIgnoreCase) && !uri.StartsWith("wss://", StringComparison.OrdinalIgnoreCase)) { - if (!_options.TlsOptions.UseTls) + if (_options.TlsOptions?.UseTls == false) { uri = "ws://" + uri; } diff --git a/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs b/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs index 8801c012..8d88ddcf 100644 --- a/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs +++ b/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs @@ -27,7 +27,7 @@ namespace MQTTnet.Core.Server foreach (var topicFilter in subscribePacket.TopicFilters) { var interceptorContext = new MqttSubscriptionInterceptorContext(clientId, topicFilter); - _options.SubscriptionsInterceptor?.Invoke(interceptorContext); + _options.SubscriptionInterceptor?.Invoke(interceptorContext); responsePacket.SubscribeReturnCodes.Add(interceptorContext.AcceptSubscription ? MqttSubscribeReturnCode.SuccessMaximumQoS1 : MqttSubscribeReturnCode.Failure); if (interceptorContext.CloseConnection) diff --git a/MQTTnet.Core/Server/MqttConnectionValidatorContext.cs b/MQTTnet.Core/Server/MqttConnectionValidatorContext.cs new file mode 100644 index 00000000..83a1eabc --- /dev/null +++ b/MQTTnet.Core/Server/MqttConnectionValidatorContext.cs @@ -0,0 +1,25 @@ +using MQTTnet.Core.Protocol; + +namespace MQTTnet.Core.Server +{ + public class MqttConnectionValidatorContext + { + public MqttConnectionValidatorContext(string clientId, string username, string password, MqttApplicationMessage willMessage) + { + ClientId = clientId; + Username = username; + Password = password; + WillMessage = willMessage; + } + + public string ClientId { get; } + + public string Username { get; } + + public string Password { get; } + + public MqttApplicationMessage WillMessage { get; } + + public MqttConnectReturnCode ReturnCode { get; set; } = MqttConnectReturnCode.ConnectionAccepted; + } +} diff --git a/MQTTnet.Core/Server/MqttServerOptions.cs b/MQTTnet.Core/Server/MqttServerOptions.cs index 4b096764..8988b111 100644 --- a/MQTTnet.Core/Server/MqttServerOptions.cs +++ b/MQTTnet.Core/Server/MqttServerOptions.cs @@ -11,14 +11,14 @@ namespace MQTTnet.Core.Server public MqttServerTlsEndpointOptions TlsEndpointOptions { get; } = new MqttServerTlsEndpointOptions(); public int ConnectionBacklog { get; set; } = 10; - + public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(15); public Func ConnectionValidator { get; set; } public Action ApplicationMessageInterceptor { get; set; } - public Action SubscriptionsInterceptor { get; set; } + public Action SubscriptionInterceptor { get; set; } public IMqttServerStorage Storage { get; set; } } diff --git a/MQTTnet.Core/Server/MqttServerOptionsBuilder.cs b/MQTTnet.Core/Server/MqttServerOptionsBuilder.cs new file mode 100644 index 00000000..692f7c19 --- /dev/null +++ b/MQTTnet.Core/Server/MqttServerOptionsBuilder.cs @@ -0,0 +1,88 @@ +using System; +using MQTTnet.Core.Packets; +using MQTTnet.Core.Protocol; + +namespace MQTTnet.Core.Server +{ + public class MqttServerOptionsBuilder + { + private readonly MqttServerOptions _options = new MqttServerOptions(); + + public MqttServerOptionsBuilder WithConnectionBacklog(int value) + { + _options.ConnectionBacklog = value; + return this; + } + + public MqttServerOptionsBuilder WithDefaultCommunicationTimeout(TimeSpan value) + { + _options.DefaultCommunicationTimeout = value; + return this; + } + + public MqttServerOptionsBuilder WithDefaultEndpointPort(int value) + { + _options.DefaultEndpointOptions.Port = value; + return this; + } + + public MqttServerOptionsBuilder WithDefaultEndpoint() + { + _options.DefaultEndpointOptions.IsEnabled = true; + return this; + } + + public MqttServerOptionsBuilder WithoutDefaultEndpoint() + { + _options.DefaultEndpointOptions.IsEnabled = false; + return this; + } + + public MqttServerOptionsBuilder WithEncryptedEndpoint() + { + _options.TlsEndpointOptions.IsEnabled = true; + return this; + } + + public MqttServerOptionsBuilder WithoutEncryptedEndpoint() + { + _options.TlsEndpointOptions.IsEnabled = false; + return this; + } + + public MqttServerOptionsBuilder WithEncryptionCertificate(byte[] value) + { + _options.TlsEndpointOptions.Certificate = value; + return this; + } + + public MqttServerOptionsBuilder WithStorage(IMqttServerStorage value) + { + _options.Storage = value; + return this; + } + + public MqttServerOptionsBuilder WithConnectionValidator(Func value) + { + _options.ConnectionValidator = value; + return this; + } + + public MqttServerOptionsBuilder WithApplicationMessageInterceptor(Action value) + { + _options.ApplicationMessageInterceptor = value; + return this; + } + + public MqttServerOptionsBuilder WithSubscriptionInterceptor(Action value) + { + _options.SubscriptionInterceptor = value; + return this; + } + + public MqttServerOptions Build() + { + return _options; + } + } +} diff --git a/Tests/MQTTnet.TestApp.AspNetCore2/MQTTnet.TestApp.AspNetCore2.csproj b/Tests/MQTTnet.TestApp.AspNetCore2/MQTTnet.TestApp.AspNetCore2.csproj index 7e4e0e3d..553b3417 100644 --- a/Tests/MQTTnet.TestApp.AspNetCore2/MQTTnet.TestApp.AspNetCore2.csproj +++ b/Tests/MQTTnet.TestApp.AspNetCore2/MQTTnet.TestApp.AspNetCore2.csproj @@ -10,7 +10,7 @@ - + diff --git a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs index a0b16269..2a8180bc 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs @@ -40,7 +40,7 @@ namespace MQTTnet.TestApp.NetCore context.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O")); } }, - SubscriptionsInterceptor = context => + SubscriptionInterceptor = context => { if (context.TopicFilter.Topic.StartsWith("admin/foo/bar") && context.ClientId != "theAdmin") { From 1bcf7ec29c0bdcc0dc0224300b57a03c93463014 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Thu, 23 Nov 2017 22:34:16 +0100 Subject: [PATCH 061/149] Fix ASP.NET Core breaking changes --- Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs | 10 ++++------ .../ServiceCollectionExtensions.cs | 12 +++++++++--- Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs | 4 +++- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs b/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs index e21b8fe5..a8061052 100644 --- a/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs +++ b/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; @@ -12,12 +13,9 @@ namespace MQTTnet.AspNetCore { private readonly MqttServerOptions _options; - public MqttHostedServer( - MqttServerOptions options, - IEnumerable adapters, - IMqttNetLogger logger) : base(adapters, logger) + public MqttHostedServer(MqttServerOptions options, IEnumerable adapters, IMqttNetLogger logger) : base(adapters, logger) { - _options = options; + _options = options ?? throw new ArgumentNullException(nameof(options)); } public Task StartAsync(CancellationToken cancellationToken) diff --git a/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs b/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs index f39b1cf8..236d44d1 100644 --- a/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs +++ b/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs @@ -1,17 +1,23 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using MQTTnet.Core.Adapter; +using MQTTnet.Core.Diagnostics; using MQTTnet.Core.Server; namespace MQTTnet.AspNetCore { public static class ServiceCollectionExtensions { - public static IServiceCollection AddHostedMqttServer(this IServiceCollection services) + public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, MqttServerOptions options) { + if (options == null) throw new ArgumentNullException(nameof(options)); + + services.AddSingleton(options); + services.AddSingleton(new MqttNetLogger()); + services.AddSingleton(); services.AddSingleton(s => s.GetService()); services.AddSingleton(s => s.GetService()); - services.AddSingleton(); services.AddSingleton(); services.AddSingleton(s => s.GetService()); diff --git a/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs b/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs index 55c57a18..5c9b32ed 100644 --- a/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs +++ b/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using MQTTnet.AspNetCore; using MQTTnet.Core; +using MQTTnet.Core.Server; namespace MQTTnet.TestApp.AspNetCore2 { @@ -16,7 +17,8 @@ namespace MQTTnet.TestApp.AspNetCore2 public void ConfigureServices(IServiceCollection services) { - services.AddHostedMqttServer(); + var mqttServerOptions = new MqttServerOptionsBuilder().Build(); + services.AddHostedMqttServer(mqttServerOptions); } // In class _Startup_ of the ASP.NET Core 2.0 project. From b02b0ccd7cb98bc244a4b12e0bf717b8ae00682e Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Thu, 23 Nov 2017 22:50:26 +0100 Subject: [PATCH 062/149] Refactor some names. --- .../{MqttNetConsoleTrace.cs => MqttNetConsoleLogger.cs} | 2 +- .../{ => Diagnostics}/TargetFrameworkInfoProvider.cs | 0 Tests/MQTTnet.TestApp.NetCore/ServerTest.cs | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename Frameworks/MQTTnet.NetStandard/Diagnostics/{MqttNetConsoleTrace.cs => MqttNetConsoleLogger.cs} (97%) rename Frameworks/MQTTnet.NetStandard/{ => Diagnostics}/TargetFrameworkInfoProvider.cs (100%) diff --git a/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetConsoleTrace.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetConsoleLogger.cs similarity index 97% rename from Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetConsoleTrace.cs rename to Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetConsoleLogger.cs index d660b17c..3cc13c38 100644 --- a/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetConsoleTrace.cs +++ b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetConsoleLogger.cs @@ -4,7 +4,7 @@ using MQTTnet.Core.Diagnostics; namespace MQTTnet.Diagnostics { - public static class MqttNetConsoleTrace + public static class MqttNetConsoleLogger { private static readonly object Lock = new object(); diff --git a/Frameworks/MQTTnet.NetStandard/TargetFrameworkInfoProvider.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/TargetFrameworkInfoProvider.cs similarity index 100% rename from Frameworks/MQTTnet.NetStandard/TargetFrameworkInfoProvider.cs rename to Frameworks/MQTTnet.NetStandard/Diagnostics/TargetFrameworkInfoProvider.cs diff --git a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs index 2a8180bc..23282920 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs @@ -13,7 +13,7 @@ namespace MQTTnet.TestApp.NetCore { try { - MqttNetConsoleTrace.ForwardToConsole(); + MqttNetConsoleLogger.ForwardToConsole(); var options = new MqttServerOptions { From 9c20edd3d05eb847023e834412203eae905d1703 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sat, 25 Nov 2017 16:17:44 +0100 Subject: [PATCH 063/149] Update documents --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6db587aa..57dfce2e 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov * .NET Standard 1.3+ * .NET Core 1.1+ * .NET Core App 1.1+ -* Universal Windows Platform (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU) +* Universal Windows Platform (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU, WIndows IoT Core) * .NET Framework 4.5.2+ (x86, x64, AnyCPU) * Mono 5.2+ * Xamarin.Android 7.5+ From ebfc6aab6ba40afe4d9a5b9757d10e17df47d99f Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sat, 25 Nov 2017 16:20:07 +0100 Subject: [PATCH 064/149] Fix nuget spec --- Build/MQTTnet.AspNetCore.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index b98eec0d..3a862bad 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -16,7 +16,7 @@ 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 a72516fdcc20105e5a808242acf63cc747620633 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 25 Nov 2017 19:50:31 +0100 Subject: [PATCH 065/149] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 57dfce2e..92520be9 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov * .NET Standard 1.3+ * .NET Core 1.1+ * .NET Core App 1.1+ -* Universal Windows Platform (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU, WIndows IoT Core) +* Universal Windows Platform (UWP) 10.0.10240+ (x86, x64, ARM, AnyCPU, Windows 10 IoT Core) * .NET Framework 4.5.2+ (x86, x64, AnyCPU) * Mono 5.2+ * Xamarin.Android 7.5+ From f9d67e2cd2420e3c4a8c445b1ca962bb5f49e354 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sat, 25 Nov 2017 19:55:26 +0100 Subject: [PATCH 066/149] Merge proces, enable signing of the assembly. --- .gitignore | 2 ++ Build/MQTTnet.nuspec | 14 ++++------- .../ApplicationBuilderExtensions.cs | 2 +- .../MQTTnet.AspnetCore/MqttHostedServer.cs | 6 ++--- .../MqttWebSocketServerAdapter.cs | 8 +++--- .../MqttWebSocketServerChannel.cs | 2 +- .../ServiceCollectionExtensions.cs | 6 ++--- .../Adapter/IMqttChannelAdapter.cs | 6 ++--- .../Adapter/IMqttServerAdapter.cs | 4 +-- .../Adapter/MqttChannelAdapter.cs | 14 +++++------ .../Adapter/MqttChannelAdapterExtensions.cs | 4 +-- .../Adapter/MqttConnectingFailedException.cs | 6 ++--- ...qttServerAdapterClientAcceptedEventArgs.cs | 2 +- .../Adapter/ReceivedMqttPacket.cs | 4 +-- .../ApplicationMessagePublisherExtensions.cs | 2 +- .../Channel/IMqttChannel.cs | 6 ++--- .../Client/IMqttClient.cs | 3 +-- .../Client/IMqttClientAdapterFactory.cs | 6 ++--- .../Client/IMqttClientChannelOptions.cs | 2 +- .../Client/IMqttClientCredentials.cs | 2 +- .../Client/IMqttClientFactory.cs | 6 ++--- .../Client/IMqttClientOptions.cs | 4 +-- .../MQTTnet.NetStandard}/Client/MqttClient.cs | 14 +++++------ .../Client/MqttClientConnectResult.cs | 2 +- .../Client/MqttClientConnectedEventArgs.cs | 2 +- .../Client/MqttClientCredentials.cs | 2 +- .../Client/MqttClientDisconnectedEventArgs.cs | 2 +- .../Client/MqttClientExtensions.cs | 2 +- .../Client/MqttClientOptions.cs | 4 +-- .../Client/MqttClientOptionsBuilder.cs | 4 +-- .../Client/MqttClientTcpOptions.cs | 2 +- .../Client/MqttClientTcpOptionsExtensions.cs | 2 +- .../Client/MqttClientTlsOptions.cs | 2 +- .../Client/MqttClientWebSocketOptions.cs | 2 +- .../Client/MqttPacketDispatcher.cs | 10 ++++---- .../Client/MqttSubscribeResult.cs | 5 ++-- .../Diagnostics/IMqttNetLogger.cs | 2 +- .../Diagnostics/MqttNetGlobalLogger.cs | 4 +-- .../Diagnostics/MqttNetLogLevel.cs | 2 +- .../Diagnostics/MqttNetLogMessage.cs | 2 +- .../MqttNetLogMessagePublishedEventArgs.cs | 2 +- .../Diagnostics/MqttNetLogger.cs | 6 ++--- .../TargetFrameworkInfoProvider.cs | 2 +- .../Exceptions/MqttCommunicationException.cs | 2 +- .../MqttCommunicationTimedOutException.cs | 2 +- .../MqttProtocolViolationException.cs | 2 +- .../IApplicationMessagePublisher.cs | 2 +- .../IApplicationMessageReceiver.cs | 3 +-- .../MqttClientAdapterFactory.cs | 8 +++--- .../Implementations/MqttServerAdapter.Uwp.cs | 8 +++--- .../Implementations/MqttServerAdapter.cs | 8 +++--- .../Implementations/MqttTcpChannel.Uwp.cs | 4 +-- .../Implementations/MqttTcpChannel.cs | 4 +-- .../Implementations/MqttWebSocketChannel.cs | 6 ++--- .../Implementations/WebSocketStream.cs | 2 +- .../MqttApplicationMessageExtensions.cs | 4 +-- .../Internal/TaskExtensions.cs | 4 +-- .../MQTTnet.Netstandard.csproj | 6 ++--- .../ManagedClient/IManagedMqttClient.cs | 4 +-- .../IManagedMqttClientOptions.cs | 4 +-- .../IManagedMqttClientStorage.cs | 2 +- .../ManagedClient/ManagedMqttClient.cs | 10 ++++---- .../ManagedMqttClientExtensions.cs | 2 +- .../ManagedClient/ManagedMqttClientOptions.cs | 4 +-- .../ManagedMqttClientOptionsBuilder.cs | 4 +-- .../ManagedMqttClientStorageManager.cs | 2 +- .../ManagedClient/ReconnectionResult.cs | 2 +- .../MqttApplicationMessage.cs | 4 +-- .../MqttApplicationMessageBuilder.cs | 6 ++--- ...MqttApplicationMessageReceivedEventArgs.cs | 2 +- Frameworks/MQTTnet.NetStandard/MqttFactory.cs | 10 ++++---- .../Packets/IMqttPacketWithIdentifier.cs | 2 +- .../Packets/MqttBasePacket.cs | 2 +- .../Packets/MqttBasePublishPacket.cs | 2 +- .../Packets/MqttConnAckPacket.cs | 4 +-- .../Packets/MqttConnectPacket.cs | 4 +-- .../Packets/MqttDisconnectPacket.cs | 2 +- .../Packets/MqttPacketExtensions.cs | 2 +- .../Packets/MqttPacketHeader.cs | 4 +-- .../Packets/MqttPingReqPacket.cs | 2 +- .../Packets/MqttPingRespPacket.cs | 2 +- .../Packets/MqttPubAckPacket.cs | 2 +- .../Packets/MqttPubCompPacket.cs | 2 +- .../Packets/MqttPubRecPacket.cs | 2 +- .../Packets/MqttPubRelPacket.cs | 2 +- .../Packets/MqttPublishPacket.cs | 4 +-- .../Packets/MqttSubAckPacket.cs | 4 +-- .../Packets/MqttSubscribePacket.cs | 2 +- .../Packets/MqttUnsubAckPacket.cs | 2 +- .../Packets/MqttUnsubscribe.cs | 2 +- .../Protocol/MqttConnectReturnCode.cs | 2 +- .../Protocol/MqttControlPacketType.cs | 2 +- .../Protocol/MqttQualityOfServiceLevel.cs | 2 +- .../Protocol/MqttSubscribeReturnCode.cs | 2 +- .../Serializer/ByteReader.cs | 2 +- .../Serializer/ByteWriter.cs | 2 +- .../Serializer/IMqttPacketSerializer.cs | 6 ++--- .../Serializer/MqttPacketReader.cs | 10 ++++---- .../Serializer/MqttPacketSerializer.cs | 10 ++++---- .../Serializer/MqttPacketWriter.cs | 6 ++--- .../Serializer/MqttProtocolVersion.cs | 2 +- .../Server/CheckSubscriptionsResult.cs | 4 +-- .../Server/ConnectedMqttClient.cs | 4 +-- .../Server/GetOrCreateClientSessionResult.cs | 2 +- .../Server/IMqttServer.cs | 2 +- .../Server/IMqttServerFactory.cs | 6 ++--- .../Server/IMqttServerStorage.cs | 2 +- ...qttApplicationMessageInterceptorContext.cs | 2 +- .../Server/MqttClientConnectedEventArgs.cs | 2 +- .../Server/MqttClientDisconnectedEventArgs.cs | 2 +- .../Server/MqttClientPendingMessagesQueue.cs | 12 ++++----- .../Server/MqttClientSession.cs | 16 ++++++------ .../Server/MqttClientSessionsManager.cs | 16 ++++++------ .../Server/MqttClientSubscribeResult.cs | 4 +-- .../Server/MqttClientSubscriptionsManager.cs | 6 ++--- .../Server/MqttConnectionValidatorContext.cs | 4 +-- .../Server/MqttRetainedMessagesManager.cs | 6 ++--- .../MQTTnet.NetStandard}/Server/MqttServer.cs | 8 +++--- .../MqttServerDefaultEndpointOptions.cs | 2 +- .../Server/MqttServerOptions.cs | 6 ++--- .../Server/MqttServerOptionsBuilder.cs | 6 ++--- .../Server/MqttServerOptionsExtensions.cs | 2 +- .../Server/MqttServerStartedEventArgs.cs | 2 +- .../Server/MqttServerTlsEndpointOptions.cs | 2 +- .../Server/MqttSubscribeResult.cs | 4 +-- .../MqttSubscriptionInterceptorContext.cs | 2 +- .../Server/MqttTopicFilterComparer.cs | 2 +- .../MQTTnet.NetStandard}/TopicFilter.cs | 4 +-- .../TopicFilterBuilder.cs | 6 ++--- MQTTnet.Core/MQTTnet.Core.csproj | 25 ------------------- MQTTnet.sln | 20 +-------------- Tests/MQTTnet.Core.Tests/ByteReaderTests.cs | 2 +- Tests/MQTTnet.Core.Tests/ByteWriterTests.cs | 2 +- Tests/MQTTnet.Core.Tests/ExtensionTests.cs | 4 +-- .../MqttApplicationMessageBuilderTests.cs | 2 +- .../MqttPacketReaderTests.cs | 2 +- .../MqttPacketSerializerTests.cs | 8 +++--- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 8 +++--- .../MqttSubscriptionsManagerTests.cs | 6 ++--- .../TestMqttCommunicationAdapter.cs | 6 ++--- .../TestMqttCommunicationAdapterFactory.cs | 6 ++--- .../TestMqttServerAdapter.cs | 12 ++++----- .../TopicFilterComparerTests.cs | 2 +- Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs | 3 +-- Tests/MQTTnet.TestApp.NetCore/ClientTest.cs | 3 +-- .../ManagedClientTest.cs | 7 +++--- .../MqttNetConsoleLogger.cs | 8 +++--- .../PerformanceTest.cs | 9 +++---- Tests/MQTTnet.TestApp.NetCore/Program.cs | 8 +++--- Tests/MQTTnet.TestApp.NetCore/ServerTest.cs | 4 +-- .../JsonServerStorage.cs | 3 +-- .../MQTTnet.TestApp.UniversalWindows.csproj | 4 --- .../MainPage.xaml.cs | 15 ++++++----- 153 files changed, 323 insertions(+), 383 deletions(-) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Adapter/IMqttChannelAdapter.cs (85%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Adapter/IMqttServerAdapter.cs (82%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Adapter/MqttChannelAdapter.cs (96%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Adapter/MqttChannelAdapterExtensions.cs (89%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Adapter/MqttConnectingFailedException.cs (79%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Adapter/MqttServerAdapterClientAcceptedEventArgs.cs (93%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Adapter/ReceivedMqttPacket.cs (90%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/ApplicationMessagePublisherExtensions.cs (95%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Channel/IMqttChannel.cs (69%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/IMqttClient.cs (91%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/IMqttClientAdapterFactory.cs (64%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/IMqttClientChannelOptions.cs (77%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/IMqttClientCredentials.cs (78%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/IMqttClientFactory.cs (74%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/IMqttClientOptions.cs (88%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttClient.cs (98%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttClientConnectResult.cs (87%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttClientConnectedEventArgs.cs (90%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttClientCredentials.cs (83%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttClientDisconnectedEventArgs.cs (90%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttClientExtensions.cs (96%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttClientOptions.cs (92%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttClientOptionsBuilder.cs (98%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttClientTcpOptions.cs (88%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttClientTcpOptionsExtensions.cs (93%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttClientTlsOptions.cs (92%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttClientWebSocketOptions.cs (94%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttPacketDispatcher.cs (96%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Client/MqttSubscribeResult.cs (79%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Diagnostics/IMqttNetLogger.cs (94%) rename MQTTnet.Core/Diagnostics/MqttNetGlobalLog.cs => Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetGlobalLogger.cs (86%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Diagnostics/MqttNetLogLevel.cs (74%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Diagnostics/MqttNetLogMessage.cs (95%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs (91%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Diagnostics/MqttNetLogger.cs (93%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Exceptions/MqttCommunicationException.cs (92%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Exceptions/MqttCommunicationTimedOutException.cs (73%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Exceptions/MqttProtocolViolationException.cs (86%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/IApplicationMessagePublisher.cs (90%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/IApplicationMessageReceiver.cs (78%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Internal/MqttApplicationMessageExtensions.cs (94%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Internal/TaskExtensions.cs (97%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/ManagedClient/IManagedMqttClient.cs (90%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/ManagedClient/IManagedMqttClientOptions.cs (77%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/ManagedClient/IManagedMqttClientStorage.cs (88%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/ManagedClient/ManagedMqttClient.cs (98%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/ManagedClient/ManagedMqttClientExtensions.cs (95%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/ManagedClient/ManagedMqttClientOptions.cs (83%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/ManagedClient/ManagedMqttClientOptionsBuilder.cs (95%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/ManagedClient/ManagedMqttClientStorageManager.cs (98%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/ManagedClient/ReconnectionResult.cs (74%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/MqttApplicationMessage.cs (94%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/MqttApplicationMessageBuilder.cs (97%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/MqttApplicationMessageReceivedEventArgs.cs (95%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/IMqttPacketWithIdentifier.cs (76%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttBasePacket.cs (62%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttBasePublishPacket.cs (81%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttConnAckPacket.cs (85%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttConnectPacket.cs (91%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttDisconnectPacket.cs (83%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttPacketExtensions.cs (96%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttPacketHeader.cs (77%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttPingReqPacket.cs (83%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttPingRespPacket.cs (83%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttPubAckPacket.cs (83%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttPubCompPacket.cs (83%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttPubRecPacket.cs (83%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttPubRelPacket.cs (83%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttPublishPacket.cs (91%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttSubAckPacket.cs (91%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttSubscribePacket.cs (95%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttUnsubAckPacket.cs (89%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Packets/MqttUnsubscribe.cs (94%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Protocol/MqttConnectReturnCode.cs (91%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Protocol/MqttControlPacketType.cs (91%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Protocol/MqttQualityOfServiceLevel.cs (80%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Protocol/MqttSubscribeReturnCode.cs (84%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Serializer/ByteReader.cs (96%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Serializer/ByteWriter.cs (95%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Serializer/IMqttPacketSerializer.cs (72%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Serializer/MqttPacketReader.cs (95%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Serializer/MqttPacketSerializer.cs (99%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Serializer/MqttPacketWriter.cs (96%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Serializer/MqttProtocolVersion.cs (68%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/CheckSubscriptionsResult.cs (74%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/ConnectedMqttClient.cs (72%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/GetOrCreateClientSessionResult.cs (84%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/IMqttServer.cs (94%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/IMqttServerFactory.cs (72%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/IMqttServerStorage.cs (90%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttApplicationMessageInterceptorContext.cs (81%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttClientConnectedEventArgs.cs (91%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttClientDisconnectedEventArgs.cs (91%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttClientPendingMessagesQueue.cs (95%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttClientSession.cs (97%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttClientSessionsManager.cs (97%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttClientSubscribeResult.cs (73%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttClientSubscriptionsManager.cs (97%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttConnectionValidatorContext.cs (91%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttRetainedMessagesManager.cs (98%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttServer.cs (98%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttServerDefaultEndpointOptions.cs (83%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttServerOptions.cs (90%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttServerOptionsBuilder.cs (96%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttServerOptionsExtensions.cs (96%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttServerStartedEventArgs.cs (75%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttServerTlsEndpointOptions.cs (85%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttSubscribeResult.cs (73%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttSubscriptionInterceptorContext.cs (93%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/Server/MqttTopicFilterComparer.cs (97%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/TopicFilter.cs (92%) rename {MQTTnet.Core => Frameworks/MQTTnet.NetStandard}/TopicFilterBuilder.cs (93%) delete mode 100644 MQTTnet.Core/MQTTnet.Core.csproj rename {Frameworks/MQTTnet.NetStandard/Diagnostics => Tests/MQTTnet.TestApp.NetCore}/MqttNetConsoleLogger.cs (88%) diff --git a/.gitignore b/.gitignore index 4372f8ed..7c38d7d9 100644 --- a/.gitignore +++ b/.gitignore @@ -291,3 +291,5 @@ __pycache__/ Build/nuget.exe *.js *.map + +*codeSigningKey.pfx diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 8dd284ea..2ebe29de 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -2,7 +2,7 @@ MQTTnet - 2.5.3 + 2.6.0 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,9 +10,9 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * [Core] Removed all dependencies to other libraries (BREAKING CHANGE!). -* [Core] Updated SDK libraries. -* [Client] Fixed broken support for WebSocketSecure connections (Thanks to @StAI). + * Merged projects. +* Added a strong name for the assembly. + Copyright Christian Kratky 2016-2017 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 @@ -46,23 +46,19 @@ + - - - - - diff --git a/Frameworks/MQTTnet.AspnetCore/ApplicationBuilderExtensions.cs b/Frameworks/MQTTnet.AspnetCore/ApplicationBuilderExtensions.cs index 831392da..5a25712d 100644 --- a/Frameworks/MQTTnet.AspnetCore/ApplicationBuilderExtensions.cs +++ b/Frameworks/MQTTnet.AspnetCore/ApplicationBuilderExtensions.cs @@ -1,8 +1,8 @@ using System; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; -using MQTTnet.Core.Server; using System.Linq; +using MQTTnet.Server; namespace MQTTnet.AspNetCore { diff --git a/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs b/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs index a8061052..7c7d3041 100644 --- a/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs +++ b/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Server; +using MQTTnet.Adapter; +using MQTTnet.Diagnostics; +using MQTTnet.Server; namespace MQTTnet.AspNetCore { diff --git a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs index 27810924..5af8b64d 100644 --- a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs +++ b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs @@ -1,10 +1,10 @@ using System; using System.Net.WebSockets; using System.Threading.Tasks; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Serializer; -using MQTTnet.Core.Server; +using MQTTnet.Adapter; +using MQTTnet.Diagnostics; +using MQTTnet.Serializer; +using MQTTnet.Server; namespace MQTTnet.AspNetCore { diff --git a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerChannel.cs b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerChannel.cs index 55b49400..7325a5f8 100644 --- a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerChannel.cs +++ b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerChannel.cs @@ -3,7 +3,7 @@ using System.IO; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Channel; +using MQTTnet.Channel; using MQTTnet.Implementations; namespace MQTTnet.AspNetCore diff --git a/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs b/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs index 236d44d1..a6af6ebe 100644 --- a/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs +++ b/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs @@ -1,9 +1,9 @@ using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Server; +using MQTTnet.Adapter; +using MQTTnet.Diagnostics; +using MQTTnet.Server; namespace MQTTnet.AspNetCore { diff --git a/MQTTnet.Core/Adapter/IMqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/IMqttChannelAdapter.cs similarity index 85% rename from MQTTnet.Core/Adapter/IMqttChannelAdapter.cs rename to Frameworks/MQTTnet.NetStandard/Adapter/IMqttChannelAdapter.cs index 13908f62..5f58d0c5 100644 --- a/MQTTnet.Core/Adapter/IMqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/IMqttChannelAdapter.cs @@ -2,10 +2,10 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Serializer; +using MQTTnet.Packets; +using MQTTnet.Serializer; -namespace MQTTnet.Core.Adapter +namespace MQTTnet.Adapter { public interface IMqttChannelAdapter { diff --git a/MQTTnet.Core/Adapter/IMqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/IMqttServerAdapter.cs similarity index 82% rename from MQTTnet.Core/Adapter/IMqttServerAdapter.cs rename to Frameworks/MQTTnet.NetStandard/Adapter/IMqttServerAdapter.cs index 9209185e..d4ea9413 100644 --- a/MQTTnet.Core/Adapter/IMqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/IMqttServerAdapter.cs @@ -1,8 +1,8 @@ using System; using System.Threading.Tasks; -using MQTTnet.Core.Server; +using MQTTnet.Server; -namespace MQTTnet.Core.Adapter +namespace MQTTnet.Adapter { public interface IMqttServerAdapter { diff --git a/MQTTnet.Core/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs similarity index 96% rename from MQTTnet.Core/Adapter/MqttChannelAdapter.cs rename to Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index 5dfcfc01..53603fa5 100644 --- a/MQTTnet.Core/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -4,14 +4,14 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Channel; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Exceptions; -using MQTTnet.Core.Internal; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Serializer; +using MQTTnet.Channel; +using MQTTnet.Diagnostics; +using MQTTnet.Exceptions; +using MQTTnet.Internal; +using MQTTnet.Packets; +using MQTTnet.Serializer; -namespace MQTTnet.Core.Adapter +namespace MQTTnet.Adapter { public class MqttChannelAdapter : IMqttChannelAdapter { diff --git a/MQTTnet.Core/Adapter/MqttChannelAdapterExtensions.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapterExtensions.cs similarity index 89% rename from MQTTnet.Core/Adapter/MqttChannelAdapterExtensions.cs rename to Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapterExtensions.cs index f271248f..58258ab6 100644 --- a/MQTTnet.Core/Adapter/MqttChannelAdapterExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapterExtensions.cs @@ -1,9 +1,9 @@ using System; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Packets; +using MQTTnet.Packets; -namespace MQTTnet.Core.Adapter +namespace MQTTnet.Adapter { public static class MqttChannelAdapterExtensions { diff --git a/MQTTnet.Core/Adapter/MqttConnectingFailedException.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttConnectingFailedException.cs similarity index 79% rename from MQTTnet.Core/Adapter/MqttConnectingFailedException.cs rename to Frameworks/MQTTnet.NetStandard/Adapter/MqttConnectingFailedException.cs index 045d0d13..68445cfd 100644 --- a/MQTTnet.Core/Adapter/MqttConnectingFailedException.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttConnectingFailedException.cs @@ -1,7 +1,7 @@ -using MQTTnet.Core.Exceptions; -using MQTTnet.Core.Protocol; +using MQTTnet.Exceptions; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Adapter +namespace MQTTnet.Adapter { public class MqttConnectingFailedException : MqttCommunicationException { diff --git a/MQTTnet.Core/Adapter/MqttServerAdapterClientAcceptedEventArgs.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttServerAdapterClientAcceptedEventArgs.cs similarity index 93% rename from MQTTnet.Core/Adapter/MqttServerAdapterClientAcceptedEventArgs.cs rename to Frameworks/MQTTnet.NetStandard/Adapter/MqttServerAdapterClientAcceptedEventArgs.cs index 341f6327..42852493 100644 --- a/MQTTnet.Core/Adapter/MqttServerAdapterClientAcceptedEventArgs.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttServerAdapterClientAcceptedEventArgs.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; -namespace MQTTnet.Core.Adapter +namespace MQTTnet.Adapter { public class MqttServerAdapterClientAcceptedEventArgs : EventArgs { diff --git a/MQTTnet.Core/Adapter/ReceivedMqttPacket.cs b/Frameworks/MQTTnet.NetStandard/Adapter/ReceivedMqttPacket.cs similarity index 90% rename from MQTTnet.Core/Adapter/ReceivedMqttPacket.cs rename to Frameworks/MQTTnet.NetStandard/Adapter/ReceivedMqttPacket.cs index f7fdbcc5..a44fb54e 100644 --- a/MQTTnet.Core/Adapter/ReceivedMqttPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/ReceivedMqttPacket.cs @@ -1,8 +1,8 @@ using System; using System.IO; -using MQTTnet.Core.Packets; +using MQTTnet.Packets; -namespace MQTTnet.Core.Adapter +namespace MQTTnet.Adapter { public sealed class ReceivedMqttPacket : IDisposable { diff --git a/MQTTnet.Core/ApplicationMessagePublisherExtensions.cs b/Frameworks/MQTTnet.NetStandard/ApplicationMessagePublisherExtensions.cs similarity index 95% rename from MQTTnet.Core/ApplicationMessagePublisherExtensions.cs rename to Frameworks/MQTTnet.NetStandard/ApplicationMessagePublisherExtensions.cs index 6893a1b6..73328de9 100644 --- a/MQTTnet.Core/ApplicationMessagePublisherExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/ApplicationMessagePublisherExtensions.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; -namespace MQTTnet.Core +namespace MQTTnet { public static class ApplicationMessagePublisherExtensions { diff --git a/MQTTnet.Core/Channel/IMqttChannel.cs b/Frameworks/MQTTnet.NetStandard/Channel/IMqttChannel.cs similarity index 69% rename from MQTTnet.Core/Channel/IMqttChannel.cs rename to Frameworks/MQTTnet.NetStandard/Channel/IMqttChannel.cs index 92c0681b..809b0b06 100644 --- a/MQTTnet.Core/Channel/IMqttChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Channel/IMqttChannel.cs @@ -1,7 +1,7 @@ -using System.Threading.Tasks; -using System.IO; +using System.IO; +using System.Threading.Tasks; -namespace MQTTnet.Core.Channel +namespace MQTTnet.Channel { public interface IMqttChannel { diff --git a/MQTTnet.Core/Client/IMqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/IMqttClient.cs similarity index 91% rename from MQTTnet.Core/Client/IMqttClient.cs rename to Frameworks/MQTTnet.NetStandard/Client/IMqttClient.cs index 6a39e211..0ac2f491 100644 --- a/MQTTnet.Core/Client/IMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/IMqttClient.cs @@ -1,9 +1,8 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using MQTTnet.Core.Packets; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public interface IMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher { diff --git a/MQTTnet.Core/Client/IMqttClientAdapterFactory.cs b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientAdapterFactory.cs similarity index 64% rename from MQTTnet.Core/Client/IMqttClientAdapterFactory.cs rename to Frameworks/MQTTnet.NetStandard/Client/IMqttClientAdapterFactory.cs index 3bd61431..8b144818 100644 --- a/MQTTnet.Core/Client/IMqttClientAdapterFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientAdapterFactory.cs @@ -1,7 +1,7 @@ -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Diagnostics; +using MQTTnet.Adapter; +using MQTTnet.Diagnostics; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public interface IMqttClientAdapterFactory { diff --git a/MQTTnet.Core/Client/IMqttClientChannelOptions.cs b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientChannelOptions.cs similarity index 77% rename from MQTTnet.Core/Client/IMqttClientChannelOptions.cs rename to Frameworks/MQTTnet.NetStandard/Client/IMqttClientChannelOptions.cs index 004430f9..22249632 100644 --- a/MQTTnet.Core/Client/IMqttClientChannelOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientChannelOptions.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public interface IMqttClientChannelOptions { diff --git a/MQTTnet.Core/Client/IMqttClientCredentials.cs b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientCredentials.cs similarity index 78% rename from MQTTnet.Core/Client/IMqttClientCredentials.cs rename to Frameworks/MQTTnet.NetStandard/Client/IMqttClientCredentials.cs index c4dfc127..d214d64f 100644 --- a/MQTTnet.Core/Client/IMqttClientCredentials.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientCredentials.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public interface IMqttClientCredentials { diff --git a/MQTTnet.Core/Client/IMqttClientFactory.cs b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientFactory.cs similarity index 74% rename from MQTTnet.Core/Client/IMqttClientFactory.cs rename to Frameworks/MQTTnet.NetStandard/Client/IMqttClientFactory.cs index 8acdb91a..444c16fc 100644 --- a/MQTTnet.Core/Client/IMqttClientFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientFactory.cs @@ -1,7 +1,7 @@ -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.ManagedClient; +using MQTTnet.Diagnostics; +using MQTTnet.ManagedClient; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public interface IMqttClientFactory { diff --git a/MQTTnet.Core/Client/IMqttClientOptions.cs b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientOptions.cs similarity index 88% rename from MQTTnet.Core/Client/IMqttClientOptions.cs rename to Frameworks/MQTTnet.NetStandard/Client/IMqttClientOptions.cs index 9139d5cb..035dba11 100644 --- a/MQTTnet.Core/Client/IMqttClientOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientOptions.cs @@ -1,7 +1,7 @@ using System; -using MQTTnet.Core.Serializer; +using MQTTnet.Serializer; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public interface IMqttClientOptions { diff --git a/MQTTnet.Core/Client/MqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs similarity index 98% rename from MQTTnet.Core/Client/MqttClient.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs index f270a381..a24fbff9 100644 --- a/MQTTnet.Core/Client/MqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs @@ -3,14 +3,14 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Exceptions; -using MQTTnet.Core.Internal; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Protocol; +using MQTTnet.Adapter; +using MQTTnet.Diagnostics; +using MQTTnet.Exceptions; +using MQTTnet.Internal; +using MQTTnet.Packets; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public class MqttClient : IMqttClient { diff --git a/MQTTnet.Core/Client/MqttClientConnectResult.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientConnectResult.cs similarity index 87% rename from MQTTnet.Core/Client/MqttClientConnectResult.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttClientConnectResult.cs index 57db57df..6044bf50 100644 --- a/MQTTnet.Core/Client/MqttClientConnectResult.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientConnectResult.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public class MqttClientConnectResult { diff --git a/MQTTnet.Core/Client/MqttClientConnectedEventArgs.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientConnectedEventArgs.cs similarity index 90% rename from MQTTnet.Core/Client/MqttClientConnectedEventArgs.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttClientConnectedEventArgs.cs index 107a2c95..c8c6ce56 100644 --- a/MQTTnet.Core/Client/MqttClientConnectedEventArgs.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientConnectedEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public class MqttClientConnectedEventArgs : EventArgs { diff --git a/MQTTnet.Core/Client/MqttClientCredentials.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientCredentials.cs similarity index 83% rename from MQTTnet.Core/Client/MqttClientCredentials.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttClientCredentials.cs index 085778a3..feaa1e6c 100644 --- a/MQTTnet.Core/Client/MqttClientCredentials.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientCredentials.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public class MqttClientCredentials : IMqttClientCredentials { diff --git a/MQTTnet.Core/Client/MqttClientDisconnectedEventArgs.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientDisconnectedEventArgs.cs similarity index 90% rename from MQTTnet.Core/Client/MqttClientDisconnectedEventArgs.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttClientDisconnectedEventArgs.cs index 1e9609ef..26125b9f 100644 --- a/MQTTnet.Core/Client/MqttClientDisconnectedEventArgs.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientDisconnectedEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public class MqttClientDisconnectedEventArgs : EventArgs { diff --git a/MQTTnet.Core/Client/MqttClientExtensions.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientExtensions.cs similarity index 96% rename from MQTTnet.Core/Client/MqttClientExtensions.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttClientExtensions.cs index 567184d0..a1a89e30 100644 --- a/MQTTnet.Core/Client/MqttClientExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientExtensions.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public static class MqttClientExtensions { diff --git a/MQTTnet.Core/Client/MqttClientOptions.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientOptions.cs similarity index 92% rename from MQTTnet.Core/Client/MqttClientOptions.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttClientOptions.cs index 04cf8bdb..20e711f3 100644 --- a/MQTTnet.Core/Client/MqttClientOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientOptions.cs @@ -1,7 +1,7 @@ using System; -using MQTTnet.Core.Serializer; +using MQTTnet.Serializer; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public class MqttClientOptions : IMqttClientOptions { diff --git a/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientOptionsBuilder.cs similarity index 98% rename from MQTTnet.Core/Client/MqttClientOptionsBuilder.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttClientOptionsBuilder.cs index 429a3fa7..079e6351 100644 --- a/MQTTnet.Core/Client/MqttClientOptionsBuilder.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientOptionsBuilder.cs @@ -1,8 +1,8 @@ using System; using System.Linq; -using MQTTnet.Core.Serializer; +using MQTTnet.Serializer; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public class MqttClientOptionsBuilder { diff --git a/MQTTnet.Core/Client/MqttClientTcpOptions.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientTcpOptions.cs similarity index 88% rename from MQTTnet.Core/Client/MqttClientTcpOptions.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttClientTcpOptions.cs index e5cf8d6c..f44d424a 100644 --- a/MQTTnet.Core/Client/MqttClientTcpOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientTcpOptions.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public class MqttClientTcpOptions : IMqttClientChannelOptions { diff --git a/MQTTnet.Core/Client/MqttClientTcpOptionsExtensions.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientTcpOptionsExtensions.cs similarity index 93% rename from MQTTnet.Core/Client/MqttClientTcpOptionsExtensions.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttClientTcpOptionsExtensions.cs index cada6f8b..460069a7 100644 --- a/MQTTnet.Core/Client/MqttClientTcpOptionsExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientTcpOptionsExtensions.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public static class MqttClientTcpOptionsExtensions { diff --git a/MQTTnet.Core/Client/MqttClientTlsOptions.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientTlsOptions.cs similarity index 92% rename from MQTTnet.Core/Client/MqttClientTlsOptions.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttClientTlsOptions.cs index 33cd691f..6478b267 100644 --- a/MQTTnet.Core/Client/MqttClientTlsOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientTlsOptions.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public class MqttClientTlsOptions { diff --git a/MQTTnet.Core/Client/MqttClientWebSocketOptions.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientWebSocketOptions.cs similarity index 94% rename from MQTTnet.Core/Client/MqttClientWebSocketOptions.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttClientWebSocketOptions.cs index 25e4ae81..1819daab 100644 --- a/MQTTnet.Core/Client/MqttClientWebSocketOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientWebSocketOptions.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Net; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public class MqttClientWebSocketOptions : IMqttClientChannelOptions { diff --git a/MQTTnet.Core/Client/MqttPacketDispatcher.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs similarity index 96% rename from MQTTnet.Core/Client/MqttPacketDispatcher.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs index dd9c7140..48755898 100644 --- a/MQTTnet.Core/Client/MqttPacketDispatcher.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs @@ -1,12 +1,12 @@ using System; using System.Collections.Concurrent; using System.Threading.Tasks; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Exceptions; -using MQTTnet.Core.Internal; -using MQTTnet.Core.Packets; +using MQTTnet.Diagnostics; +using MQTTnet.Exceptions; +using MQTTnet.Internal; +using MQTTnet.Packets; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public class MqttPacketDispatcher { diff --git a/MQTTnet.Core/Client/MqttSubscribeResult.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttSubscribeResult.cs similarity index 79% rename from MQTTnet.Core/Client/MqttSubscribeResult.cs rename to Frameworks/MQTTnet.NetStandard/Client/MqttSubscribeResult.cs index 9dd49449..2b7c46da 100644 --- a/MQTTnet.Core/Client/MqttSubscribeResult.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttSubscribeResult.cs @@ -1,7 +1,6 @@ -using MQTTnet.Core.Packets; -using MQTTnet.Core.Protocol; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Client +namespace MQTTnet.Client { public class MqttSubscribeResult { diff --git a/MQTTnet.Core/Diagnostics/IMqttNetLogger.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/IMqttNetLogger.cs similarity index 94% rename from MQTTnet.Core/Diagnostics/IMqttNetLogger.cs rename to Frameworks/MQTTnet.NetStandard/Diagnostics/IMqttNetLogger.cs index 99f7b193..a65207bf 100644 --- a/MQTTnet.Core/Diagnostics/IMqttNetLogger.cs +++ b/Frameworks/MQTTnet.NetStandard/Diagnostics/IMqttNetLogger.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Diagnostics +namespace MQTTnet.Diagnostics { public interface IMqttNetLogger { diff --git a/MQTTnet.Core/Diagnostics/MqttNetGlobalLog.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetGlobalLogger.cs similarity index 86% rename from MQTTnet.Core/Diagnostics/MqttNetGlobalLog.cs rename to Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetGlobalLogger.cs index 64326826..a42857ea 100644 --- a/MQTTnet.Core/Diagnostics/MqttNetGlobalLog.cs +++ b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetGlobalLogger.cs @@ -1,8 +1,8 @@ using System; -namespace MQTTnet.Core.Diagnostics +namespace MQTTnet.Diagnostics { - public static class MqttNetGlobalLog + public static class MqttNetGlobalLogger { public static event EventHandler LogMessagePublished; diff --git a/MQTTnet.Core/Diagnostics/MqttNetLogLevel.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogLevel.cs similarity index 74% rename from MQTTnet.Core/Diagnostics/MqttNetLogLevel.cs rename to Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogLevel.cs index 32e5de17..cdc7a78a 100644 --- a/MQTTnet.Core/Diagnostics/MqttNetLogLevel.cs +++ b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogLevel.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Diagnostics +namespace MQTTnet.Diagnostics { public enum MqttNetLogLevel { diff --git a/MQTTnet.Core/Diagnostics/MqttNetLogMessage.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogMessage.cs similarity index 95% rename from MQTTnet.Core/Diagnostics/MqttNetLogMessage.cs rename to Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogMessage.cs index e1598eb2..d118fd09 100644 --- a/MQTTnet.Core/Diagnostics/MqttNetLogMessage.cs +++ b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogMessage.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Diagnostics +namespace MQTTnet.Diagnostics { public sealed class MqttNetLogMessage { diff --git a/MQTTnet.Core/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs similarity index 91% rename from MQTTnet.Core/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs rename to Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs index 46c54685..2407752b 100644 --- a/MQTTnet.Core/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs +++ b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Diagnostics +namespace MQTTnet.Diagnostics { public sealed class MqttNetLogMessagePublishedEventArgs : EventArgs { diff --git a/MQTTnet.Core/Diagnostics/MqttNetLogger.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogger.cs similarity index 93% rename from MQTTnet.Core/Diagnostics/MqttNetLogger.cs rename to Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogger.cs index a879af1b..7d9b2907 100644 --- a/MQTTnet.Core/Diagnostics/MqttNetLogger.cs +++ b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogger.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Diagnostics +namespace MQTTnet.Diagnostics { public class MqttNetLogger : IMqttNetLogger { @@ -46,7 +46,7 @@ namespace MQTTnet.Core.Diagnostics private void Publish(MqttNetLogLevel logLevel, Exception exception, string message, object[] parameters) { var hasLocalListeners = LogMessagePublished != null; - var hasGlobalListeners = MqttNetGlobalLog.HasListeners; + var hasGlobalListeners = MqttNetGlobalLogger.HasListeners; if (!hasLocalListeners && !hasGlobalListeners) { @@ -62,7 +62,7 @@ namespace MQTTnet.Core.Diagnostics if (hasGlobalListeners) { - MqttNetGlobalLog.Publish(traceMessage); + MqttNetGlobalLogger.Publish(traceMessage); } if (hasLocalListeners) diff --git a/Frameworks/MQTTnet.NetStandard/Diagnostics/TargetFrameworkInfoProvider.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/TargetFrameworkInfoProvider.cs index 22369d9c..52582769 100644 --- a/Frameworks/MQTTnet.NetStandard/Diagnostics/TargetFrameworkInfoProvider.cs +++ b/Frameworks/MQTTnet.NetStandard/Diagnostics/TargetFrameworkInfoProvider.cs @@ -1,4 +1,4 @@ -namespace MQTTnet +namespace MQTTnet.Diagnostics { public static class TargetFrameworkInfoProvider { diff --git a/MQTTnet.Core/Exceptions/MqttCommunicationException.cs b/Frameworks/MQTTnet.NetStandard/Exceptions/MqttCommunicationException.cs similarity index 92% rename from MQTTnet.Core/Exceptions/MqttCommunicationException.cs rename to Frameworks/MQTTnet.NetStandard/Exceptions/MqttCommunicationException.cs index e019f4ee..4631de83 100644 --- a/MQTTnet.Core/Exceptions/MqttCommunicationException.cs +++ b/Frameworks/MQTTnet.NetStandard/Exceptions/MqttCommunicationException.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Exceptions +namespace MQTTnet.Exceptions { public class MqttCommunicationException : Exception { diff --git a/MQTTnet.Core/Exceptions/MqttCommunicationTimedOutException.cs b/Frameworks/MQTTnet.NetStandard/Exceptions/MqttCommunicationTimedOutException.cs similarity index 73% rename from MQTTnet.Core/Exceptions/MqttCommunicationTimedOutException.cs rename to Frameworks/MQTTnet.NetStandard/Exceptions/MqttCommunicationTimedOutException.cs index e7240072..7d0adcd4 100644 --- a/MQTTnet.Core/Exceptions/MqttCommunicationTimedOutException.cs +++ b/Frameworks/MQTTnet.NetStandard/Exceptions/MqttCommunicationTimedOutException.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Exceptions +namespace MQTTnet.Exceptions { public sealed class MqttCommunicationTimedOutException : MqttCommunicationException { diff --git a/MQTTnet.Core/Exceptions/MqttProtocolViolationException.cs b/Frameworks/MQTTnet.NetStandard/Exceptions/MqttProtocolViolationException.cs similarity index 86% rename from MQTTnet.Core/Exceptions/MqttProtocolViolationException.cs rename to Frameworks/MQTTnet.NetStandard/Exceptions/MqttProtocolViolationException.cs index cef43f5c..8756b3f8 100644 --- a/MQTTnet.Core/Exceptions/MqttProtocolViolationException.cs +++ b/Frameworks/MQTTnet.NetStandard/Exceptions/MqttProtocolViolationException.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Exceptions +namespace MQTTnet.Exceptions { public sealed class MqttProtocolViolationException : Exception { diff --git a/MQTTnet.Core/IApplicationMessagePublisher.cs b/Frameworks/MQTTnet.NetStandard/IApplicationMessagePublisher.cs similarity index 90% rename from MQTTnet.Core/IApplicationMessagePublisher.cs rename to Frameworks/MQTTnet.NetStandard/IApplicationMessagePublisher.cs index 2f6715b8..e137669e 100644 --- a/MQTTnet.Core/IApplicationMessagePublisher.cs +++ b/Frameworks/MQTTnet.NetStandard/IApplicationMessagePublisher.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace MQTTnet.Core +namespace MQTTnet { public interface IApplicationMessagePublisher { diff --git a/MQTTnet.Core/IApplicationMessageReceiver.cs b/Frameworks/MQTTnet.NetStandard/IApplicationMessageReceiver.cs similarity index 78% rename from MQTTnet.Core/IApplicationMessageReceiver.cs rename to Frameworks/MQTTnet.NetStandard/IApplicationMessageReceiver.cs index 379ba69c..b315067c 100644 --- a/MQTTnet.Core/IApplicationMessageReceiver.cs +++ b/Frameworks/MQTTnet.NetStandard/IApplicationMessageReceiver.cs @@ -1,7 +1,6 @@ using System; -using MQTTnet.Core.Client; -namespace MQTTnet.Core +namespace MQTTnet { public interface IApplicationMessageReceiver { diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttClientAdapterFactory.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttClientAdapterFactory.cs index 9884c86f..f8f0e996 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttClientAdapterFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttClientAdapterFactory.cs @@ -1,8 +1,8 @@ using System; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Client; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Serializer; +using MQTTnet.Adapter; +using MQTTnet.Client; +using MQTTnet.Diagnostics; +using MQTTnet.Serializer; namespace MQTTnet.Implementations { diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs index 1b8a43cd..3966edce 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs @@ -1,11 +1,11 @@ #if WINDOWS_UWP using System; using System.Threading.Tasks; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Server; using Windows.Networking.Sockets; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Serializer; +using MQTTnet.Adapter; +using MQTTnet.Diagnostics; +using MQTTnet.Serializer; +using MQTTnet.Server; namespace MQTTnet.Implementations { diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs index 3b8515c5..dadca442 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs @@ -7,10 +7,10 @@ using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Server; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Serializer; +using MQTTnet.Adapter; +using MQTTnet.Diagnostics; +using MQTTnet.Serializer; +using MQTTnet.Server; namespace MQTTnet.Implementations { diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs index 964bfbfe..fa96a8f8 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs @@ -8,8 +8,8 @@ using System.Threading.Tasks; using Windows.Networking; using Windows.Networking.Sockets; using Windows.Security.Cryptography.Certificates; -using MQTTnet.Core.Channel; -using MQTTnet.Core.Client; +using MQTTnet.Channel; +using MQTTnet.Client; namespace MQTTnet.Implementations { diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs index ce9dcf6c..7e23fdbe 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs @@ -5,10 +5,10 @@ using System.Net.Sockets; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; -using MQTTnet.Core.Channel; -using MQTTnet.Core.Client; using System.IO; using System.Linq; +using MQTTnet.Channel; +using MQTTnet.Client; namespace MQTTnet.Implementations { diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs index d8e24a47..77d99a85 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs @@ -1,11 +1,11 @@ -using MQTTnet.Core.Channel; -using MQTTnet.Core.Client; -using System; +using System; using System.IO; using System.Net.WebSockets; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; +using MQTTnet.Channel; +using MQTTnet.Client; namespace MQTTnet.Implementations { diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs b/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs index 4ff11dad..1aa02a64 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Exceptions; +using MQTTnet.Exceptions; namespace MQTTnet.Implementations { diff --git a/MQTTnet.Core/Internal/MqttApplicationMessageExtensions.cs b/Frameworks/MQTTnet.NetStandard/Internal/MqttApplicationMessageExtensions.cs similarity index 94% rename from MQTTnet.Core/Internal/MqttApplicationMessageExtensions.cs rename to Frameworks/MQTTnet.NetStandard/Internal/MqttApplicationMessageExtensions.cs index 7ca7d005..b1d1a389 100644 --- a/MQTTnet.Core/Internal/MqttApplicationMessageExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/Internal/MqttApplicationMessageExtensions.cs @@ -1,6 +1,6 @@ -using MQTTnet.Core.Packets; +using MQTTnet.Packets; -namespace MQTTnet.Core.Internal +namespace MQTTnet.Internal { internal static class MqttApplicationMessageExtensions { diff --git a/MQTTnet.Core/Internal/TaskExtensions.cs b/Frameworks/MQTTnet.NetStandard/Internal/TaskExtensions.cs similarity index 97% rename from MQTTnet.Core/Internal/TaskExtensions.cs rename to Frameworks/MQTTnet.NetStandard/Internal/TaskExtensions.cs index 45b3510b..6acb71ef 100644 --- a/MQTTnet.Core/Internal/TaskExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/Internal/TaskExtensions.cs @@ -1,9 +1,9 @@ using System; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Exceptions; +using MQTTnet.Exceptions; -namespace MQTTnet.Core.Internal +namespace MQTTnet.Internal { public static class TaskExtensions { diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj index 9b6211d8..752ba948 100644 --- a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -14,6 +14,8 @@ + true + codeSigningKey.pfx @@ -33,10 +35,6 @@ - - - - diff --git a/MQTTnet.Core/ManagedClient/IManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs similarity index 90% rename from MQTTnet.Core/ManagedClient/IManagedMqttClient.cs rename to Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs index 8d2ac8cc..41c0ce3b 100644 --- a/MQTTnet.Core/ManagedClient/IManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using MQTTnet.Core.Client; +using MQTTnet.Client; -namespace MQTTnet.Core.ManagedClient +namespace MQTTnet.ManagedClient { public interface IManagedMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher { diff --git a/MQTTnet.Core/ManagedClient/IManagedMqttClientOptions.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClientOptions.cs similarity index 77% rename from MQTTnet.Core/ManagedClient/IManagedMqttClientOptions.cs rename to Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClientOptions.cs index 298de9a1..fbb87b79 100644 --- a/MQTTnet.Core/ManagedClient/IManagedMqttClientOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClientOptions.cs @@ -1,7 +1,7 @@ using System; -using MQTTnet.Core.Client; +using MQTTnet.Client; -namespace MQTTnet.Core.ManagedClient +namespace MQTTnet.ManagedClient { public interface IManagedMqttClientOptions { diff --git a/MQTTnet.Core/ManagedClient/IManagedMqttClientStorage.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClientStorage.cs similarity index 88% rename from MQTTnet.Core/ManagedClient/IManagedMqttClientStorage.cs rename to Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClientStorage.cs index 39ea89cc..28bf5703 100644 --- a/MQTTnet.Core/ManagedClient/IManagedMqttClientStorage.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClientStorage.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace MQTTnet.Core.ManagedClient +namespace MQTTnet.ManagedClient { public interface IManagedMqttClientStorage { diff --git a/MQTTnet.Core/ManagedClient/ManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs similarity index 98% rename from MQTTnet.Core/ManagedClient/ManagedMqttClient.cs rename to Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs index c2e40777..90db1dc5 100644 --- a/MQTTnet.Core/ManagedClient/ManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs @@ -4,12 +4,12 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Client; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Exceptions; -using MQTTnet.Core.Protocol; +using MQTTnet.Client; +using MQTTnet.Diagnostics; +using MQTTnet.Exceptions; +using MQTTnet.Protocol; -namespace MQTTnet.Core.ManagedClient +namespace MQTTnet.ManagedClient { public class ManagedMqttClient : IManagedMqttClient { diff --git a/MQTTnet.Core/ManagedClient/ManagedMqttClientExtensions.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientExtensions.cs similarity index 95% rename from MQTTnet.Core/ManagedClient/ManagedMqttClientExtensions.cs rename to Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientExtensions.cs index a9984c4a..e1346679 100644 --- a/MQTTnet.Core/ManagedClient/ManagedMqttClientExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientExtensions.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; -namespace MQTTnet.Core.ManagedClient +namespace MQTTnet.ManagedClient { public static class ManagedMqttClientExtensions { diff --git a/MQTTnet.Core/ManagedClient/ManagedMqttClientOptions.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptions.cs similarity index 83% rename from MQTTnet.Core/ManagedClient/ManagedMqttClientOptions.cs rename to Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptions.cs index 2e24fd0a..813aee8a 100644 --- a/MQTTnet.Core/ManagedClient/ManagedMqttClientOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptions.cs @@ -1,7 +1,7 @@ using System; -using MQTTnet.Core.Client; +using MQTTnet.Client; -namespace MQTTnet.Core.ManagedClient +namespace MQTTnet.ManagedClient { public class ManagedMqttClientOptions : IManagedMqttClientOptions { diff --git a/MQTTnet.Core/ManagedClient/ManagedMqttClientOptionsBuilder.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptionsBuilder.cs similarity index 95% rename from MQTTnet.Core/ManagedClient/ManagedMqttClientOptionsBuilder.cs rename to Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptionsBuilder.cs index 3972dcd2..7c753064 100644 --- a/MQTTnet.Core/ManagedClient/ManagedMqttClientOptionsBuilder.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptionsBuilder.cs @@ -1,7 +1,7 @@ using System; -using MQTTnet.Core.Client; +using MQTTnet.Client; -namespace MQTTnet.Core.ManagedClient +namespace MQTTnet.ManagedClient { public class ManagedMqttClientOptionsBuilder { diff --git a/MQTTnet.Core/ManagedClient/ManagedMqttClientStorageManager.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientStorageManager.cs similarity index 98% rename from MQTTnet.Core/ManagedClient/ManagedMqttClientStorageManager.cs rename to Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientStorageManager.cs index 0810f36e..d55f1376 100644 --- a/MQTTnet.Core/ManagedClient/ManagedMqttClientStorageManager.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientStorageManager.cs @@ -2,7 +2,7 @@ using System.Threading; using System.Threading.Tasks; -namespace MQTTnet.Core.ManagedClient +namespace MQTTnet.ManagedClient { public class ManagedMqttClientStorageManager { diff --git a/MQTTnet.Core/ManagedClient/ReconnectionResult.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ReconnectionResult.cs similarity index 74% rename from MQTTnet.Core/ManagedClient/ReconnectionResult.cs rename to Frameworks/MQTTnet.NetStandard/ManagedClient/ReconnectionResult.cs index fae07706..42566e3e 100644 --- a/MQTTnet.Core/ManagedClient/ReconnectionResult.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ReconnectionResult.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.ManagedClient +namespace MQTTnet.ManagedClient { public enum ReconnectionResult { diff --git a/MQTTnet.Core/MqttApplicationMessage.cs b/Frameworks/MQTTnet.NetStandard/MqttApplicationMessage.cs similarity index 94% rename from MQTTnet.Core/MqttApplicationMessage.cs rename to Frameworks/MQTTnet.NetStandard/MqttApplicationMessage.cs index b07ee18f..387acb21 100644 --- a/MQTTnet.Core/MqttApplicationMessage.cs +++ b/Frameworks/MQTTnet.NetStandard/MqttApplicationMessage.cs @@ -1,7 +1,7 @@ using System; -using MQTTnet.Core.Protocol; +using MQTTnet.Protocol; -namespace MQTTnet.Core +namespace MQTTnet { public sealed class MqttApplicationMessage { diff --git a/MQTTnet.Core/MqttApplicationMessageBuilder.cs b/Frameworks/MQTTnet.NetStandard/MqttApplicationMessageBuilder.cs similarity index 97% rename from MQTTnet.Core/MqttApplicationMessageBuilder.cs rename to Frameworks/MQTTnet.NetStandard/MqttApplicationMessageBuilder.cs index c2e04318..ce949b85 100644 --- a/MQTTnet.Core/MqttApplicationMessageBuilder.cs +++ b/Frameworks/MQTTnet.NetStandard/MqttApplicationMessageBuilder.cs @@ -2,10 +2,10 @@ using System.IO; using System.Linq; using System.Text; -using MQTTnet.Core.Exceptions; -using MQTTnet.Core.Protocol; +using MQTTnet.Exceptions; +using MQTTnet.Protocol; -namespace MQTTnet.Core +namespace MQTTnet { public class MqttApplicationMessageBuilder { diff --git a/MQTTnet.Core/MqttApplicationMessageReceivedEventArgs.cs b/Frameworks/MQTTnet.NetStandard/MqttApplicationMessageReceivedEventArgs.cs similarity index 95% rename from MQTTnet.Core/MqttApplicationMessageReceivedEventArgs.cs rename to Frameworks/MQTTnet.NetStandard/MqttApplicationMessageReceivedEventArgs.cs index 3de0db54..a16a81d1 100644 --- a/MQTTnet.Core/MqttApplicationMessageReceivedEventArgs.cs +++ b/Frameworks/MQTTnet.NetStandard/MqttApplicationMessageReceivedEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core +namespace MQTTnet { public sealed class MqttApplicationMessageReceivedEventArgs : EventArgs { diff --git a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs index 99e57af6..5b0174b1 100644 --- a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Client; +using MQTTnet.Adapter; +using MQTTnet.Client; +using MQTTnet.Diagnostics; using MQTTnet.Implementations; -using MQTTnet.Core.ManagedClient; -using MQTTnet.Core.Server; -using MQTTnet.Core.Diagnostics; +using MQTTnet.ManagedClient; +using MQTTnet.Server; namespace MQTTnet { diff --git a/MQTTnet.Core/Packets/IMqttPacketWithIdentifier.cs b/Frameworks/MQTTnet.NetStandard/Packets/IMqttPacketWithIdentifier.cs similarity index 76% rename from MQTTnet.Core/Packets/IMqttPacketWithIdentifier.cs rename to Frameworks/MQTTnet.NetStandard/Packets/IMqttPacketWithIdentifier.cs index 420955cd..5f7f8e97 100644 --- a/MQTTnet.Core/Packets/IMqttPacketWithIdentifier.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/IMqttPacketWithIdentifier.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public interface IMqttPacketWithIdentifier { diff --git a/MQTTnet.Core/Packets/MqttBasePacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttBasePacket.cs similarity index 62% rename from MQTTnet.Core/Packets/MqttBasePacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttBasePacket.cs index 41901e52..d9640568 100644 --- a/MQTTnet.Core/Packets/MqttBasePacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttBasePacket.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public abstract class MqttBasePacket { diff --git a/MQTTnet.Core/Packets/MqttBasePublishPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttBasePublishPacket.cs similarity index 81% rename from MQTTnet.Core/Packets/MqttBasePublishPacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttBasePublishPacket.cs index 67d55b90..6218c154 100644 --- a/MQTTnet.Core/Packets/MqttBasePublishPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttBasePublishPacket.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public class MqttBasePublishPacket : MqttBasePacket, IMqttPacketWithIdentifier { diff --git a/MQTTnet.Core/Packets/MqttConnAckPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttConnAckPacket.cs similarity index 85% rename from MQTTnet.Core/Packets/MqttConnAckPacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttConnAckPacket.cs index 0410e669..9cf0adfe 100644 --- a/MQTTnet.Core/Packets/MqttConnAckPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttConnAckPacket.cs @@ -1,6 +1,6 @@ -using MQTTnet.Core.Protocol; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttConnAckPacket : MqttBasePacket { diff --git a/MQTTnet.Core/Packets/MqttConnectPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttConnectPacket.cs similarity index 91% rename from MQTTnet.Core/Packets/MqttConnectPacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttConnectPacket.cs index 48817120..b1943ced 100644 --- a/MQTTnet.Core/Packets/MqttConnectPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttConnectPacket.cs @@ -1,6 +1,6 @@ -using MQTTnet.Core.Serializer; +using MQTTnet.Serializer; -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttConnectPacket : MqttBasePacket { diff --git a/MQTTnet.Core/Packets/MqttDisconnectPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttDisconnectPacket.cs similarity index 83% rename from MQTTnet.Core/Packets/MqttDisconnectPacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttDisconnectPacket.cs index 4db7f795..46c3270d 100644 --- a/MQTTnet.Core/Packets/MqttDisconnectPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttDisconnectPacket.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttDisconnectPacket : MqttBasePacket { diff --git a/MQTTnet.Core/Packets/MqttPacketExtensions.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttPacketExtensions.cs similarity index 96% rename from MQTTnet.Core/Packets/MqttPacketExtensions.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttPacketExtensions.cs index 6a7e0cea..a3df53c8 100644 --- a/MQTTnet.Core/Packets/MqttPacketExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttPacketExtensions.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public static class MqttPacketExtensions { diff --git a/MQTTnet.Core/Packets/MqttPacketHeader.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttPacketHeader.cs similarity index 77% rename from MQTTnet.Core/Packets/MqttPacketHeader.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttPacketHeader.cs index 41646df4..01c26ecd 100644 --- a/MQTTnet.Core/Packets/MqttPacketHeader.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttPacketHeader.cs @@ -1,6 +1,6 @@ -using MQTTnet.Core.Protocol; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public class MqttPacketHeader { diff --git a/MQTTnet.Core/Packets/MqttPingReqPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttPingReqPacket.cs similarity index 83% rename from MQTTnet.Core/Packets/MqttPingReqPacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttPingReqPacket.cs index 9836b5aa..fee9926c 100644 --- a/MQTTnet.Core/Packets/MqttPingReqPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttPingReqPacket.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttPingReqPacket : MqttBasePacket { diff --git a/MQTTnet.Core/Packets/MqttPingRespPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttPingRespPacket.cs similarity index 83% rename from MQTTnet.Core/Packets/MqttPingRespPacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttPingRespPacket.cs index eff12b83..c5f82a3b 100644 --- a/MQTTnet.Core/Packets/MqttPingRespPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttPingRespPacket.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttPingRespPacket : MqttBasePacket { diff --git a/MQTTnet.Core/Packets/MqttPubAckPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttPubAckPacket.cs similarity index 83% rename from MQTTnet.Core/Packets/MqttPubAckPacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttPubAckPacket.cs index 9e07cd32..e7fe57b7 100644 --- a/MQTTnet.Core/Packets/MqttPubAckPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttPubAckPacket.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttPubAckPacket : MqttBasePublishPacket { diff --git a/MQTTnet.Core/Packets/MqttPubCompPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttPubCompPacket.cs similarity index 83% rename from MQTTnet.Core/Packets/MqttPubCompPacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttPubCompPacket.cs index 9b819fd0..98dace70 100644 --- a/MQTTnet.Core/Packets/MqttPubCompPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttPubCompPacket.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttPubCompPacket : MqttBasePublishPacket { diff --git a/MQTTnet.Core/Packets/MqttPubRecPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttPubRecPacket.cs similarity index 83% rename from MQTTnet.Core/Packets/MqttPubRecPacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttPubRecPacket.cs index 3b876559..86cd4b45 100644 --- a/MQTTnet.Core/Packets/MqttPubRecPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttPubRecPacket.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttPubRecPacket : MqttBasePublishPacket { diff --git a/MQTTnet.Core/Packets/MqttPubRelPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttPubRelPacket.cs similarity index 83% rename from MQTTnet.Core/Packets/MqttPubRelPacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttPubRelPacket.cs index 9d926894..ed1d933b 100644 --- a/MQTTnet.Core/Packets/MqttPubRelPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttPubRelPacket.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttPubRelPacket : MqttBasePublishPacket { diff --git a/MQTTnet.Core/Packets/MqttPublishPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttPublishPacket.cs similarity index 91% rename from MQTTnet.Core/Packets/MqttPublishPacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttPublishPacket.cs index 573ff691..52fcceed 100644 --- a/MQTTnet.Core/Packets/MqttPublishPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttPublishPacket.cs @@ -1,6 +1,6 @@ -using MQTTnet.Core.Protocol; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttPublishPacket : MqttBasePublishPacket { diff --git a/MQTTnet.Core/Packets/MqttSubAckPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttSubAckPacket.cs similarity index 91% rename from MQTTnet.Core/Packets/MqttSubAckPacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttSubAckPacket.cs index 05431a3f..c4c1a886 100644 --- a/MQTTnet.Core/Packets/MqttSubAckPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttSubAckPacket.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Linq; -using MQTTnet.Core.Protocol; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttSubAckPacket : MqttBasePacket, IMqttPacketWithIdentifier { diff --git a/MQTTnet.Core/Packets/MqttSubscribePacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttSubscribePacket.cs similarity index 95% rename from MQTTnet.Core/Packets/MqttSubscribePacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttSubscribePacket.cs index c911efcc..25536e3a 100644 --- a/MQTTnet.Core/Packets/MqttSubscribePacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttSubscribePacket.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttSubscribePacket : MqttBasePacket, IMqttPacketWithIdentifier { diff --git a/MQTTnet.Core/Packets/MqttUnsubAckPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubAckPacket.cs similarity index 89% rename from MQTTnet.Core/Packets/MqttUnsubAckPacket.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubAckPacket.cs index 3554fa95..4797d0a4 100644 --- a/MQTTnet.Core/Packets/MqttUnsubAckPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubAckPacket.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttUnsubAckPacket : MqttBasePacket, IMqttPacketWithIdentifier { diff --git a/MQTTnet.Core/Packets/MqttUnsubscribe.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubscribe.cs similarity index 94% rename from MQTTnet.Core/Packets/MqttUnsubscribe.cs rename to Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubscribe.cs index 1e06e50e..2c47cbbd 100644 --- a/MQTTnet.Core/Packets/MqttUnsubscribe.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubscribe.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace MQTTnet.Core.Packets +namespace MQTTnet.Packets { public sealed class MqttUnsubscribePacket : MqttBasePacket, IMqttPacketWithIdentifier { diff --git a/MQTTnet.Core/Protocol/MqttConnectReturnCode.cs b/Frameworks/MQTTnet.NetStandard/Protocol/MqttConnectReturnCode.cs similarity index 91% rename from MQTTnet.Core/Protocol/MqttConnectReturnCode.cs rename to Frameworks/MQTTnet.NetStandard/Protocol/MqttConnectReturnCode.cs index 604cd482..bffc4dcf 100644 --- a/MQTTnet.Core/Protocol/MqttConnectReturnCode.cs +++ b/Frameworks/MQTTnet.NetStandard/Protocol/MqttConnectReturnCode.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Protocol +namespace MQTTnet.Protocol { public enum MqttConnectReturnCode { diff --git a/MQTTnet.Core/Protocol/MqttControlPacketType.cs b/Frameworks/MQTTnet.NetStandard/Protocol/MqttControlPacketType.cs similarity index 91% rename from MQTTnet.Core/Protocol/MqttControlPacketType.cs rename to Frameworks/MQTTnet.NetStandard/Protocol/MqttControlPacketType.cs index aa46b9df..adb58b66 100644 --- a/MQTTnet.Core/Protocol/MqttControlPacketType.cs +++ b/Frameworks/MQTTnet.NetStandard/Protocol/MqttControlPacketType.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Protocol +namespace MQTTnet.Protocol { public enum MqttControlPacketType { diff --git a/MQTTnet.Core/Protocol/MqttQualityOfServiceLevel.cs b/Frameworks/MQTTnet.NetStandard/Protocol/MqttQualityOfServiceLevel.cs similarity index 80% rename from MQTTnet.Core/Protocol/MqttQualityOfServiceLevel.cs rename to Frameworks/MQTTnet.NetStandard/Protocol/MqttQualityOfServiceLevel.cs index c19496a8..579f72ef 100644 --- a/MQTTnet.Core/Protocol/MqttQualityOfServiceLevel.cs +++ b/Frameworks/MQTTnet.NetStandard/Protocol/MqttQualityOfServiceLevel.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Protocol +namespace MQTTnet.Protocol { public enum MqttQualityOfServiceLevel { diff --git a/MQTTnet.Core/Protocol/MqttSubscribeReturnCode.cs b/Frameworks/MQTTnet.NetStandard/Protocol/MqttSubscribeReturnCode.cs similarity index 84% rename from MQTTnet.Core/Protocol/MqttSubscribeReturnCode.cs rename to Frameworks/MQTTnet.NetStandard/Protocol/MqttSubscribeReturnCode.cs index a561423f..b256962b 100644 --- a/MQTTnet.Core/Protocol/MqttSubscribeReturnCode.cs +++ b/Frameworks/MQTTnet.NetStandard/Protocol/MqttSubscribeReturnCode.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Protocol +namespace MQTTnet.Protocol { public enum MqttSubscribeReturnCode { diff --git a/MQTTnet.Core/Serializer/ByteReader.cs b/Frameworks/MQTTnet.NetStandard/Serializer/ByteReader.cs similarity index 96% rename from MQTTnet.Core/Serializer/ByteReader.cs rename to Frameworks/MQTTnet.NetStandard/Serializer/ByteReader.cs index ce7f709d..ec1e3ea2 100644 --- a/MQTTnet.Core/Serializer/ByteReader.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/ByteReader.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Serializer +namespace MQTTnet.Serializer { public sealed class ByteReader { diff --git a/MQTTnet.Core/Serializer/ByteWriter.cs b/Frameworks/MQTTnet.NetStandard/Serializer/ByteWriter.cs similarity index 95% rename from MQTTnet.Core/Serializer/ByteWriter.cs rename to Frameworks/MQTTnet.NetStandard/Serializer/ByteWriter.cs index d6abec90..af961e1a 100644 --- a/MQTTnet.Core/Serializer/ByteWriter.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/ByteWriter.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Serializer +namespace MQTTnet.Serializer { public sealed class ByteWriter { diff --git a/MQTTnet.Core/Serializer/IMqttPacketSerializer.cs b/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs similarity index 72% rename from MQTTnet.Core/Serializer/IMqttPacketSerializer.cs rename to Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs index 5834c539..6b46b528 100644 --- a/MQTTnet.Core/Serializer/IMqttPacketSerializer.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs @@ -1,7 +1,7 @@ -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Packets; +using MQTTnet.Adapter; +using MQTTnet.Packets; -namespace MQTTnet.Core.Serializer +namespace MQTTnet.Serializer { public interface IMqttPacketSerializer { diff --git a/MQTTnet.Core/Serializer/MqttPacketReader.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs similarity index 95% rename from MQTTnet.Core/Serializer/MqttPacketReader.cs rename to Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs index 9fcae9e5..caf28813 100644 --- a/MQTTnet.Core/Serializer/MqttPacketReader.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs @@ -4,12 +4,12 @@ using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Exceptions; -using MQTTnet.Core.Protocol; -using MQTTnet.Core.Packets; +using MQTTnet.Adapter; +using MQTTnet.Exceptions; +using MQTTnet.Packets; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Serializer +namespace MQTTnet.Serializer { public sealed class MqttPacketReader : BinaryReader { diff --git a/MQTTnet.Core/Serializer/MqttPacketSerializer.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs similarity index 99% rename from MQTTnet.Core/Serializer/MqttPacketSerializer.cs rename to Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs index 6c2fc56a..ce45b3e2 100644 --- a/MQTTnet.Core/Serializer/MqttPacketSerializer.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs @@ -3,12 +3,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Exceptions; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Protocol; +using MQTTnet.Adapter; +using MQTTnet.Exceptions; +using MQTTnet.Packets; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Serializer +namespace MQTTnet.Serializer { public sealed class MqttPacketSerializer : IMqttPacketSerializer { diff --git a/MQTTnet.Core/Serializer/MqttPacketWriter.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketWriter.cs similarity index 96% rename from MQTTnet.Core/Serializer/MqttPacketWriter.cs rename to Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketWriter.cs index 4c86f961..cdf7915e 100644 --- a/MQTTnet.Core/Serializer/MqttPacketWriter.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketWriter.cs @@ -1,10 +1,10 @@ using System; +using System.Collections.Generic; using System.IO; using System.Text; -using MQTTnet.Core.Protocol; -using System.Collections.Generic; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Serializer +namespace MQTTnet.Serializer { public sealed class MqttPacketWriter : BinaryWriter { diff --git a/MQTTnet.Core/Serializer/MqttProtocolVersion.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttProtocolVersion.cs similarity index 68% rename from MQTTnet.Core/Serializer/MqttProtocolVersion.cs rename to Frameworks/MQTTnet.NetStandard/Serializer/MqttProtocolVersion.cs index 6b8814a7..15e698d3 100644 --- a/MQTTnet.Core/Serializer/MqttProtocolVersion.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttProtocolVersion.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Serializer +namespace MQTTnet.Serializer { public enum MqttProtocolVersion { diff --git a/MQTTnet.Core/Server/CheckSubscriptionsResult.cs b/Frameworks/MQTTnet.NetStandard/Server/CheckSubscriptionsResult.cs similarity index 74% rename from MQTTnet.Core/Server/CheckSubscriptionsResult.cs rename to Frameworks/MQTTnet.NetStandard/Server/CheckSubscriptionsResult.cs index 625457ff..9e2d1f0d 100644 --- a/MQTTnet.Core/Server/CheckSubscriptionsResult.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/CheckSubscriptionsResult.cs @@ -1,6 +1,6 @@ -using MQTTnet.Core.Protocol; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public class CheckSubscriptionsResult { diff --git a/MQTTnet.Core/Server/ConnectedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs similarity index 72% rename from MQTTnet.Core/Server/ConnectedMqttClient.cs rename to Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs index d3633511..ea1c7465 100644 --- a/MQTTnet.Core/Server/ConnectedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs @@ -1,6 +1,6 @@ -using MQTTnet.Core.Serializer; +using MQTTnet.Serializer; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public class ConnectedMqttClient { diff --git a/MQTTnet.Core/Server/GetOrCreateClientSessionResult.cs b/Frameworks/MQTTnet.NetStandard/Server/GetOrCreateClientSessionResult.cs similarity index 84% rename from MQTTnet.Core/Server/GetOrCreateClientSessionResult.cs rename to Frameworks/MQTTnet.NetStandard/Server/GetOrCreateClientSessionResult.cs index 8f802720..8f5f085e 100644 --- a/MQTTnet.Core/Server/GetOrCreateClientSessionResult.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/GetOrCreateClientSessionResult.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public sealed class GetOrCreateClientSessionResult { diff --git a/MQTTnet.Core/Server/IMqttServer.cs b/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs similarity index 94% rename from MQTTnet.Core/Server/IMqttServer.cs rename to Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs index 936e897e..3d0ccda6 100644 --- a/MQTTnet.Core/Server/IMqttServer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public interface IMqttServer : IApplicationMessageReceiver, IApplicationMessagePublisher { diff --git a/MQTTnet.Core/Server/IMqttServerFactory.cs b/Frameworks/MQTTnet.NetStandard/Server/IMqttServerFactory.cs similarity index 72% rename from MQTTnet.Core/Server/IMqttServerFactory.cs rename to Frameworks/MQTTnet.NetStandard/Server/IMqttServerFactory.cs index 378dfb01..6e399cae 100644 --- a/MQTTnet.Core/Server/IMqttServerFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/IMqttServerFactory.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Diagnostics; +using MQTTnet.Adapter; +using MQTTnet.Diagnostics; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public interface IMqttServerFactory { diff --git a/MQTTnet.Core/Server/IMqttServerStorage.cs b/Frameworks/MQTTnet.NetStandard/Server/IMqttServerStorage.cs similarity index 90% rename from MQTTnet.Core/Server/IMqttServerStorage.cs rename to Frameworks/MQTTnet.NetStandard/Server/IMqttServerStorage.cs index 3cb518c3..da6e6e28 100644 --- a/MQTTnet.Core/Server/IMqttServerStorage.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/IMqttServerStorage.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public interface IMqttServerStorage { diff --git a/MQTTnet.Core/Server/MqttApplicationMessageInterceptorContext.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttApplicationMessageInterceptorContext.cs similarity index 81% rename from MQTTnet.Core/Server/MqttApplicationMessageInterceptorContext.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttApplicationMessageInterceptorContext.cs index 218a02dc..e5f8c3f7 100644 --- a/MQTTnet.Core/Server/MqttApplicationMessageInterceptorContext.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttApplicationMessageInterceptorContext.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public class MqttApplicationMessageInterceptorContext { diff --git a/MQTTnet.Core/Server/MqttClientConnectedEventArgs.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientConnectedEventArgs.cs similarity index 91% rename from MQTTnet.Core/Server/MqttClientConnectedEventArgs.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttClientConnectedEventArgs.cs index 282e0f8d..1ca3f406 100644 --- a/MQTTnet.Core/Server/MqttClientConnectedEventArgs.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientConnectedEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public class MqttClientConnectedEventArgs : EventArgs { diff --git a/MQTTnet.Core/Server/MqttClientDisconnectedEventArgs.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientDisconnectedEventArgs.cs similarity index 91% rename from MQTTnet.Core/Server/MqttClientDisconnectedEventArgs.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttClientDisconnectedEventArgs.cs index b1e3d15b..78372bc9 100644 --- a/MQTTnet.Core/Server/MqttClientDisconnectedEventArgs.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientDisconnectedEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public class MqttClientDisconnectedEventArgs : EventArgs { diff --git a/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs similarity index 95% rename from MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs index bea60397..9e1a2cda 100644 --- a/MQTTnet.Core/Server/MqttClientPendingMessagesQueue.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs @@ -2,13 +2,13 @@ using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Exceptions; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Protocol; +using MQTTnet.Adapter; +using MQTTnet.Diagnostics; +using MQTTnet.Exceptions; +using MQTTnet.Packets; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public sealed class MqttClientPendingMessagesQueue { diff --git a/MQTTnet.Core/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs similarity index 97% rename from MQTTnet.Core/Server/MqttClientSession.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index 3646c405..cc889644 100644 --- a/MQTTnet.Core/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -2,15 +2,15 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Exceptions; -using MQTTnet.Core.Internal; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Protocol; -using MQTTnet.Core.Serializer; +using MQTTnet.Adapter; +using MQTTnet.Diagnostics; +using MQTTnet.Exceptions; +using MQTTnet.Internal; +using MQTTnet.Packets; +using MQTTnet.Protocol; +using MQTTnet.Serializer; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public sealed class MqttClientSession { diff --git a/MQTTnet.Core/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs similarity index 97% rename from MQTTnet.Core/Server/MqttClientSessionsManager.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index 63235220..61e19f76 100644 --- a/MQTTnet.Core/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -3,15 +3,15 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Exceptions; -using MQTTnet.Core.Internal; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Protocol; -using MQTTnet.Core.Serializer; +using MQTTnet.Adapter; +using MQTTnet.Diagnostics; +using MQTTnet.Exceptions; +using MQTTnet.Internal; +using MQTTnet.Packets; +using MQTTnet.Protocol; +using MQTTnet.Serializer; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public sealed class MqttClientSessionsManager { diff --git a/MQTTnet.Core/Server/MqttClientSubscribeResult.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscribeResult.cs similarity index 73% rename from MQTTnet.Core/Server/MqttClientSubscribeResult.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscribeResult.cs index 17bfe9a5..fe75c3b2 100644 --- a/MQTTnet.Core/Server/MqttClientSubscribeResult.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscribeResult.cs @@ -1,6 +1,6 @@ -using MQTTnet.Core.Packets; +using MQTTnet.Packets; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public class MqttClientSubscribeResult { diff --git a/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs similarity index 97% rename from MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs index 8d88ddcf..86156303 100644 --- a/MQTTnet.Core/Server/MqttClientSubscriptionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Protocol; +using MQTTnet.Packets; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public sealed class MqttClientSubscriptionsManager { diff --git a/MQTTnet.Core/Server/MqttConnectionValidatorContext.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttConnectionValidatorContext.cs similarity index 91% rename from MQTTnet.Core/Server/MqttConnectionValidatorContext.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttConnectionValidatorContext.cs index 83a1eabc..a24d7955 100644 --- a/MQTTnet.Core/Server/MqttConnectionValidatorContext.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttConnectionValidatorContext.cs @@ -1,6 +1,6 @@ -using MQTTnet.Core.Protocol; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public class MqttConnectionValidatorContext { diff --git a/MQTTnet.Core/Server/MqttRetainedMessagesManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs similarity index 98% rename from MQTTnet.Core/Server/MqttRetainedMessagesManager.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs index cf667236..c8377694 100644 --- a/MQTTnet.Core/Server/MqttRetainedMessagesManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Diagnostics; +using MQTTnet.Diagnostics; +using MQTTnet.Packets; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public sealed class MqttRetainedMessagesManager { diff --git a/MQTTnet.Core/Server/MqttServer.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs similarity index 98% rename from MQTTnet.Core/Server/MqttServer.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs index f9349284..25dc2d36 100644 --- a/MQTTnet.Core/Server/MqttServer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs @@ -1,12 +1,12 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Adapter; -using System.Linq; -using MQTTnet.Core.Diagnostics; +using MQTTnet.Adapter; +using MQTTnet.Diagnostics; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public class MqttServer : IMqttServer { diff --git a/MQTTnet.Core/Server/MqttServerDefaultEndpointOptions.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServerDefaultEndpointOptions.cs similarity index 83% rename from MQTTnet.Core/Server/MqttServerDefaultEndpointOptions.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttServerDefaultEndpointOptions.cs index 04c4d732..6dc21b32 100644 --- a/MQTTnet.Core/Server/MqttServerDefaultEndpointOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServerDefaultEndpointOptions.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public sealed class MqttServerDefaultEndpointOptions { diff --git a/MQTTnet.Core/Server/MqttServerOptions.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptions.cs similarity index 90% rename from MQTTnet.Core/Server/MqttServerOptions.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttServerOptions.cs index 8988b111..d04725ec 100644 --- a/MQTTnet.Core/Server/MqttServerOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptions.cs @@ -1,8 +1,8 @@ using System; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Protocol; +using MQTTnet.Packets; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public class MqttServerOptions { diff --git a/MQTTnet.Core/Server/MqttServerOptionsBuilder.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsBuilder.cs similarity index 96% rename from MQTTnet.Core/Server/MqttServerOptionsBuilder.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsBuilder.cs index 692f7c19..f6cb0bba 100644 --- a/MQTTnet.Core/Server/MqttServerOptionsBuilder.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsBuilder.cs @@ -1,8 +1,8 @@ using System; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Protocol; +using MQTTnet.Packets; +using MQTTnet.Protocol; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public class MqttServerOptionsBuilder { diff --git a/MQTTnet.Core/Server/MqttServerOptionsExtensions.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsExtensions.cs similarity index 96% rename from MQTTnet.Core/Server/MqttServerOptionsExtensions.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsExtensions.cs index 4917018f..03246240 100644 --- a/MQTTnet.Core/Server/MqttServerOptionsExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsExtensions.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public static class MqttServerOptionsExtensions { diff --git a/MQTTnet.Core/Server/MqttServerStartedEventArgs.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServerStartedEventArgs.cs similarity index 75% rename from MQTTnet.Core/Server/MqttServerStartedEventArgs.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttServerStartedEventArgs.cs index 8f46bde8..08202994 100644 --- a/MQTTnet.Core/Server/MqttServerStartedEventArgs.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServerStartedEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public class MqttServerStartedEventArgs : EventArgs { diff --git a/MQTTnet.Core/Server/MqttServerTlsEndpointOptions.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServerTlsEndpointOptions.cs similarity index 85% rename from MQTTnet.Core/Server/MqttServerTlsEndpointOptions.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttServerTlsEndpointOptions.cs index 0fb3839d..6c90a446 100644 --- a/MQTTnet.Core/Server/MqttServerTlsEndpointOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServerTlsEndpointOptions.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public sealed class MqttServerTlsEndpointOptions { diff --git a/MQTTnet.Core/Server/MqttSubscribeResult.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttSubscribeResult.cs similarity index 73% rename from MQTTnet.Core/Server/MqttSubscribeResult.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttSubscribeResult.cs index ef80af44..2de40046 100644 --- a/MQTTnet.Core/Server/MqttSubscribeResult.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttSubscribeResult.cs @@ -1,6 +1,6 @@ -using MQTTnet.Core.Packets; +using MQTTnet.Packets; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public class MqttSubscribeResult { diff --git a/MQTTnet.Core/Server/MqttSubscriptionInterceptorContext.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttSubscriptionInterceptorContext.cs similarity index 93% rename from MQTTnet.Core/Server/MqttSubscriptionInterceptorContext.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttSubscriptionInterceptorContext.cs index 93282d3b..e05dd216 100644 --- a/MQTTnet.Core/Server/MqttSubscriptionInterceptorContext.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttSubscriptionInterceptorContext.cs @@ -1,4 +1,4 @@ -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public class MqttSubscriptionInterceptorContext { diff --git a/MQTTnet.Core/Server/MqttTopicFilterComparer.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttTopicFilterComparer.cs similarity index 97% rename from MQTTnet.Core/Server/MqttTopicFilterComparer.cs rename to Frameworks/MQTTnet.NetStandard/Server/MqttTopicFilterComparer.cs index 987a71f1..82444159 100644 --- a/MQTTnet.Core/Server/MqttTopicFilterComparer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttTopicFilterComparer.cs @@ -1,6 +1,6 @@ using System; -namespace MQTTnet.Core.Server +namespace MQTTnet.Server { public static class MqttTopicFilterComparer { diff --git a/MQTTnet.Core/TopicFilter.cs b/Frameworks/MQTTnet.NetStandard/TopicFilter.cs similarity index 92% rename from MQTTnet.Core/TopicFilter.cs rename to Frameworks/MQTTnet.NetStandard/TopicFilter.cs index 6d5258f4..b82fc712 100644 --- a/MQTTnet.Core/TopicFilter.cs +++ b/Frameworks/MQTTnet.NetStandard/TopicFilter.cs @@ -1,6 +1,6 @@ -using MQTTnet.Core.Protocol; +using MQTTnet.Protocol; -namespace MQTTnet.Core +namespace MQTTnet { public sealed class TopicFilter { diff --git a/MQTTnet.Core/TopicFilterBuilder.cs b/Frameworks/MQTTnet.NetStandard/TopicFilterBuilder.cs similarity index 93% rename from MQTTnet.Core/TopicFilterBuilder.cs rename to Frameworks/MQTTnet.NetStandard/TopicFilterBuilder.cs index bb8416c1..38c8fbc2 100644 --- a/MQTTnet.Core/TopicFilterBuilder.cs +++ b/Frameworks/MQTTnet.NetStandard/TopicFilterBuilder.cs @@ -1,7 +1,7 @@ -using MQTTnet.Core.Protocol; -using MQTTnet.Core.Exceptions; +using MQTTnet.Exceptions; +using MQTTnet.Protocol; -namespace MQTTnet.Core +namespace MQTTnet { public class TopicFilterBuilder { diff --git a/MQTTnet.Core/MQTTnet.Core.csproj b/MQTTnet.Core/MQTTnet.Core.csproj deleted file mode 100644 index 60afc301..00000000 --- a/MQTTnet.Core/MQTTnet.Core.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - netstandard1.1 - MQTTnet.Core - MQTTnet.Core - False - Full - - - - - 0.0.0.0 - - - - - - - 2.5.3.0 - 2.5.3.0 - - - - \ No newline at end of file diff --git a/MQTTnet.sln b/MQTTnet.sln index 326fe7ea..ceaa04fb 100644 --- a/MQTTnet.sln +++ b/MQTTnet.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27004.2008 +VisualStudioVersion = 15.0.27004.2009 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Core.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Core.Tests.csproj", "{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}" EndProject @@ -9,8 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{9248C2E1 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Frameworks", "Frameworks", "{32A630A7-2598-41D7-B625-204CD906F5FB}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Core", "MQTTnet.Core\MQTTnet.Core.csproj", "{2ECB99E4-72D0-4C23-99BA-93D511D3967D}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.TestApp.UniversalWindows", "Tests\MQTTnet.TestApp.UniversalWindows\MQTTnet.TestApp.UniversalWindows.csproj", "{FF1F72D6-9524-4422-9497-3CC0002216ED}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.NetStandard", "Frameworks\MQTTnet.Netstandard\MQTTnet.NetStandard.csproj", "{3587E506-55A2-4EB3-99C7-DC01E42D25D2}" @@ -63,22 +61,6 @@ Global {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x64.Build.0 = Release|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.ActiveCfg = Release|Any CPU {A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}.Release|x86.Build.0 = Release|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|ARM.ActiveCfg = Debug|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|ARM.Build.0 = Debug|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|x64.ActiveCfg = Debug|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|x64.Build.0 = Debug|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|x86.ActiveCfg = Debug|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Debug|x86.Build.0 = Debug|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|Any CPU.Build.0 = Release|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|ARM.ActiveCfg = Release|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|ARM.Build.0 = Release|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|x64.ActiveCfg = Release|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|x64.Build.0 = Release|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|x86.ActiveCfg = Release|Any CPU - {2ECB99E4-72D0-4C23-99BA-93D511D3967D}.Release|x86.Build.0 = Release|Any CPU {FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|Any CPU.Build.0 = Debug|Any CPU {FF1F72D6-9524-4422-9497-3CC0002216ED}.Debug|ARM.ActiveCfg = Debug|ARM diff --git a/Tests/MQTTnet.Core.Tests/ByteReaderTests.cs b/Tests/MQTTnet.Core.Tests/ByteReaderTests.cs index 76ff90b1..e2173cbc 100644 --- a/Tests/MQTTnet.Core.Tests/ByteReaderTests.cs +++ b/Tests/MQTTnet.Core.Tests/ByteReaderTests.cs @@ -1,5 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using MQTTnet.Core.Serializer; +using MQTTnet.Serializer; namespace MQTTnet.Core.Tests { diff --git a/Tests/MQTTnet.Core.Tests/ByteWriterTests.cs b/Tests/MQTTnet.Core.Tests/ByteWriterTests.cs index 65991931..881df5c5 100644 --- a/Tests/MQTTnet.Core.Tests/ByteWriterTests.cs +++ b/Tests/MQTTnet.Core.Tests/ByteWriterTests.cs @@ -1,5 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using MQTTnet.Core.Serializer; +using MQTTnet.Serializer; namespace MQTTnet.Core.Tests { diff --git a/Tests/MQTTnet.Core.Tests/ExtensionTests.cs b/Tests/MQTTnet.Core.Tests/ExtensionTests.cs index 2f0966fb..053b0ca3 100644 --- a/Tests/MQTTnet.Core.Tests/ExtensionTests.cs +++ b/Tests/MQTTnet.Core.Tests/ExtensionTests.cs @@ -2,8 +2,8 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MQTTnet.Core.Exceptions; -using MQTTnet.Core.Internal; +using MQTTnet.Exceptions; +using MQTTnet.Internal; namespace MQTTnet.Core.Tests { diff --git a/Tests/MQTTnet.Core.Tests/MqttApplicationMessageBuilderTests.cs b/Tests/MQTTnet.Core.Tests/MqttApplicationMessageBuilderTests.cs index c6a70174..59afcd68 100644 --- a/Tests/MQTTnet.Core.Tests/MqttApplicationMessageBuilderTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttApplicationMessageBuilderTests.cs @@ -2,7 +2,7 @@ using System.IO; using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MQTTnet.Core.Protocol; +using MQTTnet.Protocol; namespace MQTTnet.Core.Tests { diff --git a/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs b/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs index 6800e6ce..606d1daf 100644 --- a/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs @@ -1,7 +1,7 @@ using System.IO; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MQTTnet.Core.Serializer; +using MQTTnet.Serializer; namespace MQTTnet.Core.Tests { diff --git a/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs b/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs index bdd07516..01d19f1f 100644 --- a/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs @@ -3,10 +3,10 @@ using System.IO; using System.Text; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Protocol; -using MQTTnet.Core.Serializer; +using MQTTnet.Adapter; +using MQTTnet.Packets; +using MQTTnet.Protocol; +using MQTTnet.Serializer; namespace MQTTnet.Core.Tests { diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index 89cae3b6..f1c8ff09 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MQTTnet.Core.Client; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.Protocol; -using MQTTnet.Core.Server; +using MQTTnet.Diagnostics; +using MQTTnet.Protocol; +using MQTTnet.Server; +using MQTTnet.Client; namespace MQTTnet.Core.Tests { diff --git a/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs b/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs index f4885434..2c24c483 100644 --- a/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs @@ -1,7 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Protocol; -using MQTTnet.Core.Server; +using MQTTnet.Packets; +using MQTTnet.Protocol; +using MQTTnet.Server; namespace MQTTnet.Core.Tests { diff --git a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs index 53a6f0fe..2bac46b6 100644 --- a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs +++ b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs @@ -3,9 +3,9 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Packets; -using MQTTnet.Core.Serializer; +using MQTTnet.Adapter; +using MQTTnet.Packets; +using MQTTnet.Serializer; namespace MQTTnet.Core.Tests { diff --git a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs index 7da1e167..eb291f9f 100644 --- a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs +++ b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs @@ -1,6 +1,6 @@ -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Client; -using MQTTnet.Core.Diagnostics; +using MQTTnet.Adapter; +using MQTTnet.Client; +using MQTTnet.Diagnostics; namespace MQTTnet.Core.Tests { diff --git a/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs b/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs index e65d9f8a..ea53512f 100644 --- a/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs +++ b/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs @@ -1,17 +1,17 @@ using System; using System.Threading.Tasks; -using MQTTnet.Core.Adapter; -using MQTTnet.Core.Server; -using MQTTnet.Core.Client; -using MQTTnet.Core.Diagnostics; +using MQTTnet.Adapter; +using MQTTnet.Client; +using MQTTnet.Diagnostics; +using MQTTnet.Server; namespace MQTTnet.Core.Tests { public class TestMqttServerAdapter : IMqttServerAdapter { public event EventHandler ClientAccepted; - - public async Task ConnectTestClient(IMqttServer server, string clientId, MqttApplicationMessage willMessage = null) + + public async Task ConnectTestClient(IMqttServer server, string clientId, MqttApplicationMessage willMessage = null) { var adapterA = new TestMqttCommunicationAdapter(); var adapterB = new TestMqttCommunicationAdapter(); diff --git a/Tests/MQTTnet.Core.Tests/TopicFilterComparerTests.cs b/Tests/MQTTnet.Core.Tests/TopicFilterComparerTests.cs index c65dcaba..be169212 100644 --- a/Tests/MQTTnet.Core.Tests/TopicFilterComparerTests.cs +++ b/Tests/MQTTnet.Core.Tests/TopicFilterComparerTests.cs @@ -1,5 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using MQTTnet.Core.Server; +using MQTTnet.Server; namespace MQTTnet.Core.Tests { diff --git a/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs b/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs index 5c9b32ed..9e5f90ae 100644 --- a/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs +++ b/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs @@ -6,8 +6,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using MQTTnet.AspNetCore; -using MQTTnet.Core; -using MQTTnet.Core.Server; +using MQTTnet.Server; namespace MQTTnet.TestApp.AspNetCore2 { diff --git a/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs b/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs index dfd7d0d9..09788cce 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs @@ -1,8 +1,7 @@ using System; using System.Text; using System.Threading.Tasks; -using MQTTnet.Core; -using MQTTnet.Core.Client; +using MQTTnet.Client; namespace MQTTnet.TestApp.NetCore { diff --git a/Tests/MQTTnet.TestApp.NetCore/ManagedClientTest.cs b/Tests/MQTTnet.TestApp.NetCore/ManagedClientTest.cs index 7f76b659..21d1fdf8 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ManagedClientTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ManagedClientTest.cs @@ -1,12 +1,11 @@ using System; using System.Threading.Tasks; -using MQTTnet.Core; -using MQTTnet.Core.Client; -using MQTTnet.Core.ManagedClient; -using MQTTnet.Core.Protocol; using System.IO; using Newtonsoft.Json; using System.Collections.Generic; +using MQTTnet.Client; +using MQTTnet.ManagedClient; +using MQTTnet.Protocol; namespace MQTTnet.TestApp.NetCore { diff --git a/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetConsoleLogger.cs b/Tests/MQTTnet.TestApp.NetCore/MqttNetConsoleLogger.cs similarity index 88% rename from Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetConsoleLogger.cs rename to Tests/MQTTnet.TestApp.NetCore/MqttNetConsoleLogger.cs index 3cc13c38..67eb69e7 100644 --- a/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetConsoleLogger.cs +++ b/Tests/MQTTnet.TestApp.NetCore/MqttNetConsoleLogger.cs @@ -1,8 +1,8 @@ using System; using System.Text; -using MQTTnet.Core.Diagnostics; +using MQTTnet.Diagnostics; -namespace MQTTnet.Diagnostics +namespace MQTTnet.TestApp.NetCore { public static class MqttNetConsoleLogger { @@ -10,8 +10,8 @@ namespace MQTTnet.Diagnostics public static void ForwardToConsole() { - MqttNetGlobalLog.LogMessagePublished -= PrintToConsole; - MqttNetGlobalLog.LogMessagePublished += PrintToConsole; + MqttNetGlobalLogger.LogMessagePublished -= PrintToConsole; + MqttNetGlobalLogger.LogMessagePublished += PrintToConsole; } private static void PrintToConsole(object sender, MqttNetLogMessagePublishedEventArgs e) diff --git a/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs b/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs index c6bbe04a..3aba3c1c 100644 --- a/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs @@ -1,14 +1,13 @@ -using MQTTnet.Core; -using MQTTnet.Core.Client; -using MQTTnet.Core.Protocol; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Core.Server; +using MQTTnet.Client; +using MQTTnet.Protocol; +using MQTTnet.Server; namespace MQTTnet.TestApp.NetCore { diff --git a/Tests/MQTTnet.TestApp.NetCore/Program.cs b/Tests/MQTTnet.TestApp.NetCore/Program.cs index fb02de8f..0e4868af 100644 --- a/Tests/MQTTnet.TestApp.NetCore/Program.cs +++ b/Tests/MQTTnet.TestApp.NetCore/Program.cs @@ -1,11 +1,11 @@ -using MQTTnet.Core; -using MQTTnet.Core.Client; -using MQTTnet.Core.Server; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; +using MQTTnet.Client; +using MQTTnet.Diagnostics; +using MQTTnet.Server; using Newtonsoft.Json; namespace MQTTnet.TestApp.NetCore diff --git a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs index 23282920..767db084 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs @@ -1,9 +1,9 @@ using System; using System.Text; using System.Threading.Tasks; -using MQTTnet.Core.Protocol; -using MQTTnet.Core.Server; using MQTTnet.Diagnostics; +using MQTTnet.Protocol; +using MQTTnet.Server; namespace MQTTnet.TestApp.NetCore { diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/JsonServerStorage.cs b/Tests/MQTTnet.TestApp.UniversalWindows/JsonServerStorage.cs index 9baafec0..fbf5b66d 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/JsonServerStorage.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/JsonServerStorage.cs @@ -1,8 +1,7 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -using MQTTnet.Core; -using MQTTnet.Core.Server; +using MQTTnet.Server; using Newtonsoft.Json; namespace MQTTnet.TestApp.UniversalWindows diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj index fa0763c7..4445af39 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj @@ -131,10 +131,6 @@ {3587e506-55a2-4eb3-99c7-dc01e42d25d2} MQTTnet.NetStandard - - {2ecb99e4-72d0-4c23-99ba-93d511d3967d} - MQTTnet.Core - diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index 6c7258b9..5d943be6 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -5,13 +5,12 @@ using System.Threading.Tasks; using Windows.Security.Cryptography.Certificates; using Windows.UI.Core; using Windows.UI.Xaml; -using MQTTnet.Core; -using MQTTnet.Core.Client; -using MQTTnet.Core.Diagnostics; -using MQTTnet.Core.ManagedClient; -using MQTTnet.Core.Protocol; -using MQTTnet.Core.Server; +using MQTTnet.Client; +using MQTTnet.Diagnostics; using MQTTnet.Implementations; +using MQTTnet.ManagedClient; +using MQTTnet.Protocol; +using MQTTnet.Server; namespace MQTTnet.TestApp.UniversalWindows { @@ -26,7 +25,7 @@ namespace MQTTnet.TestApp.UniversalWindows { InitializeComponent(); - MqttNetGlobalLog.LogMessagePublished += OnTraceMessagePublished; + MqttNetGlobalLogger.LogMessagePublished += OnTraceMessagePublished; } private async void OnTraceMessagePublished(object sender, MqttNetLogMessagePublishedEventArgs e) @@ -250,7 +249,7 @@ namespace MQTTnet.TestApp.UniversalWindows { { // Write all trace messages to the console window. - MqttNetGlobalLog.LogMessagePublished += (s, e) => + MqttNetGlobalLogger.LogMessagePublished += (s, e) => { Console.WriteLine($">> [{e.TraceMessage.Timestamp:O}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}"); if (e.TraceMessage.Exception != null) From ee6ec14bf8f69c9db7ff1ffe5c57f730c7d82ef1 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sat, 25 Nov 2017 20:12:50 +0100 Subject: [PATCH 067/149] Add interface for server options. Add context class for connection validator (hide internal packets). --- Build/MQTTnet.AspNetCore.nuspec | 6 ++-- .../MqttWebSocketServerAdapter.cs | 2 +- .../ServiceCollectionExtensions.cs | 2 +- .../Adapter/IMqttServerAdapter.cs | 2 +- .../Implementations/MqttServerAdapter.Uwp.cs | 2 +- .../Implementations/MqttServerAdapter.cs | 2 +- .../MQTTnet.NetStandard/Server/IMqttServer.cs | 2 +- .../Server/IMqttServerOptions.cs | 16 ++++++++++ .../Server/MqttClientPendingMessagesQueue.cs | 4 +-- .../Server/MqttClientSession.cs | 4 +-- .../Server/MqttClientSessionsManager.cs | 17 +++++++--- .../Server/MqttClientSubscriptionsManager.cs | 4 +-- .../Server/MqttRetainedMessagesManager.cs | 4 +-- .../MQTTnet.NetStandard/Server/MqttServer.cs | 4 +-- .../Server/MqttServerOptions.cs | 6 ++-- .../Server/MqttServerOptionsBuilder.cs | 6 ++-- .../Server/MqttServerOptionsExtensions.cs | 4 +-- .../TestMqttServerAdapter.cs | 2 +- Tests/MQTTnet.TestApp.NetCore/ServerTest.cs | 4 +-- .../MainPage.xaml.cs | 31 ++++++++++++------- 20 files changed, 74 insertions(+), 50 deletions(-) create mode 100644 Frameworks/MQTTnet.NetStandard/Server/IMqttServerOptions.cs diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index 3a862bad..1510b2d8 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -2,7 +2,7 @@ MQTTnet.AspNetCore - 2.5.3 + 2.6.0 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,13 +10,13 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false This is a support library to integrate MQTTnet into AspNetCore. - * Updated to MQTTnet 2.5.3. + * Updated to MQTTnet 2.6.0. Copyright Christian Kratky 2016-2017 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/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs index 5af8b64d..a2ca627f 100644 --- a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs +++ b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs @@ -12,7 +12,7 @@ namespace MQTTnet.AspNetCore { public event EventHandler ClientAccepted; - public Task StartAsync(MqttServerOptions options) + public Task StartAsync(IMqttServerOptions options) { return Task.CompletedTask; } diff --git a/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs b/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs index a6af6ebe..d4bdf394 100644 --- a/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs +++ b/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs @@ -9,7 +9,7 @@ namespace MQTTnet.AspNetCore { public static class ServiceCollectionExtensions { - public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, MqttServerOptions options) + public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, IMqttServerOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/IMqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/IMqttServerAdapter.cs index d4ea9413..bd583f54 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/IMqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/IMqttServerAdapter.cs @@ -8,7 +8,7 @@ namespace MQTTnet.Adapter { event EventHandler ClientAccepted; - Task StartAsync(MqttServerOptions options); + Task StartAsync(IMqttServerOptions options); Task StopAsync(); } } diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs index 3966edce..96fbae4a 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs @@ -21,7 +21,7 @@ namespace MQTTnet.Implementations public event EventHandler ClientAccepted; - public async Task StartAsync(MqttServerOptions options) + public async Task StartAsync(IMqttServerOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs index dadca442..d4ab0950 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs @@ -30,7 +30,7 @@ namespace MQTTnet.Implementations public event EventHandler ClientAccepted; - public Task StartAsync(MqttServerOptions options) + public Task StartAsync(IMqttServerOptions options) { if (_cancellationTokenSource != null) throw new InvalidOperationException("Server is already started."); diff --git a/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs b/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs index 3d0ccda6..926ab9d1 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs @@ -12,7 +12,7 @@ namespace MQTTnet.Server Task> GetConnectedClientsAsync(); - Task StartAsync(MqttServerOptions options); + Task StartAsync(IMqttServerOptions options); Task StopAsync(); } } \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Server/IMqttServerOptions.cs b/Frameworks/MQTTnet.NetStandard/Server/IMqttServerOptions.cs new file mode 100644 index 00000000..92c1bfb7 --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/Server/IMqttServerOptions.cs @@ -0,0 +1,16 @@ +using System; + +namespace MQTTnet.Server +{ + public interface IMqttServerOptions + { + Action ApplicationMessageInterceptor { get; } + int ConnectionBacklog { get; } + Action ConnectionValidator { get; } + TimeSpan DefaultCommunicationTimeout { get; } + MqttServerDefaultEndpointOptions DefaultEndpointOptions { get; } + IMqttServerStorage Storage { get; } + Action SubscriptionInterceptor { get; } + MqttServerTlsEndpointOptions TlsEndpointOptions { get; } + } +} \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs index 9e1a2cda..a64dfbf5 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs @@ -13,11 +13,11 @@ namespace MQTTnet.Server public sealed class MqttClientPendingMessagesQueue { private readonly BlockingCollection _pendingPublishPackets = new BlockingCollection(); - private readonly MqttServerOptions _options; + private readonly IMqttServerOptions _options; private readonly MqttClientSession _session; private readonly IMqttNetLogger _logger; - public MqttClientPendingMessagesQueue(MqttServerOptions options, MqttClientSession session, IMqttNetLogger logger) + public MqttClientPendingMessagesQueue(IMqttServerOptions options, MqttClientSession session, IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _session = session ?? throw new ArgumentNullException(nameof(session)); diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index cc889644..f871ad38 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -19,7 +19,7 @@ namespace MQTTnet.Server private readonly MqttClientSubscriptionsManager _subscriptionsManager; private readonly MqttClientSessionsManager _sessionsManager; private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue; - private readonly MqttServerOptions _options; + private readonly IMqttServerOptions _options; private readonly IMqttNetLogger _logger; private IMqttChannelAdapter _adapter; @@ -28,7 +28,7 @@ namespace MQTTnet.Server public MqttClientSession( string clientId, - MqttServerOptions options, + IMqttServerOptions options, MqttClientSessionsManager sessionsManager, IMqttNetLogger logger) { diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index 61e19f76..7d647d92 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -18,11 +18,11 @@ namespace MQTTnet.Server private readonly Dictionary _sessions = new Dictionary(); private readonly SemaphoreSlim _sessionsSemaphore = new SemaphoreSlim(1, 1); - private readonly MqttServerOptions _options; + private readonly IMqttServerOptions _options; private readonly MqttRetainedMessagesManager _retainedMessagesManager; private readonly IMqttNetLogger _logger; - public MqttClientSessionsManager(MqttServerOptions options, MqttRetainedMessagesManager retainedMessagesManager, IMqttNetLogger logger) + public MqttClientSessionsManager(IMqttServerOptions options, MqttRetainedMessagesManager retainedMessagesManager, IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _options = options ?? throw new ArgumentNullException(nameof(options)); @@ -174,12 +174,19 @@ namespace MQTTnet.Server private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket) { - if (_options.ConnectionValidator != null) + if (_options.ConnectionValidator == null) { - return _options.ConnectionValidator(connectPacket); + return MqttConnectReturnCode.ConnectionAccepted; } + + var context = new MqttConnectionValidatorContext( + connectPacket.ClientId, + connectPacket.Username, + connectPacket.Password, + connectPacket.WillMessage); - return MqttConnectReturnCode.ConnectionAccepted; + _options.ConnectionValidator(context); + return context.ReturnCode; } private async Task GetOrCreateClientSessionAsync(MqttConnectPacket connectPacket) diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs index 86156303..1276b066 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs @@ -8,9 +8,9 @@ namespace MQTTnet.Server public sealed class MqttClientSubscriptionsManager { private readonly Dictionary _subscriptions = new Dictionary(); - private readonly MqttServerOptions _options; + private readonly IMqttServerOptions _options; - public MqttClientSubscriptionsManager(MqttServerOptions options) + public MqttClientSubscriptionsManager(IMqttServerOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs index c8377694..0b8d6697 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs @@ -13,9 +13,9 @@ namespace MQTTnet.Server private readonly Dictionary _retainedMessages = new Dictionary(); private readonly SemaphoreSlim _gate = new SemaphoreSlim(1, 1); private readonly IMqttNetLogger _logger; - private readonly MqttServerOptions _options; + private readonly IMqttServerOptions _options; - public MqttRetainedMessagesManager(MqttServerOptions options, IMqttNetLogger logger) + public MqttRetainedMessagesManager(IMqttServerOptions options, IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _options = options ?? throw new ArgumentNullException(nameof(options)); diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs index 25dc2d36..42c68543 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs @@ -16,7 +16,7 @@ namespace MQTTnet.Server private MqttClientSessionsManager _clientSessionsManager; private MqttRetainedMessagesManager _retainedMessagesManager; private CancellationTokenSource _cancellationTokenSource; - private MqttServerOptions _options; + private IMqttServerOptions _options; public MqttServer(IEnumerable adapters, IMqttNetLogger logger) { @@ -52,7 +52,7 @@ namespace MQTTnet.Server } } - public async Task StartAsync(MqttServerOptions options) + public async Task StartAsync(IMqttServerOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptions.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptions.cs index d04725ec..2b0a9a00 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptions.cs @@ -1,10 +1,8 @@ using System; -using MQTTnet.Packets; -using MQTTnet.Protocol; namespace MQTTnet.Server { - public class MqttServerOptions + public class MqttServerOptions : IMqttServerOptions { public MqttServerDefaultEndpointOptions DefaultEndpointOptions { get; } = new MqttServerDefaultEndpointOptions(); @@ -14,7 +12,7 @@ namespace MQTTnet.Server public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(15); - public Func ConnectionValidator { get; set; } + public Action ConnectionValidator { get; set; } public Action ApplicationMessageInterceptor { get; set; } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsBuilder.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsBuilder.cs index f6cb0bba..34f36a95 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsBuilder.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsBuilder.cs @@ -1,6 +1,4 @@ using System; -using MQTTnet.Packets; -using MQTTnet.Protocol; namespace MQTTnet.Server { @@ -62,7 +60,7 @@ namespace MQTTnet.Server return this; } - public MqttServerOptionsBuilder WithConnectionValidator(Func value) + public MqttServerOptionsBuilder WithConnectionValidator(Action value) { _options.ConnectionValidator = value; return this; @@ -80,7 +78,7 @@ namespace MQTTnet.Server return this; } - public MqttServerOptions Build() + public IMqttServerOptions Build() { return _options; } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsExtensions.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsExtensions.cs index 03246240..db93ef18 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsExtensions.cs @@ -4,7 +4,7 @@ namespace MQTTnet.Server { public static class MqttServerOptionsExtensions { - public static int GetTlsEndpointPort(this MqttServerOptions options) + public static int GetTlsEndpointPort(this IMqttServerOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); @@ -16,7 +16,7 @@ namespace MQTTnet.Server return options.TlsEndpointOptions.Port.Value; } - public static int GetDefaultEndpointPort(this MqttServerOptions options) + public static int GetDefaultEndpointPort(this IMqttServerOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); diff --git a/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs b/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs index ea53512f..a2fec80f 100644 --- a/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs +++ b/Tests/MQTTnet.Core.Tests/TestMqttServerAdapter.cs @@ -62,7 +62,7 @@ namespace MQTTnet.Core.Tests ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(adapter)); } - public Task StartAsync(MqttServerOptions options) + public Task StartAsync(IMqttServerOptions options) { return Task.FromResult(0); } diff --git a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs index 767db084..d4960d06 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs @@ -23,11 +23,9 @@ namespace MQTTnet.TestApp.NetCore { if (p.Username != "USER" || p.Password != "PASS") { - return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; + p.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; } } - - return MqttConnectReturnCode.ConnectionAccepted; }, Storage = new RetainedMessageHandler(), diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index 5d943be6..a750b274 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -354,20 +354,23 @@ namespace MQTTnet.TestApp.UniversalWindows { if (c.ClientId.Length < 10) { - return MqttConnectReturnCode.ConnectionRefusedIdentifierRejected; + c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedIdentifierRejected; + return; } if (c.Username != "mySecretUser") { - return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; + c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; + return; } if (c.Password != "mySecretPassword") { - return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; + c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; + return; } - return MqttConnectReturnCode.ConnectionAccepted; + c.ReturnCode = MqttConnectReturnCode.ConnectionAccepted; }; var factory = new MqttFactory(); @@ -410,14 +413,15 @@ namespace MQTTnet.TestApp.UniversalWindows }; options.DefaultEndpointOptions.Port = 1884; - options.ConnectionValidator = packet => + options.ConnectionValidator = c => { - if (packet.ClientId != "Highlander") + if (c.ClientId != "Highlander") { - return MqttConnectReturnCode.ConnectionRefusedIdentifierRejected; + c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedIdentifierRejected; + return; } - return MqttConnectReturnCode.ConnectionAccepted; + c.ReturnCode = MqttConnectReturnCode.ConnectionAccepted; }; var mqttServer = new MqttFactory().CreateMqttServer(); @@ -432,20 +436,23 @@ namespace MQTTnet.TestApp.UniversalWindows { if (c.ClientId.Length < 10) { - return MqttConnectReturnCode.ConnectionRefusedIdentifierRejected; + c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedIdentifierRejected; + return; } if (c.Username != "mySecretUser") { - return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; + c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; + return; } if (c.Password != "mySecretPassword") { - return MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; + c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword; + return; } - return MqttConnectReturnCode.ConnectionAccepted; + c.ReturnCode = MqttConnectReturnCode.ConnectionAccepted; } }; } From 24ab285066e4761b4485ebd11f6c7c40a47d8b5e Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sat, 25 Nov 2017 20:33:04 +0100 Subject: [PATCH 068/149] Update project settings --- Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj index 752ba948..f4018cb5 100644 --- a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -16,6 +16,7 @@ true codeSigningKey.pfx + false From 611fabcd012d06a4698b90bddaeadf7587a5d2c0 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sat, 25 Nov 2017 23:10:48 +0100 Subject: [PATCH 069/149] Performance optimizations --- .../Adapter/MqttChannelAdapter.cs | 13 ++++--- .../Serializer/IMqttPacketSerializer.cs | 6 ++- .../Serializer/MqttPacketReader.cs | 22 ++++++++--- .../Serializer/MqttPacketSerializer.cs | 38 ++++++++++--------- .../Serializer/MqttPacketWriter.cs | 7 ++-- .../Server/MqttClientSession.cs | 38 +++++++------------ .../Server/MqttClientSessionsManager.cs | 9 ++--- .../Server/MqttClientSubscriptionsManager.cs | 10 ++--- .../MqttPacketSerializerTests.cs | 24 +++++++++--- .../MqttSubscriptionsManagerTests.cs | 6 +-- .../PerformanceTest.cs | 20 +++++----- 11 files changed, 105 insertions(+), 88 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index 53603fa5..58ab4521 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -60,8 +60,11 @@ namespace MQTTnet.Adapter _logger.Trace("TX >>> {0} [Timeout={1}]", packet, timeout); - var writeBuffer = PacketSerializer.Serialize(packet); - await _channel.SendStream.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken).ConfigureAwait(false); + var chunks = PacketSerializer.Serialize(packet); + foreach (var chunk in chunks) + { + await _channel.SendStream.WriteAsync(chunk.Array, chunk.Offset, chunk.Count, cancellationToken).ConfigureAwait(false); + } } if (timeout > TimeSpan.Zero) @@ -114,7 +117,7 @@ namespace MQTTnet.Adapter { receivedMqttPacket?.Dispose(); } - }); + }).ConfigureAwait(false); return packet; } @@ -140,8 +143,8 @@ namespace MQTTnet.Adapter var readBytesCount = await stream.ReadAsync(body, offset, body.Length - offset, cancellationToken).ConfigureAwait(false); offset += readBytesCount; } while (offset < header.BodyLength); - - return new ReceivedMqttPacket(header, new MemoryStream(body, 0, body.Length)); + + return new ReceivedMqttPacket(header, new MemoryStream(body, 0, body.Length, false, true)); } private static async Task ExecuteAndWrapExceptionAsync(Func action) diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs b/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs index 6b46b528..439460d1 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs @@ -1,4 +1,6 @@ -using MQTTnet.Adapter; +using System; +using System.Collections.Generic; +using MQTTnet.Adapter; using MQTTnet.Packets; namespace MQTTnet.Serializer @@ -7,7 +9,7 @@ namespace MQTTnet.Serializer { MqttProtocolVersion ProtocolVersion { get; set; } - byte[] Serialize(MqttBasePacket mqttPacket); + IEnumerable> Serialize(MqttBasePacket mqttPacket); MqttBasePacket Deserialize(ReceivedMqttPacket receivedMqttPacket); } diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs index caf28813..04ee01f2 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; @@ -30,7 +29,7 @@ namespace MQTTnet.Serializer { return null; } - + var fixedHeader = (byte)buffer; var controlPacketType = (MqttControlPacketType)(fixedHeader >> 4); var bodyLength = ReadBodyLengthFromSource(stream, cancellationToken); @@ -57,12 +56,22 @@ namespace MQTTnet.Serializer public string ReadStringWithLengthPrefix() { var buffer = ReadWithLengthPrefix(); + if (buffer.Length == 0) + { + return string.Empty; + } + return Encoding.UTF8.GetString(buffer, 0, buffer.Length); } public byte[] ReadWithLengthPrefix() { var length = ReadUInt16(); + if (length == 0) + { + return new byte[0]; + } + return ReadBytes(length); } @@ -78,7 +87,7 @@ namespace MQTTnet.Serializer var value = 0; byte encodedByte; - var readBytes = new List(); + ////var readBytes = new List(); do { if (cancellationToken.IsCancellationRequested) @@ -87,19 +96,20 @@ namespace MQTTnet.Serializer } var buffer = stream.ReadByte(); - readBytes.Add(buffer); - if (buffer == -1) { throw new MqttCommunicationException("Connection closed while reading remaining length data."); } + ////readBytes.Add(buffer); + encodedByte = (byte)buffer; value += (byte)(encodedByte & 127) * multiplier; multiplier *= 128; if (multiplier > 128 * 128 * 128) { - throw new MqttProtocolViolationException($"Remaining length is invalid (Data={string.Join(",", readBytes)})."); + //throw new MqttProtocolViolationException($"Remaining length is invalid (Data={string.Join(",", readBytes)})."); + throw new MqttProtocolViolationException("Remaining length is invalid."); } } while ((encodedByte & 128) != 0); diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs index ce45b3e2..0b041146 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs @@ -1,12 +1,12 @@ -using System; +using MQTTnet.Adapter; +using MQTTnet.Exceptions; +using MQTTnet.Packets; +using MQTTnet.Protocol; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; -using MQTTnet.Adapter; -using MQTTnet.Exceptions; -using MQTTnet.Packets; -using MQTTnet.Protocol; namespace MQTTnet.Serializer { @@ -17,25 +17,29 @@ namespace MQTTnet.Serializer public MqttProtocolVersion ProtocolVersion { get; set; } = MqttProtocolVersion.V311; - public byte[] Serialize(MqttBasePacket packet) + public IEnumerable> Serialize(MqttBasePacket packet) { if (packet == null) throw new ArgumentNullException(nameof(packet)); - using (var stream = new MemoryStream()) + using (var stream = new MemoryStream(128)) using (var writer = new MqttPacketWriter(stream)) { var fixedHeader = SerializePacket(packet, writer); - var headerBuffer = new List { fixedHeader }; - MqttPacketWriter.WriteRemainingLength((int)stream.Length, headerBuffer); + var remainingLength = (int)stream.Length; + writer.Write(fixedHeader); + MqttPacketWriter.WriteRemainingLength(remainingLength, writer); + var headerLength = (int)stream.Length - remainingLength; - var header = headerBuffer.ToArray(); - var body = stream.ToArray(); - - var buffer = new byte[header.Length + body.Length]; - Buffer.BlockCopy(header, 0, buffer, 0, header.Length); - Buffer.BlockCopy(body, 0, buffer, header.Length, body.Length); - - return buffer; +#if NET461 || NET452 || NETSTANDARD2_0 + var buffer = stream.GetBuffer(); +#else + var buffer = stream.ToArray(); +#endif + return new List> + { + new ArraySegment(buffer, remainingLength, headerLength), + new ArraySegment(buffer, 0, remainingLength) + }; } } diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketWriter.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketWriter.cs index cdf7915e..cb3d4589 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketWriter.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketWriter.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Text; using MQTTnet.Protocol; @@ -56,11 +55,11 @@ namespace MQTTnet.Serializer Write(value); } - public static void WriteRemainingLength(int length, List target) + public static void WriteRemainingLength(int length, BinaryWriter target) { if (length == 0) { - target.Add(0); + target.Write((byte)0); return; } @@ -75,7 +74,7 @@ namespace MQTTnet.Serializer encodedByte = encodedByte | 128; } - target.Add((byte)encodedByte); + target.Write((byte)encodedByte); } while (x > 0); } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index f871ad38..275fcb1b 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MQTTnet.Adapter; @@ -14,8 +13,6 @@ namespace MQTTnet.Server { public sealed class MqttClientSession { - private readonly HashSet _unacknowledgedPublishPackets = new HashSet(); - private readonly MqttClientSubscriptionsManager _subscriptionsManager; private readonly MqttClientSessionsManager _sessionsManager; private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue; @@ -99,21 +96,22 @@ namespace MQTTnet.Server if (willMessage != null) { _willMessage = null; //clear willmessage so it is send just once - await _sessionsManager.DispatchApplicationMessageAsync(this, willMessage); + await _sessionsManager.DispatchApplicationMessageAsync(this, willMessage).ConfigureAwait(false); } } } - public void EnqueuePublishPacket(MqttPublishPacket publishPacket) + public void EnqueueApplicationMessage(MqttApplicationMessage applicationMessage) { - if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket)); + if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); - var result = _subscriptionsManager.CheckSubscriptions(publishPacket); + var result = _subscriptionsManager.CheckSubscriptions(applicationMessage); if (!result.IsSubscribed) { return; } + var publishPacket = applicationMessage.ToPublishPacket(); publishPacket.QualityOfServiceLevel = result.QualityOfServiceLevel; _pendingMessagesQueue.Enqueue(publishPacket); } @@ -134,12 +132,12 @@ namespace MQTTnet.Server catch (MqttCommunicationException exception) { _logger.Warning(exception, "Client '{0}': Communication exception while processing client packets.", ClientId); - await StopAsync(); + await StopAsync().ConfigureAwait(false); } catch (Exception exception) { _logger.Error(exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId); - await StopAsync(); + await StopAsync().ConfigureAwait(false); } } @@ -200,7 +198,7 @@ namespace MQTTnet.Server if (subscribeResult.CloseConnection) { await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttDisconnectPacket()).ConfigureAwait(false); - await StopAsync(); + await StopAsync().ConfigureAwait(false); } } @@ -209,7 +207,7 @@ namespace MQTTnet.Server var retainedMessages = await _sessionsManager.GetRetainedMessagesAsync(subscribePacket).ConfigureAwait(false); foreach (var publishPacket in retainedMessages) { - EnqueuePublishPacket(publishPacket.ToPublishPacket()); + EnqueueApplicationMessage(publishPacket); } } @@ -221,27 +219,22 @@ namespace MQTTnet.Server { case MqttQualityOfServiceLevel.AtMostOnce: { - await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage); + await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false); return; } case MqttQualityOfServiceLevel.AtLeastOnce: { - await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage); + await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false); await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, - new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }); + new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }).ConfigureAwait(false); return; } case MqttQualityOfServiceLevel.ExactlyOnce: { // QoS 2 is implement as method "B" [4.3.3 QoS 2: Exactly once delivery] - lock (_unacknowledgedPublishPackets) - { - _unacknowledgedPublishPackets.Add(publishPacket.PacketIdentifier); - } - - await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage); + await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false); await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }).ConfigureAwait(false); @@ -255,11 +248,6 @@ namespace MQTTnet.Server private Task HandleIncomingPubRelPacketAsync(IMqttChannelAdapter adapter, MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken) { - lock (_unacknowledgedPublishPackets) - { - _unacknowledgedPublishPackets.Remove(pubRelPacket.PacketIdentifier); - } - return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier }); } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index 7d647d92..defe5ebc 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using MQTTnet.Adapter; using MQTTnet.Diagnostics; using MQTTnet.Exceptions; -using MQTTnet.Internal; using MQTTnet.Packets; using MQTTnet.Protocol; using MQTTnet.Serializer; @@ -59,7 +58,7 @@ namespace MQTTnet.Server return; } - var clientSession = await GetOrCreateClientSessionAsync(connectPacket); + var clientSession = await GetOrCreateClientSessionAsync(connectPacket).ConfigureAwait(false); await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttConnAckPacket { @@ -105,7 +104,7 @@ namespace MQTTnet.Server { foreach (var session in _sessions) { - await session.Value.StopAsync(); + await session.Value.StopAsync().ConfigureAwait(false); } _sessions.Clear(); @@ -162,7 +161,7 @@ namespace MQTTnet.Server { foreach (var clientSession in _sessions.Values.ToList()) { - clientSession.EnqueuePublishPacket(applicationMessage.ToPublishPacket()); + clientSession.EnqueueApplicationMessage(applicationMessage); } } } @@ -200,7 +199,7 @@ namespace MQTTnet.Server if (connectPacket.CleanSession) { _sessions.Remove(connectPacket.ClientId); - await clientSession.StopAsync(); + await clientSession.StopAsync().ConfigureAwait(false); clientSession = null; _logger.Trace("Stopped existing session of client '{0}'.", connectPacket.ClientId); diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs index 1276b066..73548ce3 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs @@ -64,23 +64,23 @@ namespace MQTTnet.Server return unsubscribePacket.CreateResponse(); } - public CheckSubscriptionsResult CheckSubscriptions(MqttPublishPacket publishPacket) + public CheckSubscriptionsResult CheckSubscriptions(MqttApplicationMessage applicationMessage) { - if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket)); + if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); lock (_subscriptions) { foreach (var subscription in _subscriptions) { - if (!MqttTopicFilterComparer.IsMatch(publishPacket.Topic, subscription.Key)) + if (!MqttTopicFilterComparer.IsMatch(applicationMessage.Topic, subscription.Key)) { continue; } var effectiveQos = subscription.Value; - if (publishPacket.QualityOfServiceLevel < effectiveQos) + if (applicationMessage.QualityOfServiceLevel < effectiveQos) { - effectiveQos = publishPacket.QualityOfServiceLevel; + effectiveQos = applicationMessage.QualityOfServiceLevel; } return new CheckSubscriptionsResult diff --git a/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs b/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs index 01d19f1f..25c93520 100644 --- a/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; @@ -392,9 +393,9 @@ namespace MQTTnet.Core.Tests private static void SerializeAndCompare(MqttBasePacket packet, string expectedBase64Value, MqttProtocolVersion protocolVersion = MqttProtocolVersion.V311) { var serializer = new MqttPacketSerializer { ProtocolVersion = protocolVersion }; - var buffer = serializer.Serialize(packet); - - Assert.AreEqual(expectedBase64Value, Convert.ToBase64String(buffer)); + var chunks = serializer.Serialize(packet); + + Assert.AreEqual(expectedBase64Value, Convert.ToBase64String(Join(chunks))); } private static void DeserializeAndCompare(MqttBasePacket packet, string expectedBase64Value) @@ -403,18 +404,29 @@ namespace MQTTnet.Core.Tests var buffer1 = serializer.Serialize(packet); - using (var headerStream = new MemoryStream(buffer1)) + using (var headerStream = new MemoryStream(Join(buffer1))) { var header = MqttPacketReader.ReadHeaderFromSource(headerStream, CancellationToken.None); - using (var bodyStream = new MemoryStream(buffer1, (int)headerStream.Position, header.BodyLength)) + using (var bodyStream = new MemoryStream(Join(buffer1), (int)headerStream.Position, header.BodyLength)) { var deserializedPacket = serializer.Deserialize(new ReceivedMqttPacket(header, bodyStream)); var buffer2 = serializer.Serialize(deserializedPacket); - Assert.AreEqual(expectedBase64Value, Convert.ToBase64String(buffer2)); + Assert.AreEqual(expectedBase64Value, Convert.ToBase64String(Join(buffer2))); } } } + + private static byte[] Join(IEnumerable> chunks) + { + var buffer = new MemoryStream(); + foreach (var chunk in chunks) + { + buffer.Write(chunk.Array, chunk.Offset, chunk.Count); + } + + return buffer.ToArray(); + } } } diff --git a/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs b/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs index 2c24c483..b6b68dce 100644 --- a/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs @@ -18,7 +18,7 @@ namespace MQTTnet.Core.Tests sm.Subscribe(sp, ""); - var pp = new MqttPublishPacket + var pp = new MqttApplicationMessage { Topic = "A/B/C", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce @@ -37,7 +37,7 @@ namespace MQTTnet.Core.Tests sm.Subscribe(sp, ""); - var pp = new MqttPublishPacket + var pp = new MqttApplicationMessage { Topic = "A/B/X", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce @@ -56,7 +56,7 @@ namespace MQTTnet.Core.Tests sm.Subscribe(sp, ""); - var pp = new MqttPublishPacket + var pp = new MqttApplicationMessage { Topic = "A/B/C", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce diff --git a/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs b/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs index 3aba3c1c..301e0fec 100644 --- a/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs @@ -171,16 +171,16 @@ namespace MQTTnet.TestApp.NetCore var msgs = 0; var stopwatch = Stopwatch.StartNew(); - mqttServer.ApplicationMessageReceived += (sender, args) => - { - msgs++; - if (stopwatch.ElapsedMilliseconds > 1000) - { - Console.WriteLine($"received {msgs}"); - msgs = 0; - stopwatch.Restart(); - } - }; + ////mqttServer.ApplicationMessageReceived += (sender, args) => + ////{ + //// msgs++; + //// if (stopwatch.ElapsedMilliseconds > 1000) + //// { + //// Console.WriteLine($"received {msgs}"); + //// msgs = 0; + //// stopwatch.Restart(); + //// } + ////}; await mqttServer.StartAsync(new MqttServerOptions()); Console.WriteLine("Press any key to exit."); From 69781d822a73fd921869ffce337438be62ce728a Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Sun, 26 Nov 2017 22:57:56 +0100 Subject: [PATCH 070/149] Update docs, fix managed client connection issue --- Build/MQTTnet.nuspec | 11 ++- .../Adapter/MqttChannelAdapter.cs | 15 +++- .../ManagedClient/ManagedMqttClient.cs | 73 ++++++++++++------- .../Server/ConnectedMqttClient.cs | 7 +- .../Server/MqttClientSessionsManager.cs | 19 +++-- .../MqttNetConsoleLogger.cs | 47 +++++++----- Tests/MQTTnet.TestApp.NetCore/ServerTest.cs | 21 +++++- .../MainPage.xaml.cs | 8 +- 8 files changed, 140 insertions(+), 61 deletions(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 2ebe29de..71a9d55a 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -10,9 +10,14 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * Merged projects. -* Added a strong name for the assembly. - + * [Core] Merged projects (BREAKING CHANGE! But only namespace changes). +* [Core] Added a strong name for the assembly. +* [Core] Performance optimizations. +* [Core] Fixed a logging issue when dealing with IOExceptions. +* [Client] Fixed an issue in _ManagedClient_ which can cause the client to stop when publishing subscriptions. +* [Server] The application message interceptor can now delete any received application message. +* [Server] Added a ConnectionValidator context to align with other APIs. +* [Server] Added an interface for the _MqttServerOptions_. Copyright Christian Kratky 2016-2017 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/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index 58ab4521..bf89fabf 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Net.Sockets; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -171,13 +172,25 @@ namespace MQTTnet.Adapter } catch (COMException comException) { - if ((uint)comException.HResult == ErrorOperationAborted) + if ((uint) comException.HResult == ErrorOperationAborted) { throw new OperationCanceledException(); } throw new MqttCommunicationException(comException); } + catch (IOException exception) + { + if (exception.InnerException is SocketException socketException) + { + if (socketException.SocketErrorCode == SocketError.ConnectionAborted) + { + throw new OperationCanceledException(); + } + } + + throw new MqttCommunicationException(exception); + } catch (Exception exception) { throw new MqttCommunicationException(exception); diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs index 90db1dc5..7ae72507 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs @@ -142,33 +142,53 @@ namespace MQTTnet.ManagedClient { while (!cancellationToken.IsCancellationRequested) { - var connectionState = await ReconnectIfRequiredAsync().ConfigureAwait(false); - if (connectionState == ReconnectionResult.NotConnected) - { - _publishingCancellationToken?.Cancel(false); - _publishingCancellationToken = null; + await TryMaintainConnectionAsync(cancellationToken); + } + } + catch (OperationCanceledException) + { + } + catch (Exception exception) + { + _logger.Error(exception, "Unhandled exception while maintaining connection."); + } + finally + { + await _mqttClient.DisconnectAsync().ConfigureAwait(false); + _logger.Info("Stopped"); + } + } - await Task.Delay(_options.AutoReconnectDelay, cancellationToken).ConfigureAwait(false); - continue; - } + private async Task TryMaintainConnectionAsync(CancellationToken cancellationToken) + { + try + { + var connectionState = await ReconnectIfRequiredAsync().ConfigureAwait(false); + if (connectionState == ReconnectionResult.NotConnected) + { + _publishingCancellationToken?.Cancel(false); + _publishingCancellationToken = null; - if (connectionState == ReconnectionResult.Reconnected || _subscriptionsNotPushed) - { - await PushSubscriptionsAsync(); + await Task.Delay(_options.AutoReconnectDelay, cancellationToken).ConfigureAwait(false); + return; + } - _publishingCancellationToken = new CancellationTokenSource(); + if (connectionState == ReconnectionResult.Reconnected || _subscriptionsNotPushed) + { + await PushSubscriptionsAsync().ConfigureAwait(false); + + _publishingCancellationToken = new CancellationTokenSource(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - Task.Run(async () => await PublishQueuedMessagesAsync(_publishingCancellationToken.Token), _publishingCancellationToken.Token).ConfigureAwait(false); + Task.Run(async () => await PublishQueuedMessagesAsync(_publishingCancellationToken.Token).ConfigureAwait(false), _publishingCancellationToken.Token).ConfigureAwait(false); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - continue; - } + return; + } - if (connectionState == ReconnectionResult.StillConnected) - { - await Task.Delay(TimeSpan.FromSeconds(1), _connectionCancellationToken.Token).ConfigureAwait(false); - } + if (connectionState == ReconnectionResult.StillConnected) + { + await Task.Delay(TimeSpan.FromSeconds(1), _connectionCancellationToken.Token).ConfigureAwait(false); } } catch (OperationCanceledException) @@ -182,11 +202,6 @@ namespace MQTTnet.ManagedClient { _logger.Error(exception, "Unhandled exception while maintaining connection."); } - finally - { - await _mqttClient.DisconnectAsync().ConfigureAwait(false); - _logger.Info("Stopped"); - } } private async Task PublishQueuedMessagesAsync(CancellationToken cancellationToken) @@ -206,16 +221,19 @@ namespace MQTTnet.ManagedClient continue; } - await TryPublishQueuedMessageAsync(message).ConfigureAwait(false); - await _storageManager.RemoveAsync(message).ConfigureAwait(false); + await TryPublishQueuedMessageAsync(message).ConfigureAwait(false); } } catch (OperationCanceledException) { } + catch (Exception exception) + { + _logger.Error(exception, "Unhandled exception while publishing queued application messages."); + } finally { - _logger.Info("Stopped publishing messages"); + _logger.Trace("Stopped publishing messages."); } } @@ -224,6 +242,7 @@ namespace MQTTnet.ManagedClient try { await _mqttClient.PublishAsync(message).ConfigureAwait(false); + await _storageManager.RemoveAsync(message).ConfigureAwait(false); } catch (MqttCommunicationException exception) { diff --git a/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs index ea1c7465..ee3a55fb 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs @@ -1,4 +1,5 @@ -using MQTTnet.Serializer; +using System; +using MQTTnet.Serializer; namespace MQTTnet.Server { @@ -7,5 +8,9 @@ namespace MQTTnet.Server public string ClientId { get; set; } public MqttProtocolVersion ProtocolVersion { get; set; } + + public TimeSpan LastPacketReceivedDuration { get; set; } + + public TimeSpan LastNonKeepAlivePacketReceivedDuration{ get; set; } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index defe5ebc..870e5e09 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -120,6 +120,7 @@ namespace MQTTnet.Server await _sessionsSemaphore.WaitAsync().ConfigureAwait(false); try { + var now = DateTime.UtcNow; return _sessions.Where(s => s.Value.IsConnected).Select(s => new ConnectedMqttClient { ClientId = s.Value.ClientId, @@ -136,13 +137,21 @@ namespace MQTTnet.Server { try { - var interceptorContext = new MqttApplicationMessageInterceptorContext + if (_options.ApplicationMessageInterceptor != null) { - ApplicationMessage = applicationMessage - }; + var interceptorContext = new MqttApplicationMessageInterceptorContext + { + ApplicationMessage = applicationMessage + }; - _options.ApplicationMessageInterceptor?.Invoke(interceptorContext); - applicationMessage = interceptorContext.ApplicationMessage; + _options.ApplicationMessageInterceptor(interceptorContext); + applicationMessage = interceptorContext.ApplicationMessage; + } + + if (applicationMessage == null) + { + return; + } if (applicationMessage.Retain) { diff --git a/Tests/MQTTnet.TestApp.NetCore/MqttNetConsoleLogger.cs b/Tests/MQTTnet.TestApp.NetCore/MqttNetConsoleLogger.cs index 67eb69e7..2713aa3a 100644 --- a/Tests/MQTTnet.TestApp.NetCore/MqttNetConsoleLogger.cs +++ b/Tests/MQTTnet.TestApp.NetCore/MqttNetConsoleLogger.cs @@ -14,6 +14,17 @@ namespace MQTTnet.TestApp.NetCore MqttNetGlobalLogger.LogMessagePublished += PrintToConsole; } + public static void PrintToConsole(string message, ConsoleColor color) + { + lock (Lock) + { + var backupColor = Console.ForegroundColor; + Console.ForegroundColor = color; + Console.Write(message); + Console.ForegroundColor = backupColor; + } + } + private static void PrintToConsole(object sender, MqttNetLogMessagePublishedEventArgs e) { var output = new StringBuilder(); @@ -23,28 +34,24 @@ namespace MQTTnet.TestApp.NetCore output.AppendLine(e.TraceMessage.Exception.ToString()); } - lock (Lock) + var color = ConsoleColor.Red; + switch (e.TraceMessage.Level) { - var backupColor = Console.ForegroundColor; - switch (e.TraceMessage.Level) - { - case MqttNetLogLevel.Error: - Console.ForegroundColor = ConsoleColor.Red; - break; - case MqttNetLogLevel.Warning: - Console.ForegroundColor = ConsoleColor.Yellow; - break; - case MqttNetLogLevel.Info: - Console.ForegroundColor = ConsoleColor.Green; - break; - case MqttNetLogLevel.Verbose: - Console.ForegroundColor = ConsoleColor.Gray; - break; - } - - Console.Write(output); - Console.ForegroundColor = backupColor; + case MqttNetLogLevel.Error: + color = ConsoleColor.Red; + break; + case MqttNetLogLevel.Warning: + color = ConsoleColor.Yellow; + break; + case MqttNetLogLevel.Info: + color = ConsoleColor.Green; + break; + case MqttNetLogLevel.Verbose: + color = ConsoleColor.Gray; + break; } + + PrintToConsole(output.ToString(), color); } } } \ No newline at end of file diff --git a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs index d4960d06..8f89176c 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs @@ -1,9 +1,9 @@ using System; using System.Text; using System.Threading.Tasks; -using MQTTnet.Diagnostics; using MQTTnet.Protocol; using MQTTnet.Server; +using Newtonsoft.Json.Linq; namespace MQTTnet.TestApp.NetCore { @@ -63,6 +63,25 @@ namespace MQTTnet.TestApp.NetCore //options.TlsEndpointOptions.IsEnabled = false; var mqttServer = new MqttFactory().CreateMqttServer(); + + mqttServer.ApplicationMessageReceived += (s, e) => + { + MqttNetConsoleLogger.PrintToConsole( + $"'{e.ClientId}' reported '{e.ApplicationMessage.Topic}' > '{Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}'", + ConsoleColor.Magenta); + }; + + options.ApplicationMessageInterceptor = c => + { + var content = JObject.Parse(Encoding.UTF8.GetString(c.ApplicationMessage.Payload)); + var timestampProperty = content.Property("timestamp"); + if (timestampProperty != null && timestampProperty.Value.Type == JTokenType.Null) + { + timestampProperty.Value = DateTime.Now.ToString("O"); + c.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(content.ToString()); + } + }; + mqttServer.ClientDisconnected += (s, e) => { Console.Write("Client disconnected event fired."); diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index a750b274..00c6ffae 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -407,12 +407,14 @@ namespace MQTTnet.TestApp.UniversalWindows { // Configure MQTT server. + var optionsBuilder = new MqttServerOptionsBuilder() + .WithConnectionBacklog(100) + .WithDefaultEndpointPort(1884); + var options = new MqttServerOptions { - ConnectionBacklog = 100 }; - options.DefaultEndpointOptions.Port = 1884; options.ConnectionValidator = c => { if (c.ClientId != "Highlander") @@ -425,7 +427,7 @@ namespace MQTTnet.TestApp.UniversalWindows }; var mqttServer = new MqttFactory().CreateMqttServer(); - await mqttServer.StartAsync(options); + await mqttServer.StartAsync(optionsBuilder.Build()); } { From bc959a8c3dcb676b72ae40768cc58da54d587090 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Mon, 27 Nov 2017 00:25:45 +0100 Subject: [PATCH 071/149] Performance optimizations --- .../MQTTnet.AspnetCore.csproj | 4 ++ .../Adapter/MqttChannelAdapter.cs | 12 ++-- .../Internal/TaskExtensions.cs | 18 +++--- .../MQTTnet.Netstandard.csproj | 4 ++ .../Server/MqttClientSession.cs | 10 ++-- .../Server/MqttClientSessionsManager.cs | 2 +- README.md | 2 +- .../PerformanceTest.cs | 56 +++++-------------- 8 files changed, 46 insertions(+), 62 deletions(-) diff --git a/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj b/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj index 5556b11c..fbde3f2b 100644 --- a/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj +++ b/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj @@ -6,6 +6,10 @@ 2.5.2.0 + + RELEASE;NETSTANDARD2_0 + + diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index bf89fabf..2a9815d4 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -31,23 +31,23 @@ namespace MQTTnet.Adapter public IMqttPacketSerializer PacketSerializer { get; } - public async Task ConnectAsync(TimeSpan timeout) + public Task ConnectAsync(TimeSpan timeout) { _logger.Info("Connecting [Timeout={0}]", timeout); - await ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout)); + return ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout)); } - public async Task DisconnectAsync(TimeSpan timeout) + public Task DisconnectAsync(TimeSpan timeout) { _logger.Info("Disconnecting [Timeout={0}]", timeout); - await ExecuteAndWrapExceptionAsync(() => _channel.DisconnectAsync().TimeoutAfter(timeout)); + return ExecuteAndWrapExceptionAsync(() => _channel.DisconnectAsync().TimeoutAfter(timeout)); } - public async Task SendPacketsAsync(TimeSpan timeout, CancellationToken cancellationToken, IEnumerable packets) + public Task SendPacketsAsync(TimeSpan timeout, CancellationToken cancellationToken, IEnumerable packets) { - await ExecuteAndWrapExceptionAsync(async () => + return ExecuteAndWrapExceptionAsync(async () => { await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try diff --git a/Frameworks/MQTTnet.NetStandard/Internal/TaskExtensions.cs b/Frameworks/MQTTnet.NetStandard/Internal/TaskExtensions.cs index 6acb71ef..bfa01bdb 100644 --- a/Frameworks/MQTTnet.NetStandard/Internal/TaskExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/Internal/TaskExtensions.cs @@ -9,13 +9,15 @@ namespace MQTTnet.Internal { public static async Task TimeoutAfter(this Task task, TimeSpan timeout) { - using (var cancellationTokenSource = new CancellationTokenSource()) + if (task == null) throw new ArgumentNullException(nameof(task)); + + using (var timeoutCts = new CancellationTokenSource()) { try { - var timeoutTask = Task.Delay(timeout, cancellationTokenSource.Token); + var timeoutTask = Task.Delay(timeout, timeoutCts.Token); var finishedTask = await Task.WhenAny(timeoutTask, task).ConfigureAwait(false); - + if (finishedTask == timeoutTask) { throw new MqttCommunicationTimedOutException(); @@ -33,18 +35,20 @@ namespace MQTTnet.Internal } finally { - cancellationTokenSource.Cancel(); + timeoutCts.Cancel(); } } } public static async Task TimeoutAfter(this Task task, TimeSpan timeout) { - using (var cancellationTokenSource = new CancellationTokenSource()) + if (task == null) throw new ArgumentNullException(nameof(task)); + + using (var timeoutCts = new CancellationTokenSource()) { try { - var timeoutTask = Task.Delay(timeout, cancellationTokenSource.Token); + var timeoutTask = Task.Delay(timeout, timeoutCts.Token); var finishedTask = await Task.WhenAny(timeoutTask, task).ConfigureAwait(false); if (finishedTask == timeoutTask) @@ -66,7 +70,7 @@ namespace MQTTnet.Internal } finally { - cancellationTokenSource.Cancel(); + timeoutCts.Cancel(); } } } diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj index f4018cb5..abcc8658 100644 --- a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -36,6 +36,10 @@ + + RELEASE;NETSTANDARD1_3 + + diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index 275fcb1b..c5f16a9e 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -143,16 +143,16 @@ namespace MQTTnet.Server private Task ProcessReceivedPacketAsync(IMqttChannelAdapter adapter, MqttBasePacket packet, CancellationToken cancellationToken) { - if (packet is MqttPingReqPacket) - { - return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttPingRespPacket()); - } - if (packet is MqttPublishPacket publishPacket) { return HandleIncomingPublishPacketAsync(adapter, publishPacket, cancellationToken); } + if (packet is MqttPingReqPacket) + { + return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttPingRespPacket()); + } + if (packet is MqttPubRelPacket pubRelPacket) { return HandleIncomingPubRelPacketAsync(adapter, pubRelPacket, cancellationToken); diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index 870e5e09..f65ed2ba 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -168,7 +168,7 @@ namespace MQTTnet.Server lock (_sessions) { - foreach (var clientSession in _sessions.Values.ToList()) + foreach (var clientSession in _sessions.Values) { clientSession.EnqueueApplicationMessage(applicationMessage); } diff --git a/README.md b/README.md index 57dfce2e..5d3e1867 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov * TLS 1.2 support for client and server (but not UWP servers) * Extensible communication channels (i.e. In-Memory, TCP, TCP+TLS, WS) * Lightweight (only the low level implementation of MQTT, no overhead) -* Performance optimized (processing ~27.000 messages / second)* +* Performance optimized (processing ~30.000 messages / second)* * Interfaces included for mocking and testing * Access to internal trace messages * Unit tested (70+ tests) diff --git a/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs b/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs index 301e0fec..1c72b06a 100644 --- a/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs @@ -43,33 +43,6 @@ namespace MQTTnet.TestApp.NetCore var client = new MqttFactory().CreateMqttClient(); - client.Connected += async (s, e) => - { - Console.WriteLine("### CONNECTED WITH SERVER ###"); - - await client.SubscribeAsync(new List - { - new TopicFilter("#") - }); - - Console.WriteLine("### SUBSCRIBED ###"); - }; - - client.Disconnected += async (s, e) => - { - Console.WriteLine("### DISCONNECTED FROM SERVER ###"); - await Task.Delay(TimeSpan.FromSeconds(5)); - - try - { - await client.ConnectAsync(options); - } - catch - { - Console.WriteLine("### RECONNECTING FAILED ###"); - } - }; - try { await client.ConnectAsync(options); @@ -79,24 +52,12 @@ namespace MQTTnet.TestApp.NetCore Console.WriteLine("### CONNECTING FAILED ###" + Environment.NewLine + exception); } - Console.WriteLine("### WAITING FOR APPLICATION MESSAGES ###"); - - var testMessageCount = 10000; var message = CreateMessage(); - var stopwatch = Stopwatch.StartNew(); - for (var i = 0; i < testMessageCount; i++) - { - await client.PublishAsync(message); - } - - stopwatch.Stop(); - Console.WriteLine($"Sent 10.000 messages within {stopwatch.ElapsedMilliseconds} ms ({stopwatch.ElapsedMilliseconds / (float)testMessageCount} ms / message)."); - var messages = new[] { message }; + + var stopwatch = Stopwatch.StartNew(); + var sentMessagesCount = 0; - - stopwatch.Restart(); - while (stopwatch.ElapsedMilliseconds < 1000) { await client.PublishAsync(messages).ConfigureAwait(false); @@ -104,6 +65,17 @@ namespace MQTTnet.TestApp.NetCore } Console.WriteLine($"Sending {sentMessagesCount} messages per second."); + + stopwatch.Restart(); + + var testMessageCount = 10000; + for (var i = 0; i < testMessageCount; i++) + { + await client.PublishAsync(message); + } + + stopwatch.Stop(); + Console.WriteLine($"Sent 10.000 messages within {stopwatch.ElapsedMilliseconds} ms ({stopwatch.ElapsedMilliseconds / (float)testMessageCount} ms / message)."); var last = DateTime.Now; var msgCount = 0; From 0ee3c8e135261567ac5755aa262c586039e4a3e9 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 28 Nov 2017 21:19:30 +0100 Subject: [PATCH 072/149] Add statistics of last sent packets to the _ConnectedClient_. --- .../Adapter/MqttChannelAdapter.cs | 4 +- .../MQTTnet.NetStandard/Client/MqttClient.cs | 58 ++++++---------- .../Diagnostics/MqttNetLogger.cs | 2 +- .../Implementations/MqttServerAdapter.cs | 39 +++++++++-- .../Server/ConnectedMqttClient.cs | 4 +- .../Server/MqttClientSession.cs | 69 ++++++++++++++----- .../Server/MqttClientSessionsManager.cs | 5 +- Tests/MQTTnet.TestApp.NetCore/Program.cs | 24 ++++++- 8 files changed, 137 insertions(+), 68 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index 2a9815d4..af399583 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -33,14 +33,14 @@ namespace MQTTnet.Adapter public Task ConnectAsync(TimeSpan timeout) { - _logger.Info("Connecting [Timeout={0}]", timeout); + _logger.Trace("Connecting [Timeout={0}]", timeout); return ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout)); } public Task DisconnectAsync(TimeSpan timeout) { - _logger.Info("Disconnecting [Timeout={0}]", timeout); + _logger.Trace("Disconnecting [Timeout={0}]", timeout); return ExecuteAndWrapExceptionAsync(() => _channel.DisconnectAsync().TimeoutAfter(timeout)); } diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs index a24fbff9..b7658705 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs @@ -14,8 +14,6 @@ namespace MQTTnet.Client { public class MqttClient : IMqttClient { - private readonly HashSet _unacknowledgedPublishPackets = new HashSet(); - private readonly IMqttClientAdapterFactory _adapterFactory; private readonly MqttPacketDispatcher _packetDispatcher; private readonly IMqttNetLogger _logger; @@ -133,7 +131,7 @@ namespace MQTTnet.Client TopicFilters = topicFilters.ToList() }; - await SendAndReceiveAsync(unsubscribePacket); + await SendAndReceiveAsync(unsubscribePacket).ConfigureAwait(false); } public async Task PublishAsync(IEnumerable applicationMessages) @@ -141,21 +139,21 @@ namespace MQTTnet.Client ThrowIfNotConnected(); var publishPackets = applicationMessages.Select(m => m.ToPublishPacket()); + var packetGroups = publishPackets.GroupBy(p => p.QualityOfServiceLevel).OrderBy(g => g.Key); - foreach (var qosGroup in publishPackets.GroupBy(p => p.QualityOfServiceLevel)) + foreach (var qosGroup in packetGroups) { - var qosPackets = qosGroup.ToArray(); switch (qosGroup.Key) { case MqttQualityOfServiceLevel.AtMostOnce: { // No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier] - await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, qosPackets).ConfigureAwait(false); + await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, qosGroup).ConfigureAwait(false); break; } case MqttQualityOfServiceLevel.AtLeastOnce: { - foreach (var publishPacket in qosPackets) + foreach (var publishPacket in qosGroup) { publishPacket.PacketIdentifier = GetNewPacketIdentifier(); await SendAndReceiveAsync(publishPacket).ConfigureAwait(false); @@ -165,7 +163,7 @@ namespace MQTTnet.Client } case MqttQualityOfServiceLevel.ExactlyOnce: { - foreach (var publishPacket in qosPackets) + foreach (var publishPacket in qosGroup) { publishPacket.PacketIdentifier = GetNewPacketIdentifier(); var pubRecPacket = await SendAndReceiveAsync(publishPacket).ConfigureAwait(false); @@ -249,28 +247,28 @@ namespace MQTTnet.Client try { _logger.Info("Received <<< {0}", packet); + + if (packet is MqttPublishPacket publishPacket) + { + await ProcessReceivedPublishPacketAsync(publishPacket).ConfigureAwait(false); + return; + } if (packet is MqttPingReqPacket) { - await SendAsync(new MqttPingRespPacket()); + await SendAsync(new MqttPingRespPacket()).ConfigureAwait(false); return; } if (packet is MqttDisconnectPacket) { - await DisconnectAsync(); - return; - } - - if (packet is MqttPublishPacket publishPacket) - { - await ProcessReceivedPublishPacket(publishPacket); + await DisconnectAsync().ConfigureAwait(false); return; } if (packet is MqttPubRelPacket pubRelPacket) { - await ProcessReceivedPubRelPacket(pubRelPacket); + await ProcessReceivedPubRelPacket(pubRelPacket).ConfigureAwait(false); return; } @@ -295,32 +293,25 @@ namespace MQTTnet.Client } } - private async Task ProcessReceivedPublishPacket(MqttPublishPacket publishPacket) + private Task ProcessReceivedPublishPacketAsync(MqttPublishPacket publishPacket) { if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce) { FireApplicationMessageReceivedEvent(publishPacket); - return; + return Task.FromResult(0); } if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce) { FireApplicationMessageReceivedEvent(publishPacket); - await SendAsync(new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }); - return; + return SendAsync(new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }); } if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce) { // QoS 2 is implement as method "B" [4.3.3 QoS 2: Exactly once delivery] - lock (_unacknowledgedPublishPackets) - { - _unacknowledgedPublishPackets.Add(publishPacket.PacketIdentifier); - } - FireApplicationMessageReceivedEvent(publishPacket); - await SendAsync(new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }); - return; + return SendAsync(new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }); } throw new MqttCommunicationException("Received a not supported QoS level."); @@ -328,11 +319,6 @@ namespace MQTTnet.Client private Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket) { - lock (_unacknowledgedPublishPackets) - { - _unacknowledgedPublishPackets.Remove(pubRelPacket.PacketIdentifier); - } - return SendAsync(pubRelPacket.CreateResponse()); } @@ -454,7 +440,7 @@ namespace MQTTnet.Client { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed Task.Run( - () => ProcessReceivedPacketAsync(packet), + async () => await ProcessReceivedPacketAsync(packet).ConfigureAwait(false), cancellationToken).ConfigureAwait(false); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } @@ -465,7 +451,7 @@ namespace MQTTnet.Client #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed Task.Run( - async () => await ReceivePacketsAsync(cancellationToken), + async () => await ReceivePacketsAsync(cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed @@ -479,7 +465,7 @@ namespace MQTTnet.Client { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed Task.Run( - async () => await SendKeepAliveMessagesAsync(cancellationToken), + async () => await SendKeepAliveMessagesAsync(cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } diff --git a/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogger.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogger.cs index 7d9b2907..8ad1d4c4 100644 --- a/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogger.cs +++ b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogger.cs @@ -10,7 +10,7 @@ namespace MQTTnet.Diagnostics { _logId = logId; } - + public event EventHandler LogMessagePublished; public void Trace(string message, params object[] parameters) diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs index d4ab0950..a0441bcc 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs @@ -42,7 +42,7 @@ namespace MQTTnet.Implementations _defaultEndpointSocket.Bind(new IPEndPoint(IPAddress.Any, options.GetDefaultEndpointPort())); _defaultEndpointSocket.Listen(options.ConnectionBacklog); - Task.Run(() => AcceptDefaultEndpointConnectionsAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token); + Task.Run(async () => await AcceptDefaultEndpointConnectionsAsync(_cancellationTokenSource.Token).ConfigureAwait(false), _cancellationTokenSource.Token).ConfigureAwait(false); } if (options.TlsEndpointOptions.IsEnabled) @@ -62,7 +62,7 @@ namespace MQTTnet.Implementations _tlsEndpointSocket.Bind(new IPEndPoint(IPAddress.Any, options.GetTlsEndpointPort())); _tlsEndpointSocket.Listen(options.ConnectionBacklog); - Task.Run(() => AcceptTlsEndpointConnectionsAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token); + Task.Run(async () => await AcceptTlsEndpointConnectionsAsync(_cancellationTokenSource.Token).ConfigureAwait(false), _cancellationTokenSource.Token).ConfigureAwait(false); } return Task.FromResult(0); @@ -102,13 +102,29 @@ namespace MQTTnet.Implementations #else var clientSocket = await _defaultEndpointSocket.AcceptAsync().ConfigureAwait(false); #endif + var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, null), new MqttPacketSerializer(), _logger); ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); } + catch (ObjectDisposedException) + { + // It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed. + } + catch (SocketException exception) + { + if (exception.SocketErrorCode == SocketError.OperationAborted) + { + return; + } + + _logger.Error(exception, "Error while accepting connection at default endpoint."); + } catch (Exception exception) { _logger.Error(exception, "Error while accepting connection at default endpoint."); - + } + finally + { //excessive CPU consumed if in endless loop of socket errors await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); } @@ -133,10 +149,25 @@ namespace MQTTnet.Implementations var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, sslStream), new MqttPacketSerializer(), _logger); ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); } + catch (ObjectDisposedException) + { + // It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed. + } + catch (SocketException exception) + { + if (exception.SocketErrorCode == SocketError.OperationAborted) + { + return; + } + + _logger.Error(exception, "Error while accepting connection at default endpoint."); + } catch (Exception exception) { _logger.Error(exception, "Error while accepting connection at TLS endpoint."); - + } + finally + { //excessive CPU consumed if in endless loop of socket errors await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); } diff --git a/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs index ee3a55fb..cd941930 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs @@ -9,8 +9,8 @@ namespace MQTTnet.Server public MqttProtocolVersion ProtocolVersion { get; set; } - public TimeSpan LastPacketReceivedDuration { get; set; } + public TimeSpan LastPacketReceived { get; set; } - public TimeSpan LastNonKeepAlivePacketReceivedDuration{ get; set; } + public TimeSpan LastNonKeepAlivePacketReceived { get; set; } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index c5f16a9e..12ef891a 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using MQTTnet.Adapter; @@ -13,6 +14,9 @@ namespace MQTTnet.Server { public sealed class MqttClientSession { + private readonly Stopwatch _lastPacketReceivedTracker = new Stopwatch(); + private readonly Stopwatch _lastNonKeepAlivePacketReceivedTracker = new Stopwatch(); + private readonly MqttClientSubscriptionsManager _subscriptionsManager; private readonly MqttClientSessionsManager _sessionsManager; private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue; @@ -44,6 +48,10 @@ namespace MQTTnet.Server public MqttProtocolVersion? ProtocolVersion => _adapter?.PacketSerializer.ProtocolVersion; + public TimeSpan LastPacketReceived => _lastPacketReceivedTracker.Elapsed; + + public TimeSpan LastNonKeepAlivePacketReceived => _lastNonKeepAlivePacketReceivedTracker.Elapsed; + public bool IsConnected => _adapter != null; public async Task RunAsync(MqttApplicationMessage willMessage, IMqttChannelAdapter adapter) @@ -52,6 +60,9 @@ namespace MQTTnet.Server try { + _lastPacketReceivedTracker.Restart(); + _lastNonKeepAlivePacketReceivedTracker.Restart(); + var cancellationTokenSource = new CancellationTokenSource(); _willMessage = willMessage; @@ -78,6 +89,11 @@ namespace MQTTnet.Server { try { + if (_cancellationTokenSource == null) + { + return; + } + _cancellationTokenSource?.Cancel(false); _cancellationTokenSource?.Dispose(); _cancellationTokenSource = null; @@ -143,6 +159,13 @@ namespace MQTTnet.Server private Task ProcessReceivedPacketAsync(IMqttChannelAdapter adapter, MqttBasePacket packet, CancellationToken cancellationToken) { + _lastPacketReceivedTracker.Restart(); + + if (!(packet is MqttPingReqPacket)) + { + _lastNonKeepAlivePacketReceivedTracker.Restart(); + } + if (packet is MqttPublishPacket publishPacket) { return HandleIncomingPublishPacketAsync(adapter, publishPacket, cancellationToken); @@ -185,7 +208,7 @@ namespace MQTTnet.Server } _logger.Warning("Client '{0}': Received not supported packet ({1}). Closing connection.", ClientId, packet); - return StopAsync(); + return StopAsync(); } private async Task HandleIncomingSubscribePacketAsync(IMqttChannelAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken) @@ -211,7 +234,7 @@ namespace MQTTnet.Server } } - private async Task HandleIncomingPublishPacketAsync(IMqttChannelAdapter adapter, MqttPublishPacket publishPacket, CancellationToken cancellationToken) + private Task HandleIncomingPublishPacketAsync(IMqttChannelAdapter adapter, MqttPublishPacket publishPacket, CancellationToken cancellationToken) { var applicationMessage = publishPacket.ToApplicationMessage(); @@ -219,36 +242,44 @@ namespace MQTTnet.Server { case MqttQualityOfServiceLevel.AtMostOnce: { - await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false); - return; + return _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage); } case MqttQualityOfServiceLevel.AtLeastOnce: { - await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false); - - await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, - new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }).ConfigureAwait(false); - - return; + return HandleIncomingPublishPacketWithQoS1(adapter, applicationMessage, publishPacket, cancellationToken); } case MqttQualityOfServiceLevel.ExactlyOnce: { - // QoS 2 is implement as method "B" [4.3.3 QoS 2: Exactly once delivery] - await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false); - - await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, - new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }).ConfigureAwait(false); - - return; + return HandleIncomingPublishPacketWithQoS2(adapter, applicationMessage, publishPacket, cancellationToken); } default: - throw new MqttCommunicationException("Received a not supported QoS level."); + { + throw new MqttCommunicationException("Received a not supported QoS level."); + } } } + private async Task HandleIncomingPublishPacketWithQoS1(IMqttChannelAdapter adapter, MqttApplicationMessage applicationMessage, MqttPublishPacket publishPacket, CancellationToken cancellationToken) + { + await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false); + + var response = new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }; + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response).ConfigureAwait(false); + } + + private async Task HandleIncomingPublishPacketWithQoS2(IMqttChannelAdapter adapter, MqttApplicationMessage applicationMessage, MqttPublishPacket publishPacket, CancellationToken cancellationToken) + { + // QoS 2 is implement as method "B" [4.3.3 QoS 2: Exactly once delivery] + await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false); + + var response = new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }; + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response).ConfigureAwait(false); + } + private Task HandleIncomingPubRelPacketAsync(IMqttChannelAdapter adapter, MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken) { - return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier }); + var response = new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier }; + return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response); } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index f65ed2ba..5bb65984 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -120,11 +120,12 @@ namespace MQTTnet.Server await _sessionsSemaphore.WaitAsync().ConfigureAwait(false); try { - var now = DateTime.UtcNow; return _sessions.Where(s => s.Value.IsConnected).Select(s => new ConnectedMqttClient { ClientId = s.Value.ClientId, - ProtocolVersion = s.Value.ProtocolVersion ?? MqttProtocolVersion.V311 + ProtocolVersion = s.Value.ProtocolVersion ?? MqttProtocolVersion.V311, + LastPacketReceived = s.Value.LastPacketReceived, + LastNonKeepAlivePacketReceived = s.Value.LastNonKeepAlivePacketReceived }).ToList(); } finally diff --git a/Tests/MQTTnet.TestApp.NetCore/Program.cs b/Tests/MQTTnet.TestApp.NetCore/Program.cs index 0e4868af..77b9ea6e 100644 --- a/Tests/MQTTnet.TestApp.NetCore/Program.cs +++ b/Tests/MQTTnet.TestApp.NetCore/Program.cs @@ -40,7 +40,7 @@ namespace MQTTnet.TestApp.NetCore Thread.Sleep(Timeout.Infinite); } - + // This code is used at the Wiki on GitHub! // ReSharper disable once UnusedMember.Local private static async void WikiCode() @@ -71,6 +71,26 @@ namespace MQTTnet.TestApp.NetCore var factory = new MqttFactory(); var client = factory.CreateMqttClient(); } + + { + // Write all trace messages to the console window. + MqttNetGlobalLogger.LogMessagePublished += (s, e) => + { + var trace = $">> [{e.TraceMessage.Timestamp:O}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}"; + if (e.TraceMessage.Exception != null) + { + trace += Environment.NewLine + e.TraceMessage.Exception.ToString(); + } + + Console.WriteLine(trace); + }; + } + + { + // Use a custom log ID for the logger. + var factory = new MqttFactory(); + var mqttClient = factory.CreateMqttClient(new MqttNetLogger("MyCustomId")); + } } } @@ -106,4 +126,4 @@ namespace MQTTnet.TestApp.NetCore return Task.FromResult(retainedMessages); } } -} +} \ No newline at end of file From d12d2648b7eed47ca839550e0e6dfd4ea9a446f4 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Mon, 4 Dec 2017 10:21:37 +0100 Subject: [PATCH 073/149] Add extension for RPC calls; replace locks; Refactored storage in Managed Client --- Build/MQTTnet.nuspec | 6 +- .../MQTTnet.Extensions.Rpc.csproj | 30 ++++ .../MQTTnet.Extensions.Rpc/MqttRpcClient.cs | 101 +++++++++++++ .../MQTTnet.AspnetCore.csproj | 9 +- .../Adapter/MqttChannelAdapter.cs | 49 +++--- .../Adapter/ReceivedMqttPacket.cs | 12 +- .../Implementations/MqttTcpChannel.cs | 7 +- .../MQTTnet.Netstandard.csproj | 5 +- .../ManagedClient/ManagedMqttClient.cs | 57 ++++--- .../ManagedMqttClientStorageManager.cs | 32 ++-- .../Serializer/IMqttPacketSerializer.cs | 5 +- .../Serializer/MqttPacketReader.cs | 25 ++-- .../Serializer/MqttPacketSerializer.cs | 15 +- .../Server/MqttClientSession.cs | 43 ++++-- .../Server/MqttClientSessionsManager.cs | 71 ++++----- .../Server/MqttClientSubscriptionsManager.cs | 113 ++++++++++---- .../Server/MqttRetainedMessagesManager.cs | 14 +- .../MQTTnet.NetStandard/Server/MqttServer.cs | 59 ++++---- .../MqttSubscriptionInterceptorContext.cs | 8 +- Frameworks/MQTTnet.NetStandard/TopicFilter.cs | 2 +- MQTTnet.sln | 23 ++- .../MqttPacketSerializerTests.cs | 3 +- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 8 +- .../MqttSubscriptionsManagerTests.cs | 67 +++++++-- Tests/MQTTnet.TestApp.NetCore/ClientTest.cs | 6 +- .../MQTTnet.TestApp.NetCore.csproj | 4 + .../PerformanceTest.cs | 17 ++- Tests/MQTTnet.TestApp.NetCore/ServerTest.cs | 24 ++- .../MQTTnet.TestApp.UniversalWindows.csproj | 4 + .../MainPage.xaml | 38 ++++- .../MainPage.xaml.cs | 140 ++++++++++++------ 31 files changed, 690 insertions(+), 307 deletions(-) create mode 100644 Extensions/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj create mode 100644 Extensions/MQTTnet.Extensions.Rpc/MqttRpcClient.cs diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 71a9d55a..302b128a 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -14,10 +14,14 @@ * [Core] Added a strong name for the assembly. * [Core] Performance optimizations. * [Core] Fixed a logging issue when dealing with IOExceptions. +* [Core] Fixed a typo in the global logger class (BREAKING CHANGE! Please find new example in Wiki). * [Client] Fixed an issue in _ManagedClient_ which can cause the client to stop when publishing subscriptions. * [Server] The application message interceptor can now delete any received application message. -* [Server] Added a ConnectionValidator context to align with other APIs. +* [Server] Added a ConnectionValidator context to align with other APIs (BREAKING CHANGE! Please find new example in Wiki). * [Server] Added an interface for the _MqttServerOptions_. +* [Server] Added packet statistics for the connected clients. +* [Server] Fixed a security issue which sends retained packages to a failed subscription. +* [Server] Fixed the response (MaximumQoS) of a subscription (Thanks to @redbeans2017). Copyright Christian Kratky 2016-2017 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/Extensions/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj b/Extensions/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj new file mode 100644 index 00000000..fd16072b --- /dev/null +++ b/Extensions/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj @@ -0,0 +1,30 @@ + + + + netstandard1.3;netstandard2.0;net452;net461;uap10.0 + 0.0.0.0 + 0.0.0.0 + + + + + 0.0.0.0 + + + + false + UAP,Version=v10.0 + UAP + 10.0.16299.0 + 10.0.10240.0 + .NETCore + v5.0 + $(DefineConstants);WINDOWS_UWP + $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets + + + + + + + diff --git a/Extensions/MQTTnet.Extensions.Rpc/MqttRpcClient.cs b/Extensions/MQTTnet.Extensions.Rpc/MqttRpcClient.cs new file mode 100644 index 00000000..6a9d1c1c --- /dev/null +++ b/Extensions/MQTTnet.Extensions.Rpc/MqttRpcClient.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Concurrent; +using System.Threading.Tasks; +using MQTTnet.Client; +using MQTTnet.Internal; +using MQTTnet.Protocol; + +namespace MQTTnet.Extensions.Rpc +{ + public sealed class MqttRpcClient : IDisposable + { + private const string ResponseTopic = "$RPC/+/+/response"; + private readonly ConcurrentDictionary> _waitingCalls = new ConcurrentDictionary>(); + private readonly IMqttClient _mqttClient; + private bool _isEnabled; + + public MqttRpcClient(IMqttClient mqttClient) + { + _mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient)); + + _mqttClient.ApplicationMessageReceived += OnApplicationMessageReceived; + } + + public async Task EnableAsync() + { + await _mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(ResponseTopic).WithAtLeastOnceQoS().Build()); + _isEnabled = true; + } + + public async Task DisableAsync() + { + await _mqttClient.UnsubscribeAsync(ResponseTopic); + _isEnabled = false; + } + + public async Task ExecuteAsync(TimeSpan timeout, string methodName, byte[] payload, MqttQualityOfServiceLevel qualityOfServiceLevel) + { + if (methodName == null) throw new ArgumentNullException(nameof(methodName)); + + if (methodName.Contains("/") || methodName.Contains("+") || methodName.Contains("#")) + { + throw new ArgumentException("The method name cannot contain /, + or #."); + } + + if (!_isEnabled) + { + throw new InvalidOperationException("The RPC client is not enabled."); + } + + var requestTopic = $"$MQTTnet.RPC/{Guid.NewGuid():N}/{methodName}"; + var responseTopic = requestTopic + "/response"; + + var requestMessage = new MqttApplicationMessageBuilder() + .WithTopic(requestTopic) + .WithPayload(payload) + .WithQualityOfServiceLevel(qualityOfServiceLevel) + .Build(); + + try + { + var tcs = new TaskCompletionSource(); + if (!_waitingCalls.TryAdd(responseTopic, tcs)) + { + throw new InvalidOperationException(); + } + + await _mqttClient.PublishAsync(requestMessage); + return await tcs.Task.TimeoutAfter(timeout); + } + finally + { + _waitingCalls.TryRemove(responseTopic, out _); + } + } + + private void OnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs eventArgs) + { + if (!_waitingCalls.TryRemove(eventArgs.ApplicationMessage.Topic, out TaskCompletionSource tcs)) + { + return; + } + + if (tcs.Task.IsCompleted || tcs.Task.IsCanceled) + { + return; + } + + tcs.TrySetResult(eventArgs.ApplicationMessage.Payload); + } + + public void Dispose() + { + foreach (var tcs in _waitingCalls) + { + tcs.Value.SetCanceled(); + } + + _waitingCalls.Clear(); + } + } +} diff --git a/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj b/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj index fbde3f2b..1f23602d 100644 --- a/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj +++ b/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj @@ -2,8 +2,13 @@ netstandard2.0 - 2.5.2.0 - 2.5.2.0 + 0.0.0.0 + 0.0.0.0 + 0.0.0.0 + + + + diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index af399583..0cbcc93e 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -18,6 +18,8 @@ namespace MQTTnet.Adapter { private const uint ErrorOperationAborted = 0x800703E3; + private static readonly byte[] EmptyBody = new byte[0]; + private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly IMqttNetLogger _logger; private readonly IMqttChannel _channel; @@ -89,35 +91,28 @@ namespace MQTTnet.Adapter MqttBasePacket packet = null; await ExecuteAndWrapExceptionAsync(async () => { - ReceivedMqttPacket receivedMqttPacket = null; - try + ReceivedMqttPacket receivedMqttPacket; + if (timeout > TimeSpan.Zero) { - if (timeout > TimeSpan.Zero) - { - receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false); - } - else - { - receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).ConfigureAwait(false); - } - - if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested) - { - throw new TaskCanceledException(); - } - - packet = PacketSerializer.Deserialize(receivedMqttPacket); - if (packet == null) - { - throw new MqttProtocolViolationException("Received malformed packet."); - } - - _logger.Trace("RX <<< {0}", packet); + receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false); } - finally + else { - receivedMqttPacket?.Dispose(); + receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).ConfigureAwait(false); } + + if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested) + { + throw new TaskCanceledException(); + } + + packet = PacketSerializer.Deserialize(receivedMqttPacket.Header, receivedMqttPacket.Body); + if (packet == null) + { + throw new MqttProtocolViolationException("Received malformed packet."); + } + + _logger.Trace("RX <<< {0}", packet); }).ConfigureAwait(false); return packet; @@ -133,7 +128,7 @@ namespace MQTTnet.Adapter if (header.BodyLength == 0) { - return new ReceivedMqttPacket(header, new MemoryStream(0)); + return new ReceivedMqttPacket(header, EmptyBody); } var body = new byte[header.BodyLength]; @@ -145,7 +140,7 @@ namespace MQTTnet.Adapter offset += readBytesCount; } while (offset < header.BodyLength); - return new ReceivedMqttPacket(header, new MemoryStream(body, 0, body.Length, false, true)); + return new ReceivedMqttPacket(header, body); } private static async Task ExecuteAndWrapExceptionAsync(Func action) diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/ReceivedMqttPacket.cs b/Frameworks/MQTTnet.NetStandard/Adapter/ReceivedMqttPacket.cs index a44fb54e..c92f9d0d 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/ReceivedMqttPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/ReceivedMqttPacket.cs @@ -1,12 +1,11 @@ using System; -using System.IO; using MQTTnet.Packets; namespace MQTTnet.Adapter { - public sealed class ReceivedMqttPacket : IDisposable + public class ReceivedMqttPacket { - public ReceivedMqttPacket(MqttPacketHeader header, MemoryStream body) + public ReceivedMqttPacket(MqttPacketHeader header, byte[] body) { Header = header ?? throw new ArgumentNullException(nameof(header)); Body = body ?? throw new ArgumentNullException(nameof(body)); @@ -14,11 +13,6 @@ namespace MQTTnet.Adapter public MqttPacketHeader Header { get; } - public MemoryStream Body { get; } - - public void Dispose() - { - Body?.Dispose(); - } + public byte[] Body { get; } } } diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs index 7e23fdbe..7e6f663e 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs @@ -70,7 +70,7 @@ namespace MQTTnet.Implementations _sslStream = new SslStream(new NetworkStream(_socket, true), false, InternalUserCertificateValidationCallback); await _sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(_options), SslProtocols.Tls12, _options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false); } - + CreateStreams(_socket, _sslStream); } @@ -139,10 +139,7 @@ namespace MQTTnet.Implementations private void CreateStreams(Socket socket, Stream sslStream) { var stream = sslStream ?? new NetworkStream(socket); - - //cannot use this as default buffering prevents from receiving the first connect message - //need two streams otherwise read and write have to be synchronized - + //todo: if branch can be used with min dependency NetStandard1.6 #if NET452 || NET461 SendStream = new BufferedStream(stream, BufferSize); diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj index abcc8658..92920cd3 100644 --- a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -6,8 +6,8 @@ MQTTnet False Full - 2.5.3.0 - 2.5.3.0 + 0.0.0.0 + 0.0.0.0 0.0.0.0 @@ -29,7 +29,6 @@ v5.0 $(DefineConstants);WINDOWS_UWP $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets - diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs index 7ae72507..9b011563 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs @@ -13,9 +13,9 @@ namespace MQTTnet.ManagedClient { public class ManagedMqttClient : IManagedMqttClient { - private readonly ManagedMqttClientStorageManager _storageManager = new ManagedMqttClientStorageManager(); private readonly BlockingCollection _messageQueue = new BlockingCollection(); private readonly HashSet _subscriptions = new HashSet(); + private readonly SemaphoreSlim _subscriptionsSemaphore = new SemaphoreSlim(1, 1); private readonly IMqttClient _mqttClient; private readonly IMqttNetLogger _logger; @@ -23,7 +23,9 @@ namespace MQTTnet.ManagedClient private CancellationTokenSource _connectionCancellationToken; private CancellationTokenSource _publishingCancellationToken; + private ManagedMqttClientStorageManager _storageManager; private IManagedMqttClientOptions _options; + private bool _subscriptionsNotPushed; public ManagedMqttClient(IMqttClient mqttClient, IMqttNetLogger logger) @@ -55,15 +57,11 @@ namespace MQTTnet.ManagedClient if (_connectionCancellationToken != null) throw new InvalidOperationException("The managed client is already started."); _options = options; - await _storageManager.SetStorageAsync(_options.Storage).ConfigureAwait(false); - + if (_options.Storage != null) { - var loadedMessages = await _options.Storage.LoadQueuedMessagesAsync().ConfigureAwait(false); - foreach (var loadedMessage in loadedMessages) - { - _messageQueue.Add(loadedMessage); - } + _storageManager = new ManagedMqttClientStorageManager(_options.Storage); + await _storageManager.LoadQueuedMessagesAsync().ConfigureAwait(false); } _connectionCancellationToken = new CancellationTokenSource(); @@ -97,16 +95,21 @@ namespace MQTTnet.ManagedClient foreach (var applicationMessage in applicationMessages) { - await _storageManager.AddAsync(applicationMessage).ConfigureAwait(false); + if (_storageManager != null) + { + await _storageManager.AddAsync(applicationMessage).ConfigureAwait(false); + } + _messageQueue.Add(applicationMessage); } } - public Task SubscribeAsync(IEnumerable topicFilters) + public async Task SubscribeAsync(IEnumerable topicFilters) { if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); - lock (_subscriptions) + await _subscriptionsSemaphore.WaitAsync().ConfigureAwait(false); + try { foreach (var topicFilter in topicFilters) { @@ -116,13 +119,16 @@ namespace MQTTnet.ManagedClient } } } - - return Task.FromResult(0); + finally + { + _subscriptionsSemaphore.Release(); + } } - public Task UnsubscribeAsync(IEnumerable topicFilters) + public async Task UnsubscribeAsync(IEnumerable topicFilters) { - lock (_subscriptions) + await _subscriptionsSemaphore.WaitAsync().ConfigureAwait(false); + try { foreach (var topicFilter in topicFilters) { @@ -132,8 +138,10 @@ namespace MQTTnet.ManagedClient } } } - - return Task.FromResult(0); + finally + { + _subscriptionsSemaphore.Release(); + } } private async Task MaintainConnectionAsync(CancellationToken cancellationToken) @@ -242,7 +250,11 @@ namespace MQTTnet.ManagedClient try { await _mqttClient.PublishAsync(message).ConfigureAwait(false); - await _storageManager.RemoveAsync(message).ConfigureAwait(false); + + if (_storageManager != null) + { + await _storageManager.RemoveAsync(message).ConfigureAwait(false); + } } catch (MqttCommunicationException exception) { @@ -264,13 +276,18 @@ namespace MQTTnet.ManagedClient _logger.Info(nameof(ManagedMqttClient), "Synchronizing subscriptions"); List subscriptions; - lock (_subscriptions) + await _subscriptionsSemaphore.WaitAsync().ConfigureAwait(false); + try { subscriptions = _subscriptions.ToList(); _subscriptionsNotPushed = false; } + finally + { + _subscriptionsSemaphore.Release(); + } - if (!_subscriptions.Any()) + if (!subscriptions.Any()) { return; } diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientStorageManager.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientStorageManager.cs index d55f1376..0e71776e 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientStorageManager.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientStorageManager.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -8,18 +9,19 @@ namespace MQTTnet.ManagedClient { private readonly List _applicationMessages = new List(); private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); - private IManagedMqttClientStorage _storage; + private readonly IManagedMqttClientStorage _storage; - public async Task SetStorageAsync(IManagedMqttClientStorage storage) + public ManagedMqttClientStorageManager(IManagedMqttClientStorage storage) { - await _semaphore.WaitAsync().ConfigureAwait(false); - try + _storage = storage ?? throw new ArgumentNullException(nameof(storage)); + } + + public async Task LoadQueuedMessagesAsync() + { + var loadedMessages = await _storage.LoadQueuedMessagesAsync().ConfigureAwait(false); + foreach (var loadedMessage in loadedMessages) { - _storage = storage; - } - finally - { - _semaphore.Release(); + _applicationMessages.Add(loadedMessage); } } @@ -28,11 +30,6 @@ namespace MQTTnet.ManagedClient await _semaphore.WaitAsync().ConfigureAwait(false); try { - if (_storage == null) - { - return; - } - _applicationMessages.Add(applicationMessage); await SaveAsync().ConfigureAwait(false); } @@ -47,11 +44,6 @@ namespace MQTTnet.ManagedClient await _semaphore.WaitAsync().ConfigureAwait(false); try { - if (_storage == null) - { - return; - } - var index = _applicationMessages.IndexOf(applicationMessage); if (index == -1) { diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs b/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs index 439460d1..20686411 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using MQTTnet.Adapter; using MQTTnet.Packets; namespace MQTTnet.Serializer @@ -9,8 +8,8 @@ namespace MQTTnet.Serializer { MqttProtocolVersion ProtocolVersion { get; set; } - IEnumerable> Serialize(MqttBasePacket mqttPacket); + ICollection> Serialize(MqttBasePacket mqttPacket); - MqttBasePacket Deserialize(ReceivedMqttPacket receivedMqttPacket); + MqttBasePacket Deserialize(MqttPacketHeader header, byte[] body); } } \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs index 04ee01f2..a22707c1 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs @@ -1,9 +1,9 @@ using System; +using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Adapter; using MQTTnet.Exceptions; using MQTTnet.Packets; using MQTTnet.Protocol; @@ -12,15 +12,15 @@ namespace MQTTnet.Serializer { public sealed class MqttPacketReader : BinaryReader { - private readonly ReceivedMqttPacket _receivedMqttPacket; - - public MqttPacketReader(ReceivedMqttPacket receivedMqttPacket) - : base(receivedMqttPacket.Body, Encoding.UTF8, true) + private readonly MqttPacketHeader _header; + + public MqttPacketReader(MqttPacketHeader header, Stream bodyStream) + : base(bodyStream, Encoding.UTF8, true) { - _receivedMqttPacket = receivedMqttPacket; + _header = header; } - public bool EndOfRemainingData => BaseStream.Position == _receivedMqttPacket.Header.BodyLength; + public bool EndOfRemainingData => BaseStream.Position == _header.BodyLength; public static MqttPacketHeader ReadHeaderFromSource(Stream stream, CancellationToken cancellationToken) { @@ -77,7 +77,7 @@ namespace MQTTnet.Serializer public byte[] ReadRemainingData() { - return ReadBytes(_receivedMqttPacket.Header.BodyLength - (int)BaseStream.Position); + return ReadBytes(_header.BodyLength - (int)BaseStream.Position); } private static int ReadBodyLengthFromSource(Stream stream, CancellationToken cancellationToken) @@ -87,7 +87,7 @@ namespace MQTTnet.Serializer var value = 0; byte encodedByte; - ////var readBytes = new List(); + var readBytes = new List(); do { if (cancellationToken.IsCancellationRequested) @@ -101,15 +101,14 @@ namespace MQTTnet.Serializer throw new MqttCommunicationException("Connection closed while reading remaining length data."); } - ////readBytes.Add(buffer); - encodedByte = (byte)buffer; + readBytes.Add(encodedByte); + value += (byte)(encodedByte & 127) * multiplier; multiplier *= 128; if (multiplier > 128 * 128 * 128) { - //throw new MqttProtocolViolationException($"Remaining length is invalid (Data={string.Join(",", readBytes)})."); - throw new MqttProtocolViolationException("Remaining length is invalid."); + throw new MqttProtocolViolationException($"Remaining length is invalid (Data={string.Join(",", readBytes)})."); } } while ((encodedByte & 128) != 0); diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs index 0b041146..88414d5d 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs @@ -1,5 +1,4 @@ -using MQTTnet.Adapter; -using MQTTnet.Exceptions; +using MQTTnet.Exceptions; using MQTTnet.Packets; using MQTTnet.Protocol; using System; @@ -17,7 +16,7 @@ namespace MQTTnet.Serializer public MqttProtocolVersion ProtocolVersion { get; set; } = MqttProtocolVersion.V311; - public IEnumerable> Serialize(MqttBasePacket packet) + public ICollection> Serialize(MqttBasePacket packet) { if (packet == null) throw new ArgumentNullException(nameof(packet)); @@ -43,13 +42,15 @@ namespace MQTTnet.Serializer } } - public MqttBasePacket Deserialize(ReceivedMqttPacket receivedMqttPacket) + public MqttBasePacket Deserialize(MqttPacketHeader header, byte[] body) { - if (receivedMqttPacket == null) throw new ArgumentNullException(nameof(receivedMqttPacket)); + if (header == null) throw new ArgumentNullException(nameof(header)); + if (body == null) throw new ArgumentNullException(nameof(body)); - using (var reader = new MqttPacketReader(receivedMqttPacket)) + using (var bodyStream = new MemoryStream(body)) + using (var reader = new MqttPacketReader(header, bodyStream)) { - return Deserialize(receivedMqttPacket.Header, reader); + return Deserialize(header, reader); } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index 12ef891a..8f7199ab 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -14,15 +14,17 @@ namespace MQTTnet.Server { public sealed class MqttClientSession { - private readonly Stopwatch _lastPacketReceivedTracker = new Stopwatch(); - private readonly Stopwatch _lastNonKeepAlivePacketReceivedTracker = new Stopwatch(); + private readonly Stopwatch _lastPacketReceivedTracker = Stopwatch.StartNew(); + private readonly Stopwatch _lastNonKeepAlivePacketReceivedTracker = Stopwatch.StartNew(); - private readonly MqttClientSubscriptionsManager _subscriptionsManager; - private readonly MqttClientSessionsManager _sessionsManager; - private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue; private readonly IMqttServerOptions _options; private readonly IMqttNetLogger _logger; + private readonly MqttClientSessionsManager _sessionsManager; + private readonly MqttRetainedMessagesManager _retainedMessagesManager; + private readonly MqttClientSubscriptionsManager _subscriptionsManager; + private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue; + private IMqttChannelAdapter _adapter; private CancellationTokenSource _cancellationTokenSource; private MqttApplicationMessage _willMessage; @@ -30,16 +32,17 @@ namespace MQTTnet.Server public MqttClientSession( string clientId, IMqttServerOptions options, + MqttRetainedMessagesManager retainedMessagesManager, MqttClientSessionsManager sessionsManager, IMqttNetLogger logger) { + _options = options ?? throw new ArgumentNullException(nameof(options)); + _retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager)); _sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); ClientId = clientId; - - _options = options; - + _subscriptionsManager = new MqttClientSubscriptionsManager(_options); _pendingMessagesQueue = new MqttClientPendingMessagesQueue(_options, this, _logger); } @@ -117,11 +120,11 @@ namespace MQTTnet.Server } } - public void EnqueueApplicationMessage(MqttApplicationMessage applicationMessage) + public async Task EnqueueApplicationMessageAsync(MqttApplicationMessage applicationMessage) { if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); - var result = _subscriptionsManager.CheckSubscriptions(applicationMessage); + var result = await _subscriptionsManager.CheckSubscriptionsAsync(applicationMessage); if (!result.IsSubscribed) { return; @@ -129,6 +132,7 @@ namespace MQTTnet.Server var publishPacket = applicationMessage.ToPublishPacket(); publishPacket.QualityOfServiceLevel = result.QualityOfServiceLevel; + _pendingMessagesQueue.Enqueue(publishPacket); } @@ -199,7 +203,7 @@ namespace MQTTnet.Server if (packet is MqttUnsubscribePacket unsubscribePacket) { - return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, _subscriptionsManager.Unsubscribe(unsubscribePacket)); + return HandleIncomingUnsubscribePacketAsync(adapter, unsubscribePacket, cancellationToken); } if (packet is MqttDisconnectPacket || packet is MqttConnectPacket) @@ -213,24 +217,31 @@ namespace MQTTnet.Server private async Task HandleIncomingSubscribePacketAsync(IMqttChannelAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken) { - var subscribeResult = _subscriptionsManager.Subscribe(subscribePacket, ClientId); + var subscribeResult = await _subscriptionsManager.SubscribeAsync(subscribePacket, ClientId); await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, subscribeResult.ResponsePacket).ConfigureAwait(false); - await EnqueueSubscribedRetainedMessagesAsync(subscribePacket).ConfigureAwait(false); - if (subscribeResult.CloseConnection) { await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttDisconnectPacket()).ConfigureAwait(false); await StopAsync().ConfigureAwait(false); } + + await EnqueueSubscribedRetainedMessagesAsync(subscribePacket).ConfigureAwait(false); + } + + private async Task HandleIncomingUnsubscribePacketAsync(IMqttChannelAdapter adapter, MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken) + { + var unsubscribeResult = await _subscriptionsManager.UnsubscribeAsync(unsubscribePacket); + + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, unsubscribeResult); } private async Task EnqueueSubscribedRetainedMessagesAsync(MqttSubscribePacket subscribePacket) { - var retainedMessages = await _sessionsManager.GetRetainedMessagesAsync(subscribePacket).ConfigureAwait(false); + var retainedMessages = await _retainedMessagesManager.GetSubscribedMessagesAsync(subscribePacket); foreach (var publishPacket in retainedMessages) { - EnqueueApplicationMessage(publishPacket); + await EnqueueApplicationMessageAsync(publishPacket); } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index 5bb65984..739f9649 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -15,23 +15,21 @@ namespace MQTTnet.Server public sealed class MqttClientSessionsManager { private readonly Dictionary _sessions = new Dictionary(); - private readonly SemaphoreSlim _sessionsSemaphore = new SemaphoreSlim(1, 1); + private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly IMqttServerOptions _options; + private readonly MqttServer _server; private readonly MqttRetainedMessagesManager _retainedMessagesManager; private readonly IMqttNetLogger _logger; - public MqttClientSessionsManager(IMqttServerOptions options, MqttRetainedMessagesManager retainedMessagesManager, IMqttNetLogger logger) + public MqttClientSessionsManager(IMqttServerOptions options, MqttRetainedMessagesManager retainedMessagesManager, MqttServer server, IMqttNetLogger logger) { + _server = server ?? throw new ArgumentNullException(nameof(server)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _options = options ?? throw new ArgumentNullException(nameof(options)); _retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager)); } - public event EventHandler ClientConnected; - public event EventHandler ClientDisconnected; - public event EventHandler ApplicationMessageReceived; - public async Task RunClientSessionAsync(IMqttChannelAdapter clientAdapter, CancellationToken cancellationToken) { var clientId = string.Empty; @@ -66,11 +64,11 @@ namespace MQTTnet.Server IsSessionPresent = clientSession.IsExistingSession }).ConfigureAwait(false); - ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(new ConnectedMqttClient + _server.OnClientConnected(new ConnectedMqttClient { ClientId = clientId, ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion - })); + }); await clientSession.Session.RunAsync(connectPacket.WillMessage, clientAdapter).ConfigureAwait(false); } @@ -89,17 +87,17 @@ namespace MQTTnet.Server // ignored } - ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(new ConnectedMqttClient + _server.OnClientDisconnected(new ConnectedMqttClient { ClientId = clientId, ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion - })); + }); } } public async Task StopAsync() { - await _sessionsSemaphore.WaitAsync().ConfigureAwait(false); + await _semaphore.WaitAsync().ConfigureAwait(false); try { foreach (var session in _sessions) @@ -111,13 +109,13 @@ namespace MQTTnet.Server } finally { - _sessionsSemaphore.Release(); + _semaphore.Release(); } } public async Task> GetConnectedClientsAsync() { - await _sessionsSemaphore.WaitAsync().ConfigureAwait(false); + await _semaphore.WaitAsync().ConfigureAwait(false); try { return _sessions.Where(s => s.Value.IsConnected).Select(s => new ConnectedMqttClient @@ -130,7 +128,7 @@ namespace MQTTnet.Server } finally { - _sessionsSemaphore.Release(); + _semaphore.Release(); } } @@ -138,17 +136,7 @@ namespace MQTTnet.Server { try { - if (_options.ApplicationMessageInterceptor != null) - { - var interceptorContext = new MqttApplicationMessageInterceptorContext - { - ApplicationMessage = applicationMessage - }; - - _options.ApplicationMessageInterceptor(interceptorContext); - applicationMessage = interceptorContext.ApplicationMessage; - } - + applicationMessage = InterceptApplicationMessage(applicationMessage); if (applicationMessage == null) { return; @@ -159,26 +147,41 @@ namespace MQTTnet.Server await _retainedMessagesManager.HandleMessageAsync(senderClientSession?.ClientId, applicationMessage).ConfigureAwait(false); } - var eventArgs = new MqttApplicationMessageReceivedEventArgs(senderClientSession?.ClientId, applicationMessage); - ApplicationMessageReceived?.Invoke(this, eventArgs); + _server.OnApplicationMessageReceived(senderClientSession?.ClientId, applicationMessage); } catch (Exception exception) { _logger.Error(exception, "Error while processing application message"); } - lock (_sessions) + await _semaphore.WaitAsync().ConfigureAwait(false); + try { foreach (var clientSession in _sessions.Values) { - clientSession.EnqueueApplicationMessage(applicationMessage); + await clientSession.EnqueueApplicationMessageAsync(applicationMessage); } } + finally + { + _semaphore.Release(); + } } - public Task> GetRetainedMessagesAsync(MqttSubscribePacket subscribePacket) + private MqttApplicationMessage InterceptApplicationMessage(MqttApplicationMessage applicationMessage) { - return _retainedMessagesManager.GetSubscribedMessagesAsync(subscribePacket); + if (_options.ApplicationMessageInterceptor == null) + { + return applicationMessage; + } + + var interceptorContext = new MqttApplicationMessageInterceptorContext + { + ApplicationMessage = applicationMessage + }; + + _options.ApplicationMessageInterceptor(interceptorContext); + return interceptorContext.ApplicationMessage; } private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket) @@ -200,7 +203,7 @@ namespace MQTTnet.Server private async Task GetOrCreateClientSessionAsync(MqttConnectPacket connectPacket) { - await _sessionsSemaphore.WaitAsync().ConfigureAwait(false); + await _semaphore.WaitAsync().ConfigureAwait(false); try { var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var clientSession); @@ -225,7 +228,7 @@ namespace MQTTnet.Server { isExistingSession = false; - clientSession = new MqttClientSession(connectPacket.ClientId, _options, this, _logger); + clientSession = new MqttClientSession(connectPacket.ClientId, _options, _retainedMessagesManager, this, _logger); _sessions[connectPacket.ClientId] = clientSession; _logger.Trace("Created a new session for client '{0}'.", connectPacket.ClientId); @@ -235,7 +238,7 @@ namespace MQTTnet.Server } finally { - _sessionsSemaphore.Release(); + _semaphore.Release(); } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs index 73548ce3..2151f77b 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs @@ -1,5 +1,8 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; using MQTTnet.Packets; using MQTTnet.Protocol; @@ -7,6 +10,7 @@ namespace MQTTnet.Server { public sealed class MqttClientSubscriptionsManager { + private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly Dictionary _subscriptions = new Dictionary(); private readonly IMqttServerOptions _options; @@ -15,24 +19,34 @@ namespace MQTTnet.Server _options = options ?? throw new ArgumentNullException(nameof(options)); } - public MqttClientSubscribeResult Subscribe(MqttSubscribePacket subscribePacket, string clientId) + public async Task SubscribeAsync(MqttSubscribePacket subscribePacket, string clientId) { if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket)); - var responsePacket = subscribePacket.CreateResponse(); - var closeConnection = false; + var result = new MqttClientSubscribeResult + { + ResponsePacket = subscribePacket.CreateResponse(), + CloseConnection = false + }; - lock (_subscriptions) + await _semaphore.WaitAsync().ConfigureAwait(false); + try { foreach (var topicFilter in subscribePacket.TopicFilters) { - var interceptorContext = new MqttSubscriptionInterceptorContext(clientId, topicFilter); - _options.SubscriptionInterceptor?.Invoke(interceptorContext); - responsePacket.SubscribeReturnCodes.Add(interceptorContext.AcceptSubscription ? MqttSubscribeReturnCode.SuccessMaximumQoS1 : MqttSubscribeReturnCode.Failure); - + var interceptorContext = InterceptSubscribe(clientId, topicFilter); + if (!interceptorContext.AcceptSubscription) + { + result.ResponsePacket.SubscribeReturnCodes.Add(MqttSubscribeReturnCode.Failure); + } + else + { + result.ResponsePacket.SubscribeReturnCodes.Add(ConvertToMaximumQoS(topicFilter.QualityOfServiceLevel)); + } + if (interceptorContext.CloseConnection) { - closeConnection = true; + result.CloseConnection = true; } if (interceptorContext.AcceptSubscription) @@ -41,35 +55,42 @@ namespace MQTTnet.Server } } } - - return new MqttClientSubscribeResult + finally { - ResponsePacket = responsePacket, - CloseConnection = closeConnection - }; + _semaphore.Release(); + } + + return result; } - public MqttUnsubAckPacket Unsubscribe(MqttUnsubscribePacket unsubscribePacket) + public async Task UnsubscribeAsync(MqttUnsubscribePacket unsubscribePacket) { if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket)); - lock (_subscriptions) + await _semaphore.WaitAsync().ConfigureAwait(false); + try { foreach (var topicFilter in unsubscribePacket.TopicFilters) { _subscriptions.Remove(topicFilter); } } + finally + { + _semaphore.Release(); + } return unsubscribePacket.CreateResponse(); } - public CheckSubscriptionsResult CheckSubscriptions(MqttApplicationMessage applicationMessage) + public async Task CheckSubscriptionsAsync(MqttApplicationMessage applicationMessage) { if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); - lock (_subscriptions) + await _semaphore.WaitAsync().ConfigureAwait(false); + try { + var qosLevels = new HashSet(); foreach (var subscription in _subscriptions) { if (!MqttTopicFilterComparer.IsMatch(applicationMessage.Topic, subscription.Key)) @@ -77,24 +98,64 @@ namespace MQTTnet.Server continue; } - var effectiveQos = subscription.Value; - if (applicationMessage.QualityOfServiceLevel < effectiveQos) - { - effectiveQos = applicationMessage.QualityOfServiceLevel; - } + qosLevels.Add(subscription.Value); + } + if (qosLevels.Count == 0) + { return new CheckSubscriptionsResult { - IsSubscribed = true, - QualityOfServiceLevel = effectiveQos + IsSubscribed = false }; } + + return CreateSubscriptionResult(applicationMessage, qosLevels); + } + finally + { + _semaphore.Release(); + } + } + + private MqttSubscriptionInterceptorContext InterceptSubscribe(string clientId, TopicFilter topicFilter) + { + var interceptorContext = new MqttSubscriptionInterceptorContext(clientId, topicFilter); + _options.SubscriptionInterceptor?.Invoke(interceptorContext); + return interceptorContext; + } + + private static CheckSubscriptionsResult CreateSubscriptionResult(MqttApplicationMessage applicationMessage, HashSet subscribedQoSLevels) + { + MqttQualityOfServiceLevel effectiveQoS; + if (subscribedQoSLevels.Contains(applicationMessage.QualityOfServiceLevel)) + { + effectiveQoS = applicationMessage.QualityOfServiceLevel; + } + else if (subscribedQoSLevels.Count == 1) + { + effectiveQoS = subscribedQoSLevels.First(); + } + else + { + effectiveQoS = subscribedQoSLevels.Max(); } return new CheckSubscriptionsResult { - IsSubscribed = false + IsSubscribed = true, + QualityOfServiceLevel = effectiveQoS }; } + + private static MqttSubscribeReturnCode ConvertToMaximumQoS(MqttQualityOfServiceLevel qualityOfServiceLevel) + { + switch (qualityOfServiceLevel) + { + case MqttQualityOfServiceLevel.AtMostOnce: return MqttSubscribeReturnCode.SuccessMaximumQoS0; + case MqttQualityOfServiceLevel.AtLeastOnce: return MqttSubscribeReturnCode.SuccessMaximumQoS1; + case MqttQualityOfServiceLevel.ExactlyOnce: return MqttSubscribeReturnCode.SuccessMaximumQoS2; + default: return MqttSubscribeReturnCode.Failure; + } + } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs index 0b8d6697..2c0b2602 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs @@ -11,7 +11,7 @@ namespace MQTTnet.Server public sealed class MqttRetainedMessagesManager { private readonly Dictionary _retainedMessages = new Dictionary(); - private readonly SemaphoreSlim _gate = new SemaphoreSlim(1, 1); + private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly IMqttNetLogger _logger; private readonly IMqttServerOptions _options; @@ -28,7 +28,7 @@ namespace MQTTnet.Server return; } - await _gate.WaitAsync(); + await _semaphore.WaitAsync().ConfigureAwait(false); try { var retainedMessages = await _options.Storage.LoadRetainedMessagesAsync(); @@ -45,7 +45,7 @@ namespace MQTTnet.Server } finally { - _gate.Release(); + _semaphore.Release(); } } @@ -53,7 +53,7 @@ namespace MQTTnet.Server { if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); - await _gate.WaitAsync().ConfigureAwait(false); + await _semaphore.WaitAsync().ConfigureAwait(false); try { await HandleMessageInternalAsync(clientId, applicationMessage); @@ -64,7 +64,7 @@ namespace MQTTnet.Server } finally { - _gate.Release(); + _semaphore.Release(); } } @@ -72,7 +72,7 @@ namespace MQTTnet.Server { var retainedMessages = new List(); - await _gate.WaitAsync().ConfigureAwait(false); + await _semaphore.WaitAsync().ConfigureAwait(false); try { foreach (var retainedMessage in _retainedMessages.Values) @@ -96,7 +96,7 @@ namespace MQTTnet.Server } finally { - _gate.Release(); + _semaphore.Release(); } return retainedMessages; diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs index 42c68543..888dd425 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs @@ -60,11 +60,7 @@ namespace MQTTnet.Server _cancellationTokenSource = new CancellationTokenSource(); _retainedMessagesManager = new MqttRetainedMessagesManager(_options, _logger); - - _clientSessionsManager = new MqttClientSessionsManager(_options, _retainedMessagesManager, _logger); - _clientSessionsManager.ApplicationMessageReceived += OnApplicationMessageReceived; - _clientSessionsManager.ClientConnected += OnClientConnected; - _clientSessionsManager.ClientDisconnected += OnClientDisconnected; + _clientSessionsManager = new MqttClientSessionsManager(_options, _retainedMessagesManager, this, _logger); await _retainedMessagesManager.LoadMessagesAsync(); @@ -104,40 +100,39 @@ namespace MQTTnet.Server finally { _cancellationTokenSource = null; - _retainedMessagesManager = null; - - if (_clientSessionsManager != null) - { - _clientSessionsManager.ApplicationMessageReceived -= OnApplicationMessageReceived; - _clientSessionsManager.ClientConnected -= OnClientConnected; - _clientSessionsManager.ClientDisconnected -= OnClientDisconnected; - } - _clientSessionsManager = null; } } + internal void OnClientConnected(ConnectedMqttClient client) + { + if (client == null) throw new ArgumentNullException(nameof(client)); + + _logger.Info("Client '{0}': Connected.", client.ClientId); + ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(client)); + } + + internal void OnClientDisconnected(ConnectedMqttClient client) + { + if (client == null) throw new ArgumentNullException(nameof(client)); + + _logger.Info("Client '{0}': Disconnected.", client.ClientId); + ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(client)); + } + + internal void OnApplicationMessageReceived(string clientId, MqttApplicationMessage applicationMessage) + { + if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); + + ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(clientId, applicationMessage)); + } + private void OnClientAccepted(object sender, MqttServerAdapterClientAcceptedEventArgs eventArgs) { - eventArgs.SessionTask = Task.Run(async () => await _clientSessionsManager.RunClientSessionAsync(eventArgs.Client, _cancellationTokenSource.Token), _cancellationTokenSource.Token); - } - - private void OnClientConnected(object sender, MqttClientConnectedEventArgs eventArgs) - { - _logger.Info("Client '{0}': Connected.", eventArgs.Client.ClientId); - ClientConnected?.Invoke(this, eventArgs); - } - - private void OnClientDisconnected(object sender, MqttClientDisconnectedEventArgs eventArgs) - { - _logger.Info("Client '{0}': Disconnected.", eventArgs.Client.ClientId); - ClientDisconnected?.Invoke(this, eventArgs); - } - - private void OnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e) - { - ApplicationMessageReceived?.Invoke(this, e); + eventArgs.SessionTask = Task.Run( + async () => await _clientSessionsManager.RunClientSessionAsync(eventArgs.Client, _cancellationTokenSource.Token).ConfigureAwait(false), + _cancellationTokenSource.Token); } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttSubscriptionInterceptorContext.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttSubscriptionInterceptorContext.cs index e05dd216..07b94bb6 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttSubscriptionInterceptorContext.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttSubscriptionInterceptorContext.cs @@ -1,17 +1,19 @@ -namespace MQTTnet.Server +using System; + +namespace MQTTnet.Server { public class MqttSubscriptionInterceptorContext { public MqttSubscriptionInterceptorContext(string clientId, TopicFilter topicFilter) { ClientId = clientId; - TopicFilter = topicFilter; + TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter)); } public string ClientId { get; } public TopicFilter TopicFilter { get; } - + public bool AcceptSubscription { get; set; } = true; public bool CloseConnection { get; set; } diff --git a/Frameworks/MQTTnet.NetStandard/TopicFilter.cs b/Frameworks/MQTTnet.NetStandard/TopicFilter.cs index b82fc712..da126d6d 100644 --- a/Frameworks/MQTTnet.NetStandard/TopicFilter.cs +++ b/Frameworks/MQTTnet.NetStandard/TopicFilter.cs @@ -4,7 +4,7 @@ namespace MQTTnet { public sealed class TopicFilter { - public TopicFilter(string topic, MqttQualityOfServiceLevel qualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce) + public TopicFilter(string topic, MqttQualityOfServiceLevel qualityOfServiceLevel) { Topic = topic; QualityOfServiceLevel = qualityOfServiceLevel; diff --git a/MQTTnet.sln b/MQTTnet.sln index ceaa04fb..cece21c5 100644 --- a/MQTTnet.sln +++ b/MQTTnet.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27004.2009 +VisualStudioVersion = 15.0.27004.2010 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Core.Tests", "Tests\MQTTnet.Core.Tests\MQTTnet.Core.Tests.csproj", "{A7FF0C91-25DE-4BA6-B39E-F54E8DADF1CC}" EndProject @@ -33,6 +33,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.TestApp.AspNetCore2 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.AspNetCore", "Frameworks\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", "Extensions\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj", "{C444E9C8-95FA-430E-9126-274129DE16CD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -147,6 +151,22 @@ Global {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -158,6 +178,7 @@ Global {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} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {07536672-5CBC-4BE3-ACE0-708A431A7894} diff --git a/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs b/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs index 25c93520..9f51b86f 100644 --- a/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs @@ -4,7 +4,6 @@ using System.IO; using System.Text; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MQTTnet.Adapter; using MQTTnet.Packets; using MQTTnet.Protocol; using MQTTnet.Serializer; @@ -410,7 +409,7 @@ namespace MQTTnet.Core.Tests using (var bodyStream = new MemoryStream(Join(buffer1), (int)headerStream.Position, header.BodyLength)) { - var deserializedPacket = serializer.Deserialize(new ReceivedMqttPacket(header, bodyStream)); + var deserializedPacket = serializer.Deserialize(header, bodyStream.ToArray()); var buffer2 = serializer.Serialize(deserializedPacket); Assert.AreEqual(expectedBase64Value, Convert.ToBase64String(Join(buffer2))); diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index f1c8ff09..5081dfc6 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -62,7 +62,7 @@ namespace MQTTnet.Core.Tests var c2 = await serverAdapter.ConnectTestClient(s, "c2", willMessage); c1.ApplicationMessageReceived += (_, __) => receivedMessagesCount++; - await c1.SubscribeAsync(new TopicFilter("#")); + await c1.SubscribeAsync(new TopicFilterBuilder().WithTopic("#").Build()); await c2.DisconnectAsync(); @@ -167,7 +167,7 @@ namespace MQTTnet.Core.Tests var c2 = await serverAdapter.ConnectTestClient(s, "c2"); c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++; - await c2.SubscribeAsync(new TopicFilter("retained")); + await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained").Build()); await Task.Delay(500); } @@ -199,7 +199,7 @@ namespace MQTTnet.Core.Tests var c2 = await serverAdapter.ConnectTestClient(s, "c2"); c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++; - await c2.SubscribeAsync(new TopicFilter("retained")); + await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained").Build()); await Task.Delay(500); } @@ -277,7 +277,7 @@ namespace MQTTnet.Core.Tests var c2 = await serverAdapter.ConnectTestClient(s, "c2"); c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++; - await c2.SubscribeAsync(new TopicFilter("retained")); + await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained").Build()); await Task.Delay(500); } diff --git a/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs b/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs index b6b68dce..50acd617 100644 --- a/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs @@ -14,9 +14,9 @@ namespace MQTTnet.Core.Tests var sm = new MqttClientSubscriptionsManager(new MqttServerOptions()); var sp = new MqttSubscribePacket(); - sp.TopicFilters.Add(new TopicFilter("A/B/C")); + sp.TopicFilters.Add(new TopicFilterBuilder().WithTopic("A/B/C").Build()); - sm.Subscribe(sp, ""); + sm.SubscribeAsync(sp, "").Wait(); var pp = new MqttApplicationMessage { @@ -24,7 +24,52 @@ namespace MQTTnet.Core.Tests QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce }; - Assert.IsTrue(sm.CheckSubscriptions(pp).IsSubscribed); + var result = sm.CheckSubscriptionsAsync(pp).Result; + Assert.IsTrue(result.IsSubscribed); + Assert.AreEqual(result.QualityOfServiceLevel, MqttQualityOfServiceLevel.AtMostOnce); + } + + [TestMethod] + public void MqttSubscriptionsManager_SubscribeDifferentQoSSuccess() + { + var sm = new MqttClientSubscriptionsManager(new MqttServerOptions()); + + var sp = new MqttSubscribePacket(); + sp.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.AtMostOnce)); + + sm.SubscribeAsync(sp, "").Wait(); + + var pp = new MqttApplicationMessage + { + Topic = "A/B/C", + QualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce + }; + + var result = sm.CheckSubscriptionsAsync(pp).Result; + Assert.IsTrue(result.IsSubscribed); + Assert.AreEqual(result.QualityOfServiceLevel, MqttQualityOfServiceLevel.AtMostOnce); + } + + [TestMethod] + public void MqttSubscriptionsManager_SubscribeTwoTimesSuccess() + { + var sm = new MqttClientSubscriptionsManager(new MqttServerOptions()); + + var sp = new MqttSubscribePacket(); + sp.TopicFilters.Add(new TopicFilter("#", MqttQualityOfServiceLevel.AtMostOnce)); + sp.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.AtLeastOnce)); + + sm.SubscribeAsync(sp, "").Wait(); + + var pp = new MqttApplicationMessage + { + Topic = "A/B/C", + QualityOfServiceLevel = MqttQualityOfServiceLevel.ExactlyOnce + }; + + var result = sm.CheckSubscriptionsAsync(pp).Result; + Assert.IsTrue(result.IsSubscribed); + Assert.AreEqual(result.QualityOfServiceLevel, MqttQualityOfServiceLevel.AtLeastOnce); } [TestMethod] @@ -33,9 +78,9 @@ namespace MQTTnet.Core.Tests var sm = new MqttClientSubscriptionsManager(new MqttServerOptions()); var sp = new MqttSubscribePacket(); - sp.TopicFilters.Add(new TopicFilter("A/B/C")); + sp.TopicFilters.Add(new TopicFilterBuilder().WithTopic("A/B/C").Build()); - sm.Subscribe(sp, ""); + sm.SubscribeAsync(sp, "").Wait(); var pp = new MqttApplicationMessage { @@ -43,7 +88,7 @@ namespace MQTTnet.Core.Tests QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce }; - Assert.IsFalse(sm.CheckSubscriptions(pp).IsSubscribed); + Assert.IsFalse(sm.CheckSubscriptionsAsync(pp).Result.IsSubscribed); } [TestMethod] @@ -52,9 +97,9 @@ namespace MQTTnet.Core.Tests var sm = new MqttClientSubscriptionsManager(new MqttServerOptions()); var sp = new MqttSubscribePacket(); - sp.TopicFilters.Add(new TopicFilter("A/B/C")); + sp.TopicFilters.Add(new TopicFilterBuilder().WithTopic("A/B/C").Build()); - sm.Subscribe(sp, ""); + sm.SubscribeAsync(sp, "").Wait(); var pp = new MqttApplicationMessage { @@ -62,13 +107,13 @@ namespace MQTTnet.Core.Tests QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce }; - Assert.IsTrue(sm.CheckSubscriptions(pp).IsSubscribed); + Assert.IsTrue(sm.CheckSubscriptionsAsync(pp).Result.IsSubscribed); var up = new MqttUnsubscribePacket(); up.TopicFilters.Add("A/B/C"); - sm.Unsubscribe(up); + sm.UnsubscribeAsync(up).Wait(); - Assert.IsFalse(sm.CheckSubscriptions(pp).IsSubscribed); + Assert.IsFalse(sm.CheckSubscriptionsAsync(pp).Result.IsSubscribed); } } } diff --git a/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs b/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs index 09788cce..dd4a1bc0 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ClientTest.cs @@ -2,6 +2,7 @@ using System.Text; using System.Threading.Tasks; using MQTTnet.Client; +using MQTTnet.Protocol; namespace MQTTnet.TestApp.NetCore { @@ -17,7 +18,8 @@ namespace MQTTnet.TestApp.NetCore CleanSession = true, ChannelOptions = new MqttClientTcpOptions { - Server = "localhost" + //Server = "localhost", + Server = "192.168.1.174" }, //ChannelOptions = new MqttClientWebSocketOptions //{ @@ -78,6 +80,8 @@ namespace MQTTnet.TestApp.NetCore { Console.ReadLine(); + await client.SubscribeAsync(new TopicFilter("test", MqttQualityOfServiceLevel.AtMostOnce)); + var applicationMessage = new MqttApplicationMessageBuilder() .WithTopic("A/B/C") .WithPayload("Hello World") diff --git a/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj b/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj index 8f25448d..1784cc0e 100644 --- a/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj +++ b/Tests/MQTTnet.TestApp.NetCore/MQTTnet.TestApp.NetCore.csproj @@ -6,6 +6,10 @@ netcoreapp2.0;net452;net461 + + RELEASE;NETCOREAPP2_0 + + diff --git a/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs b/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs index 1c72b06a..5f2e5adc 100644 --- a/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/PerformanceTest.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; @@ -64,9 +63,17 @@ namespace MQTTnet.TestApp.NetCore sentMessagesCount++; } - Console.WriteLine($"Sending {sentMessagesCount} messages per second."); - + Console.WriteLine($"Sending {sentMessagesCount} messages per second. #1"); + + sentMessagesCount = 0; stopwatch.Restart(); + while (stopwatch.ElapsedMilliseconds < 1000) + { + await client.PublishAsync(messages).ConfigureAwait(false); + sentMessagesCount++; + } + + Console.WriteLine($"Sending {sentMessagesCount} messages per second. #2"); var testMessageCount = 10000; for (var i = 0; i < testMessageCount; i++) @@ -141,8 +148,8 @@ namespace MQTTnet.TestApp.NetCore { var mqttServer = new MqttFactory().CreateMqttServer(); - var msgs = 0; - var stopwatch = Stopwatch.StartNew(); + ////var msgs = 0; + ////var stopwatch = Stopwatch.StartNew(); ////mqttServer.ApplicationMessageReceived += (sender, args) => ////{ //// msgs++; diff --git a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs index 8f89176c..bd8b4efc 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs @@ -29,6 +29,7 @@ namespace MQTTnet.TestApp.NetCore }, Storage = new RetainedMessageHandler(), + ApplicationMessageInterceptor = context => { if (MqttTopicFilterComparer.IsMatch(context.ApplicationMessage.Topic, "/myTopic/WithTimestamp/#")) @@ -67,18 +68,29 @@ namespace MQTTnet.TestApp.NetCore mqttServer.ApplicationMessageReceived += (s, e) => { MqttNetConsoleLogger.PrintToConsole( - $"'{e.ClientId}' reported '{e.ApplicationMessage.Topic}' > '{Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}'", + $"'{e.ClientId}' reported '{e.ApplicationMessage.Topic}' > '{Encoding.UTF8.GetString(e.ApplicationMessage.Payload ?? new byte[0])}'", ConsoleColor.Magenta); }; options.ApplicationMessageInterceptor = c => { - var content = JObject.Parse(Encoding.UTF8.GetString(c.ApplicationMessage.Payload)); - var timestampProperty = content.Property("timestamp"); - if (timestampProperty != null && timestampProperty.Value.Type == JTokenType.Null) + if (c.ApplicationMessage.Payload == null || c.ApplicationMessage.Payload.Length == 0) + { + return; + } + + try + { + var content = JObject.Parse(Encoding.UTF8.GetString(c.ApplicationMessage.Payload)); + var timestampProperty = content.Property("timestamp"); + if (timestampProperty != null && timestampProperty.Value.Type == JTokenType.Null) + { + timestampProperty.Value = DateTime.Now.ToString("O"); + c.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(content.ToString()); + } + } + catch (Exception e) { - timestampProperty.Value = DateTime.Now.ToString("O"); - c.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(content.ToString()); } }; diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj index 4445af39..5636dd20 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj @@ -127,6 +127,10 @@ + + {c444e9c8-95fa-430e-9126-274129de16cd} + MQTTnet.Extensions.Rpc + {3587e506-55a2-4eb3-99c7-dc01e42d25d2} MQTTnet.NetStandard diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml index 43b26c7a..cf058887 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml @@ -65,6 +65,40 @@ + + + Method: + + + Payload: + + + Text + Base64 + + + QoS: + + 0 (At most once) + 1 (At least once) + 2 (Exactly once) + + + Responses: + + + + + + + + + + + + + + Topic: @@ -86,7 +120,7 @@ - + @@ -101,7 +135,7 @@ Persist retained messages in JSON format Clear previously retained messages on startup - + diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index 00c6ffae..bbd64747 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -7,6 +7,8 @@ using Windows.UI.Core; using Windows.UI.Xaml; using MQTTnet.Client; using MQTTnet.Diagnostics; +using MQTTnet.Exceptions; +using MQTTnet.Extensions.Rpc; using MQTTnet.Implementations; using MQTTnet.ManagedClient; using MQTTnet.Protocol; @@ -245,6 +247,95 @@ namespace MQTTnet.TestApp.UniversalWindows // This code is for the Wiki at GitHub! // ReSharper disable once UnusedMember.Local + + private async void StartServer(object sender, RoutedEventArgs e) + { + if (_mqttServer != null) + { + return; + } + + JsonServerStorage storage = null; + if (ServerPersistRetainedMessages.IsChecked == true) + { + storage = new JsonServerStorage(); + + if (ServerClearRetainedMessages.IsChecked == true) + { + storage.Clear(); + } + } + + _mqttServer = new MqttFactory().CreateMqttServer(); + + var options = new MqttServerOptions(); + options.DefaultEndpointOptions.Port = int.Parse(ServerPort.Text); + options.Storage = storage; + + await _mqttServer.StartAsync(options); + } + + private async void StopServer(object sender, RoutedEventArgs e) + { + if (_mqttServer == null) + { + return; + } + + await _mqttServer.StopAsync(); + _mqttServer = null; + } + + private void ClearReceivedMessages(object sender, RoutedEventArgs e) + { + ReceivedMessages.Items.Clear(); + } + + private async void ExecuteRpc(object sender, RoutedEventArgs e) + { + var qos = MqttQualityOfServiceLevel.AtMostOnce; + if (RpcQoS1.IsChecked == true) + { + qos = MqttQualityOfServiceLevel.AtLeastOnce; + } + + if (RpcQoS2.IsChecked == true) + { + qos = MqttQualityOfServiceLevel.ExactlyOnce; + } + + var payload = new byte[0]; + if (RpcText.IsChecked == true) + { + payload = Encoding.UTF8.GetBytes(RpcPayload.Text); + } + + if (RpcBase64.IsChecked == true) + { + payload = Convert.FromBase64String(RpcPayload.Text); + } + + + try + { + var rpcClient = new MqttRpcClient(_mqttClient); + await rpcClient.EnableAsync(); + var response = await rpcClient.ExecuteAsync(TimeSpan.FromSeconds(5), RpcMethod.Text, payload, qos); + await rpcClient.DisableAsync(); + + RpcResponses.Items.Add(RpcMethod.Text + " >>> " + Encoding.UTF8.GetString(response)); + } + catch (MqttCommunicationTimedOutException) + { + RpcResponses.Items.Add(RpcMethod.Text + " >>> [TIMEOUT]"); + } + } + + private void ClearRpcResponses(object sender, RoutedEventArgs e) + { + RpcResponses.Items.Clear(); + } + private async Task WikiCode() { { @@ -293,9 +384,9 @@ namespace MQTTnet.TestApp.UniversalWindows { // Use secure TCP connection. var options = new MqttClientOptionsBuilder() - .WithTcpServer("broker.hivemq.com") - .WithTls() - .Build(); + .WithTcpServer("broker.hivemq.com") + .WithTls() + .Build(); } { @@ -480,48 +571,5 @@ namespace MQTTnet.TestApp.UniversalWindows } } - - private async void StartServer(object sender, RoutedEventArgs e) - { - if (_mqttServer != null) - { - return; - } - - JsonServerStorage storage = null; - if (ServerPersistRetainedMessages.IsChecked == true) - { - storage = new JsonServerStorage(); - - if (ServerClearRetainedMessages.IsChecked == true) - { - storage.Clear(); - } - } - - _mqttServer = new MqttFactory().CreateMqttServer(); - - var options = new MqttServerOptions(); - options.DefaultEndpointOptions.Port = int.Parse(ServerPort.Text); - options.Storage = storage; - - await _mqttServer.StartAsync(options); - } - - private async void StopServer(object sender, RoutedEventArgs e) - { - if (_mqttServer == null) - { - return; - } - - await _mqttServer.StopAsync(); - _mqttServer = null; - } - - private void ClearReceivedMessages(object sender, RoutedEventArgs e) - { - ReceivedMessages.Items.Clear(); - } } } From 644e9484890bd1bf21868deebd70707fcbc9fbec Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Mon, 4 Dec 2017 13:52:14 +0100 Subject: [PATCH 074/149] Fix keep alive checks in server --- Build/MQTTnet.nuspec | 1 + .../MqttWebSocketServerAdapter.cs | 2 +- .../MQTTnet.NetStandard/Client/MqttClient.cs | 7 +- .../Server/MqttClientPendingMessagesQueue.cs | 36 +++++---- .../Server/MqttClientSession.cs | 77 +++++++++++++++---- .../Server/MqttClientSessionsManager.cs | 6 +- .../MQTTnet.NetStandard/Server/MqttServer.cs | 1 - .../MainPage.xaml | 4 +- .../MainPage.xaml.cs | 3 +- 9 files changed, 98 insertions(+), 39 deletions(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 302b128a..ab982c04 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -22,6 +22,7 @@ * [Server] Added packet statistics for the connected clients. * [Server] Fixed a security issue which sends retained packages to a failed subscription. * [Server] Fixed the response (MaximumQoS) of a subscription (Thanks to @redbeans2017). +* [Server] The keep alive timeouts are now checked for every client (Thanks to @RainerMueller82). Copyright Christian Kratky 2016-2017 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/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs index a2ca627f..c84b9be3 100644 --- a/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs +++ b/Frameworks/MQTTnet.AspnetCore/MqttWebSocketServerAdapter.cs @@ -8,7 +8,7 @@ using MQTTnet.Server; namespace MQTTnet.AspNetCore { - public class MqttWebSocketServerAdapter : IMqttServerAdapter, IDisposable + public sealed class MqttWebSocketServerAdapter : IMqttServerAdapter, IDisposable { public event EventHandler ClientAccepted; diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs index b7658705..b5592e0d 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs @@ -347,13 +347,8 @@ namespace MQTTnet.Client { while (!cancellationToken.IsCancellationRequested) { - await Task.Delay(_options.KeepAlivePeriod, cancellationToken).ConfigureAwait(false); - if (cancellationToken.IsCancellationRequested) - { - return; - } - await SendAndReceiveAsync(new MqttPingReqPacket()).ConfigureAwait(false); + await Task.Delay(_options.KeepAlivePeriod, cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException) diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs index a64dfbf5..2048d529 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs @@ -10,9 +10,9 @@ using MQTTnet.Protocol; namespace MQTTnet.Server { - public sealed class MqttClientPendingMessagesQueue + public sealed class MqttClientPendingMessagesQueue : IDisposable { - private readonly BlockingCollection _pendingPublishPackets = new BlockingCollection(); + private readonly BlockingCollection _queue = new BlockingCollection(); private readonly IMqttServerOptions _options; private readonly MqttClientSession _session; private readonly IMqttNetLogger _logger; @@ -33,24 +33,24 @@ namespace MQTTnet.Server return; } - Task.Run(async () => await SendPendingPublishPacketsAsync(adapter, cancellationToken), cancellationToken).ConfigureAwait(false); + Task.Run(async () => await SendQueuedPacketsAsync(adapter, cancellationToken), cancellationToken).ConfigureAwait(false); } - public void Enqueue(MqttPublishPacket publishPacket) + public void Enqueue(MqttBasePacket packet) { - if (publishPacket == null) throw new ArgumentNullException(nameof(publishPacket)); + if (packet == null) throw new ArgumentNullException(nameof(packet)); - _pendingPublishPackets.Add(publishPacket); + _queue.Add(packet); _logger.Trace("Enqueued packet (ClientId: {0}).", _session.ClientId); } - private async Task SendPendingPublishPacketsAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken) + private async Task SendQueuedPacketsAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken) { try { while (!cancellationToken.IsCancellationRequested) { - await SendPendingPublishPacketAsync(adapter, cancellationToken); + await SendQueuedPacketAsync(adapter, cancellationToken); } } catch (OperationCanceledException) @@ -62,12 +62,12 @@ namespace MQTTnet.Server } } - private async Task SendPendingPublishPacketAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken) + private async Task SendQueuedPacketAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken) { - MqttPublishPacket packet = null; + MqttBasePacket packet = null; try { - packet = _pendingPublishPackets.Take(cancellationToken); + packet = _queue.Take(cancellationToken); await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, packet).ConfigureAwait(false); _logger.Trace("Enqueued packet sent (ClientId: {0}).", _session.ClientId); @@ -90,14 +90,22 @@ namespace MQTTnet.Server _logger.Error(exception, "Sending publish packet failed (ClientId: {0}).", _session.ClientId); } - if (packet != null && packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) + if (packet is MqttPublishPacket publishPacket) { - packet.Dup = true; - _pendingPublishPackets.Add(packet, CancellationToken.None); + if (publishPacket.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) + { + publishPacket.Dup = true; + _queue.Add(packet, CancellationToken.None); + } } await _session.StopAsync(); } } + + public void Dispose() + { + _queue?.Dispose(); + } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index 8f7199ab..a321d934 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -12,7 +12,7 @@ using MQTTnet.Serializer; namespace MQTTnet.Server { - public sealed class MqttClientSession + public sealed class MqttClientSession : IDisposable { private readonly Stopwatch _lastPacketReceivedTracker = Stopwatch.StartNew(); private readonly Stopwatch _lastNonKeepAlivePacketReceivedTracker = Stopwatch.StartNew(); @@ -57,22 +57,29 @@ namespace MQTTnet.Server public bool IsConnected => _adapter != null; - public async Task RunAsync(MqttApplicationMessage willMessage, IMqttChannelAdapter adapter) + public async Task RunAsync(MqttConnectPacket connectPacket, IMqttChannelAdapter adapter) { + if (connectPacket == null) throw new ArgumentNullException(nameof(connectPacket)); if (adapter == null) throw new ArgumentNullException(nameof(adapter)); try { - _lastPacketReceivedTracker.Restart(); - _lastNonKeepAlivePacketReceivedTracker.Restart(); - var cancellationTokenSource = new CancellationTokenSource(); - _willMessage = willMessage; + _willMessage = connectPacket.WillMessage; _adapter = adapter; _cancellationTokenSource = cancellationTokenSource; _pendingMessagesQueue.Start(adapter, cancellationTokenSource.Token); + + _lastPacketReceivedTracker.Restart(); + _lastNonKeepAlivePacketReceivedTracker.Restart(); + + if (connectPacket.KeepAlivePeriod > 0) + { + StartCheckingKeepAliveTimeout(TimeSpan.FromSeconds(connectPacket.KeepAlivePeriod), cancellationTokenSource.Token); + } + await ReceivePacketsAsync(adapter, cancellationTokenSource.Token).ConfigureAwait(false); } catch (OperationCanceledException) @@ -136,6 +143,12 @@ namespace MQTTnet.Server _pendingMessagesQueue.Enqueue(publishPacket); } + public void Dispose() + { + _pendingMessagesQueue?.Dispose(); + _cancellationTokenSource?.Dispose(); + } + private async Task ReceivePacketsAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken) { try @@ -143,6 +156,14 @@ namespace MQTTnet.Server while (!cancellationToken.IsCancellationRequested) { var packet = await adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(false); + + _lastPacketReceivedTracker.Restart(); + + if (!(packet is MqttPingReqPacket)) + { + _lastNonKeepAlivePacketReceivedTracker.Restart(); + } + await ProcessReceivedPacketAsync(adapter, packet, cancellationToken).ConfigureAwait(false); } } @@ -163,13 +184,6 @@ namespace MQTTnet.Server private Task ProcessReceivedPacketAsync(IMqttChannelAdapter adapter, MqttBasePacket packet, CancellationToken cancellationToken) { - _lastPacketReceivedTracker.Restart(); - - if (!(packet is MqttPingReqPacket)) - { - _lastNonKeepAlivePacketReceivedTracker.Restart(); - } - if (packet is MqttPublishPacket publishPacket) { return HandleIncomingPublishPacketAsync(adapter, publishPacket, cancellationToken); @@ -292,5 +306,42 @@ namespace MQTTnet.Server var response = new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier }; return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response); } + + private void StartCheckingKeepAliveTimeout(TimeSpan keepAlivePeriod, CancellationToken cancellationToken) + { + Task.Run( + async () => await CheckKeepAliveTimeoutAsync(keepAlivePeriod, cancellationToken).ConfigureAwait(false) + , cancellationToken); + } + + private async Task CheckKeepAliveTimeoutAsync(TimeSpan keepAlivePeriod, CancellationToken cancellationToken) + { + try + { + while (!cancellationToken.IsCancellationRequested) + { + // Values described here: [MQTT-3.1.2-24]. + if (_lastPacketReceivedTracker.Elapsed.TotalSeconds > keepAlivePeriod.TotalSeconds * 1.5D) + { + _logger.Warning("Client '{0}': Did not receive any packet or keep alive signal.", ClientId); + await StopAsync(); + return; + } + + await Task.Delay(keepAlivePeriod, cancellationToken); + } + } + catch (OperationCanceledException) + { + } + catch (Exception exception) + { + _logger.Error(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", ClientId); + } + finally + { + _logger.Trace("Client {0}: Stopped checking keep alive timeout.", ClientId); + } + } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index 739f9649..7b4d6d14 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -70,7 +70,7 @@ namespace MQTTnet.Server ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion }); - await clientSession.Session.RunAsync(connectPacket.WillMessage, clientAdapter).ConfigureAwait(false); + await clientSession.Session.RunAsync(connectPacket, clientAdapter).ConfigureAwait(false); } catch (Exception exception) { @@ -210,9 +210,11 @@ namespace MQTTnet.Server if (isSessionPresent) { if (connectPacket.CleanSession) - { + { _sessions.Remove(connectPacket.ClientId); + await clientSession.StopAsync().ConfigureAwait(false); + clientSession.Dispose(); clientSession = null; _logger.Trace("Stopped existing session of client '{0}'.", connectPacket.ClientId); diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs index 888dd425..461842fe 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs @@ -71,7 +71,6 @@ namespace MQTTnet.Server } _logger.Info("Started."); - Started?.Invoke(this, new MqttServerStartedEventArgs()); } diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml index cf058887..939061be 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml @@ -27,7 +27,9 @@ Clean session: - + Keep alive interval: + + TCP WS diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index bbd64747..ec42bacd 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -103,7 +103,8 @@ namespace MQTTnet.TestApp.UniversalWindows }; options.CleanSession = CleanSession.IsChecked == true; - + options.KeepAlivePeriod = TimeSpan.FromSeconds(double.Parse(KeepAliveInterval.Text)); + try { if (_mqttClient != null) From 2cb1c544f5dfb24d38b10f93ade1fe031441f349 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Mon, 4 Dec 2017 22:40:44 +0100 Subject: [PATCH 075/149] Add extension method for subscriptions --- Build/MQTTnet.Extensions.Rpc.nuspec | 47 +++++++++++++++++++ Build/build.ps1 | 10 ++++ .../MQTTnet.Extensions.Rpc/MqttRpcClient.cs | 2 +- .../MQTTnet.Extensions.Rpc/SampleCCode.c | 1 + .../Client/MqttClientExtensions.cs | 9 ++++ .../MainPage.xaml | 2 + .../MainPage.xaml.cs | 1 + 7 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 Build/MQTTnet.Extensions.Rpc.nuspec create mode 100644 Extensions/MQTTnet.Extensions.Rpc/SampleCCode.c diff --git a/Build/MQTTnet.Extensions.Rpc.nuspec b/Build/MQTTnet.Extensions.Rpc.nuspec new file mode 100644 index 00000000..ec09c1de --- /dev/null +++ b/Build/MQTTnet.Extensions.Rpc.nuspec @@ -0,0 +1,47 @@ + + + + MQTTnet.Extensions.Rpc + 2.6.0 + Christian Kratky + Christian Kratky + https://github.com/chkr1011/MQTTnet/blob/master/LICENSE + https://github.com/chkr1011/MQTTnet + https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png + false + This is a extension library which allows executing synchronous device calls including a response using MQTTnet. + * Initial version. + + Copyright Christian Kratky 2016-2017 + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Build/build.ps1 b/Build/build.ps1 index 09eabf25..2b4ee5f2 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -8,16 +8,26 @@ $path = &$vswhere -latest -products * -requires Microsoft.Component.MSBuild -pro if ($path) { $msbuild = join-path $path 'MSBuild\15.0\Bin\MSBuild.exe' + # Build the core library &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m + # Build the ASP.NET Core 2.0 extension &$msbuild ..\Frameworks\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m + # Build the RPC extension + &$msbuild ..\Extensions\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m + &$msbuild ..\Extensions\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m + &$msbuild ..\Extensions\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m + &$msbuild ..\Extensions\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m + &$msbuild ..\Extensions\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m + Remove-Item .\NuGet -Force -Recurse New-Item -ItemType Directory -Force -Path .\NuGet .\NuGet.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion .\NuGet.exe pack MQTTnet.AspNetCore.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion + .\NuGet.exe pack MQTTnet.Extensions.Rpc.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion } \ No newline at end of file diff --git a/Extensions/MQTTnet.Extensions.Rpc/MqttRpcClient.cs b/Extensions/MQTTnet.Extensions.Rpc/MqttRpcClient.cs index 6a9d1c1c..938fcb4c 100644 --- a/Extensions/MQTTnet.Extensions.Rpc/MqttRpcClient.cs +++ b/Extensions/MQTTnet.Extensions.Rpc/MqttRpcClient.cs @@ -9,7 +9,7 @@ namespace MQTTnet.Extensions.Rpc { public sealed class MqttRpcClient : IDisposable { - private const string ResponseTopic = "$RPC/+/+/response"; + private const string ResponseTopic = "$MQTTnet.RPC/+/+/response"; private readonly ConcurrentDictionary> _waitingCalls = new ConcurrentDictionary>(); private readonly IMqttClient _mqttClient; private bool _isEnabled; diff --git a/Extensions/MQTTnet.Extensions.Rpc/SampleCCode.c b/Extensions/MQTTnet.Extensions.Rpc/SampleCCode.c new file mode 100644 index 00000000..5f282702 --- /dev/null +++ b/Extensions/MQTTnet.Extensions.Rpc/SampleCCode.c @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClientExtensions.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientExtensions.cs index a1a89e30..73f4d40c 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClientExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using MQTTnet.Protocol; namespace MQTTnet.Client { @@ -15,6 +16,14 @@ namespace MQTTnet.Client return client.SubscribeAsync(topicFilters.ToList()); } + public static Task> SubscribeAsync(this IMqttClient client, string topic, MqttQualityOfServiceLevel qualityOfServiceLevel) + { + if (client == null) throw new ArgumentNullException(nameof(client)); + if (topic == null) throw new ArgumentNullException(nameof(topic)); + + return client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build()); + } + public static Task UnsubscribeAsync(this IMqttClient client, params string[] topicFilters) { if (client == null) throw new ArgumentNullException(nameof(client)); diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml index 939061be..dcdee000 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml @@ -19,6 +19,8 @@ Server: + Port: + User: Password: diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index ec42bacd..a48b7ee5 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -78,6 +78,7 @@ namespace MQTTnet.TestApp.UniversalWindows options.ChannelOptions = new MqttClientTcpOptions { Server = Server.Text, + Port = int.Parse(Port.Text), TlsOptions = tlsOptions }; } From f974dcb647c98ca467057f13cff61f215175d313 Mon Sep 17 00:00:00 2001 From: cvellan <34144841+cvellan@users.noreply.github.com> Date: Tue, 5 Dec 2017 10:13:07 +1100 Subject: [PATCH 076/149] Serialized certificates loaded as X509Certificate2 Instances of X509Certificate2 passed into an MqttClientOptionsBuilder lose data and functionality by being loaded as an X509Certificate. --- .../MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs index ce9dcf6c..8fa93ff8 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs @@ -130,7 +130,7 @@ namespace MQTTnet.Implementations foreach (var certificate in options.TlsOptions.Certificates) { - certificates.Add(new X509Certificate(certificate)); + certificates.Add(new X509Certificate2(certificate)); } return certificates; @@ -155,4 +155,4 @@ namespace MQTTnet.Implementations } } -#endif \ No newline at end of file +#endif From 333fc4c387002539104e16c9ee06bebe06baa531 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Thu, 7 Dec 2017 20:35:29 +0100 Subject: [PATCH 077/149] Fixed an TLS issue in the MqttClientOptionsBuilder; Fix a subscription issue in the managed client. --- .gitignore | 1 + Build/MQTTnet.nuspec | 2 + .../MQTTnet.NetStandard/Client/IMqttClient.cs | 2 +- .../MQTTnet.NetStandard/Client/MqttClient.cs | 7 +- .../Client/MqttClientOptionsBuilder.cs | 6 +- .../ManagedClient/IManagedMqttClient.cs | 2 +- .../ManagedClient/ManagedMqttClient.cs | 100 +++++++++++------- .../Server/MqttClientSession.cs | 2 +- Frameworks/MQTTnet.NetStandard/TopicFilter.cs | 9 +- .../ManagedClientTest.cs | 3 +- 10 files changed, 83 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index 7c38d7d9..1e47707e 100644 --- a/.gitignore +++ b/.gitignore @@ -293,3 +293,4 @@ Build/nuget.exe *.map *codeSigningKey.pfx +/Tests/MQTTnet.TestApp.NetCore/RetainedMessages.json diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index ab982c04..096c2b12 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -16,6 +16,8 @@ * [Core] Fixed a logging issue when dealing with IOExceptions. * [Core] Fixed a typo in the global logger class (BREAKING CHANGE! Please find new example in Wiki). * [Client] Fixed an issue in _ManagedClient_ which can cause the client to stop when publishing subscriptions. +* [Client] Fixed an issue in _ManagedClient_ which prevents changing the QoS of an existing subscription (BREAKING CHANGE!). +* [Client] Fixed an issue in _MqttClientOptionsBuilder_ which prevents adding TLS options to the client options when calling _Build()_. (Thanks to @cvellan). * [Server] The application message interceptor can now delete any received application message. * [Server] Added a ConnectionValidator context to align with other APIs (BREAKING CHANGE! Please find new example in Wiki). * [Server] Added an interface for the _MqttServerOptions_. diff --git a/Frameworks/MQTTnet.NetStandard/Client/IMqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/IMqttClient.cs index 0ac2f491..42ca0a4e 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/IMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/IMqttClient.cs @@ -15,6 +15,6 @@ namespace MQTTnet.Client Task DisconnectAsync(); Task> SubscribeAsync(IEnumerable topicFilters); - Task UnsubscribeAsync(IEnumerable topicFilters); + Task UnsubscribeAsync(IEnumerable topics); } } \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs index b5592e0d..9625808b 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs @@ -12,7 +12,7 @@ using MQTTnet.Protocol; namespace MQTTnet.Client { - public class MqttClient : IMqttClient + public class MqttClient : IMqttClient, IDisposable { private readonly IMqttClientAdapterFactory _adapterFactory; private readonly MqttPacketDispatcher _packetDispatcher; @@ -180,6 +180,11 @@ namespace MQTTnet.Client } } + public void Dispose() + { + _cancellationTokenSource?.Dispose(); + } + private async Task AuthenticateAsync(MqttApplicationMessage willApplicationMessage) { var connectPacket = new MqttConnectPacket diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClientOptionsBuilder.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientOptionsBuilder.cs index 079e6351..ad766c3f 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClientOptionsBuilder.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientOptionsBuilder.cs @@ -119,11 +119,11 @@ namespace MQTTnet.Client if (_tcpOptions != null) { - _options.ChannelOptions = _tcpOptions; + _tcpOptions.TlsOptions = _tlsOptions; } - else + else if (_webSocketOptions != null) { - _options.ChannelOptions = _webSocketOptions; + _webSocketOptions.TlsOptions = _tlsOptions; } } diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs index 41c0ce3b..24759596 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs @@ -16,6 +16,6 @@ namespace MQTTnet.ManagedClient Task StopAsync(); Task SubscribeAsync(IEnumerable topicFilters); - Task UnsubscribeAsync(IEnumerable topicFilters); + Task UnsubscribeAsync(IEnumerable topics); } } \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs index 9b011563..01fa4cd9 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs @@ -11,10 +11,10 @@ using MQTTnet.Protocol; namespace MQTTnet.ManagedClient { - public class ManagedMqttClient : IManagedMqttClient + public class ManagedMqttClient : IManagedMqttClient, IDisposable { private readonly BlockingCollection _messageQueue = new BlockingCollection(); - private readonly HashSet _subscriptions = new HashSet(); + private readonly Dictionary _subscriptions = new Dictionary(); private readonly SemaphoreSlim _subscriptionsSemaphore = new SemaphoreSlim(1, 1); private readonly IMqttClient _mqttClient; @@ -75,11 +75,8 @@ namespace MQTTnet.ManagedClient public Task StopAsync() { - _connectionCancellationToken?.Cancel(false); - _connectionCancellationToken = null; - - _publishingCancellationToken?.Cancel(false); - _publishingCancellationToken = null; + StopPublishing(); + StopMaintainingConnection(); while (_messageQueue.Any()) { @@ -88,7 +85,7 @@ namespace MQTTnet.ManagedClient return Task.FromResult(0); } - + public async Task PublishAsync(IEnumerable applicationMessages) { if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages)); @@ -113,7 +110,24 @@ namespace MQTTnet.ManagedClient { foreach (var topicFilter in topicFilters) { - if (_subscriptions.Add(topicFilter)) + _subscriptions[topicFilter.Topic] = topicFilter.QualityOfServiceLevel; + _subscriptionsNotPushed = true; + } + } + finally + { + _subscriptionsSemaphore.Release(); + } + } + + public async Task UnsubscribeAsync(IEnumerable topics) + { + await _subscriptionsSemaphore.WaitAsync().ConfigureAwait(false); + try + { + foreach (var topic in topics) + { + if (_subscriptions.Remove(topic)) { _subscriptionsNotPushed = true; } @@ -125,23 +139,12 @@ namespace MQTTnet.ManagedClient } } - public async Task UnsubscribeAsync(IEnumerable topicFilters) + public void Dispose() { - await _subscriptionsSemaphore.WaitAsync().ConfigureAwait(false); - try - { - foreach (var topicFilter in topicFilters) - { - if (_subscriptions.Remove(topicFilter)) - { - _subscriptionsNotPushed = true; - } - } - } - finally - { - _subscriptionsSemaphore.Release(); - } + _messageQueue?.Dispose(); + _subscriptionsSemaphore?.Dispose(); + _connectionCancellationToken?.Dispose(); + _publishingCancellationToken?.Dispose(); } private async Task MaintainConnectionAsync(CancellationToken cancellationToken) @@ -174,9 +177,7 @@ namespace MQTTnet.ManagedClient var connectionState = await ReconnectIfRequiredAsync().ConfigureAwait(false); if (connectionState == ReconnectionResult.NotConnected) { - _publishingCancellationToken?.Cancel(false); - _publishingCancellationToken = null; - + StopPublishing(); await Task.Delay(_options.AutoReconnectDelay, cancellationToken).ConfigureAwait(false); return; } @@ -185,18 +186,15 @@ namespace MQTTnet.ManagedClient { await PushSubscriptionsAsync().ConfigureAwait(false); - _publishingCancellationToken = new CancellationTokenSource(); - -#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - Task.Run(async () => await PublishQueuedMessagesAsync(_publishingCancellationToken.Token).ConfigureAwait(false), _publishingCancellationToken.Token).ConfigureAwait(false); -#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + StartPublishing(); + return; } if (connectionState == ReconnectionResult.StillConnected) { - await Task.Delay(TimeSpan.FromSeconds(1), _connectionCancellationToken.Token).ConfigureAwait(false); + await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException) @@ -211,7 +209,7 @@ namespace MQTTnet.ManagedClient _logger.Error(exception, "Unhandled exception while maintaining connection."); } } - + private async Task PublishQueuedMessagesAsync(CancellationToken cancellationToken) { try @@ -279,7 +277,7 @@ namespace MQTTnet.ManagedClient await _subscriptionsSemaphore.WaitAsync().ConfigureAwait(false); try { - subscriptions = _subscriptions.ToList(); + subscriptions = _subscriptions.Select(i => new TopicFilter(i.Key, i.Value)).ToList(); _subscriptionsNotPushed = false; } finally @@ -335,5 +333,35 @@ namespace MQTTnet.ManagedClient { Connected?.Invoke(this, eventArgs); } + + private void StartPublishing() + { + if (_publishingCancellationToken != null) + { + StopPublishing(); + } + + var cts = new CancellationTokenSource(); + + _publishingCancellationToken = cts; + +#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + Task.Run(async () => await PublishQueuedMessagesAsync(cts.Token).ConfigureAwait(false), cts.Token).ConfigureAwait(false); +#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + } + + private void StopPublishing() + { + _publishingCancellationToken?.Cancel(false); + _publishingCancellationToken?.Dispose(); + _publishingCancellationToken = null; + } + + private void StopMaintainingConnection() + { + _connectionCancellationToken?.Cancel(false); + _connectionCancellationToken?.Dispose(); + _connectionCancellationToken = null; + } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index a321d934..9615f86e 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -232,8 +232,8 @@ namespace MQTTnet.Server private async Task HandleIncomingSubscribePacketAsync(IMqttChannelAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken) { var subscribeResult = await _subscriptionsManager.SubscribeAsync(subscribePacket, ClientId); - await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, subscribeResult.ResponsePacket).ConfigureAwait(false); + if (subscribeResult.CloseConnection) { await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttDisconnectPacket()).ConfigureAwait(false); diff --git a/Frameworks/MQTTnet.NetStandard/TopicFilter.cs b/Frameworks/MQTTnet.NetStandard/TopicFilter.cs index da126d6d..1dad73d0 100644 --- a/Frameworks/MQTTnet.NetStandard/TopicFilter.cs +++ b/Frameworks/MQTTnet.NetStandard/TopicFilter.cs @@ -10,14 +10,9 @@ namespace MQTTnet QualityOfServiceLevel = qualityOfServiceLevel; } - public string Topic { get; } + public string Topic { get; set; } - public MqttQualityOfServiceLevel QualityOfServiceLevel { get; } - - public override int GetHashCode() - { - return QualityOfServiceLevel.GetHashCode() ^ (Topic ?? string.Empty).GetHashCode(); - } + public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; } public override string ToString() { diff --git a/Tests/MQTTnet.TestApp.NetCore/ManagedClientTest.cs b/Tests/MQTTnet.TestApp.NetCore/ManagedClientTest.cs index 21d1fdf8..e23e9945 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ManagedClientTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ManagedClientTest.cs @@ -45,7 +45,8 @@ namespace MQTTnet.TestApp.NetCore await managedClient.StartAsync(options); await managedClient.SubscribeAsync(new TopicFilter("xyz", MqttQualityOfServiceLevel.AtMostOnce)); - + await managedClient.SubscribeAsync(new TopicFilter("abc", MqttQualityOfServiceLevel.AtMostOnce)); + await managedClient.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("Step").WithPayload("3").Build()); Console.WriteLine("Managed client started."); From ad8506cc30e70c10d1208327f97564fb2fd68546 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Thu, 7 Dec 2017 20:41:44 +0100 Subject: [PATCH 078/149] Update documents --- Build/MQTTnet.nuspec | 1 + 1 file changed, 1 insertion(+) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 096c2b12..ee3138c6 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -15,6 +15,7 @@ * [Core] Performance optimizations. * [Core] Fixed a logging issue when dealing with IOExceptions. * [Core] Fixed a typo in the global logger class (BREAKING CHANGE! Please find new example in Wiki). +* [Client] The certificate for encryption is now loaded as a _X509Certificate2_ which prodives more data (Thanks to @cvellan). * [Client] Fixed an issue in _ManagedClient_ which can cause the client to stop when publishing subscriptions. * [Client] Fixed an issue in _ManagedClient_ which prevents changing the QoS of an existing subscription (BREAKING CHANGE!). * [Client] Fixed an issue in _MqttClientOptionsBuilder_ which prevents adding TLS options to the client options when calling _Build()_. (Thanks to @cvellan). From fb8b60fcccf5d3922ea010dd37ee51aa70e5eb80 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Fri, 8 Dec 2017 21:12:05 +0100 Subject: [PATCH 079/149] Add overload for subscribing. --- Build/MQTTnet.nuspec | 1 + .../ManagedClient/ManagedMqttClientExtensions.cs | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index ee3138c6..e7ed1cd6 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -19,6 +19,7 @@ * [Client] Fixed an issue in _ManagedClient_ which can cause the client to stop when publishing subscriptions. * [Client] Fixed an issue in _ManagedClient_ which prevents changing the QoS of an existing subscription (BREAKING CHANGE!). * [Client] Fixed an issue in _MqttClientOptionsBuilder_ which prevents adding TLS options to the client options when calling _Build()_. (Thanks to @cvellan). +* [Client] Added an overload for subscribing at both clients which reduces required code. * [Server] The application message interceptor can now delete any received application message. * [Server] Added a ConnectionValidator context to align with other APIs (BREAKING CHANGE! Please find new example in Wiki). * [Server] Added an interface for the _MqttServerOptions_. diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientExtensions.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientExtensions.cs index e1346679..d75117a5 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using MQTTnet.Protocol; namespace MQTTnet.ManagedClient { @@ -12,7 +13,15 @@ namespace MQTTnet.ManagedClient return managedClient.SubscribeAsync(topicFilters); } - public static Task UnsubscribeAsync(this IManagedMqttClient managedClient, params TopicFilter[] topicFilters) + public static Task SubscribeAsync(this IManagedMqttClient managedClient, string topic, MqttQualityOfServiceLevel qualityOfServiceLevel) + { + if (managedClient == null) throw new ArgumentNullException(nameof(managedClient)); + if (topic == null) throw new ArgumentNullException(nameof(topic)); + + return managedClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build()); + } + + public static Task UnsubscribeAsync(this IManagedMqttClient managedClient, params string[] topicFilters) { if (managedClient == null) throw new ArgumentNullException(nameof(managedClient)); From f91d935708f43b486f36623c60579570f2b91a9a Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Mon, 11 Dec 2017 17:10:27 +0100 Subject: [PATCH 080/149] Add the ClientId to the application message interceptor. --- Build/MQTTnet.nuspec | 1 + .../Implementations/MqttServerAdapter.cs | 2 +- .../MqttApplicationMessageInterceptorContext.cs | 8 ++++++++ .../Server/MqttClientSessionsManager.cs | 15 +++++++-------- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index e7ed1cd6..d1074617 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -20,6 +20,7 @@ * [Client] Fixed an issue in _ManagedClient_ which prevents changing the QoS of an existing subscription (BREAKING CHANGE!). * [Client] Fixed an issue in _MqttClientOptionsBuilder_ which prevents adding TLS options to the client options when calling _Build()_. (Thanks to @cvellan). * [Client] Added an overload for subscribing at both clients which reduces required code. +* [Client] Added the _ClientId_ to the application message interceptor context. * [Server] The application message interceptor can now delete any received application message. * [Server] Added a ConnectionValidator context to align with other APIs (BREAKING CHANGE! Please find new example in Wiki). * [Server] Added an interface for the _MqttServerOptions_. diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs index a0441bcc..c991c23a 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs @@ -145,7 +145,7 @@ namespace MQTTnet.Implementations var sslStream = new SslStream(new NetworkStream(clientSocket)); await sslStream.AuthenticateAsServerAsync(_tlsCertificate, false, SslProtocols.Tls12, false).ConfigureAwait(false); - + var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, sslStream), new MqttPacketSerializer(), _logger); ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter)); } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttApplicationMessageInterceptorContext.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttApplicationMessageInterceptorContext.cs index e5f8c3f7..8074d527 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttApplicationMessageInterceptorContext.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttApplicationMessageInterceptorContext.cs @@ -2,6 +2,14 @@ { public class MqttApplicationMessageInterceptorContext { + public MqttApplicationMessageInterceptorContext(string clientId, MqttApplicationMessage applicationMessage) + { + ClientId = clientId; + ApplicationMessage = applicationMessage; + } + + public string ClientId { get; } + public MqttApplicationMessage ApplicationMessage { get; set; } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index 7b4d6d14..28dac0d7 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -136,7 +136,7 @@ namespace MQTTnet.Server { try { - applicationMessage = InterceptApplicationMessage(applicationMessage); + applicationMessage = InterceptApplicationMessage(senderClientSession, applicationMessage); if (applicationMessage == null) { return; @@ -168,17 +168,16 @@ namespace MQTTnet.Server } } - private MqttApplicationMessage InterceptApplicationMessage(MqttApplicationMessage applicationMessage) + private MqttApplicationMessage InterceptApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage) { if (_options.ApplicationMessageInterceptor == null) { return applicationMessage; } - var interceptorContext = new MqttApplicationMessageInterceptorContext - { - ApplicationMessage = applicationMessage - }; + var interceptorContext = new MqttApplicationMessageInterceptorContext( + senderClientSession.ClientId, + applicationMessage); _options.ApplicationMessageInterceptor(interceptorContext); return interceptorContext.ApplicationMessage; @@ -190,7 +189,7 @@ namespace MQTTnet.Server { return MqttConnectReturnCode.ConnectionAccepted; } - + var context = new MqttConnectionValidatorContext( connectPacket.ClientId, connectPacket.Username, @@ -210,7 +209,7 @@ namespace MQTTnet.Server if (isSessionPresent) { if (connectPacket.CleanSession) - { + { _sessions.Remove(connectPacket.ClientId); await clientSession.StopAsync().ConfigureAwait(false); From 0f54663789b92122ee8def388c315e9a97393786 Mon Sep 17 00:00:00 2001 From: limingru Date: Tue, 12 Dec 2017 17:21:22 +0800 Subject: [PATCH 081/149] fixed: Compile Source Code Occur Errors On Mac Machine --- Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj index 92920cd3..5436ad45 100644 --- a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -1,7 +1,8 @@  - netstandard1.3;netstandard2.0;net452;net461;uap10.0 + netstandard1.3;netstandard2.0;net452;net461;uap10.0 + netstandard1.3;netstandard2.0 MQTTnet MQTTnet False @@ -14,9 +15,9 @@ - true + From e98ff1d6d6afc6ce24b50f022bcbd9baed75254f Mon Sep 17 00:00:00 2001 From: limingru Date: Tue, 12 Dec 2017 17:26:16 +0800 Subject: [PATCH 082/149] uncomment code --- Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj index 5436ad45..70415cd9 100644 --- a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -15,9 +15,9 @@ - + false From f6b38081fcdb84ed94e30944c9637da2f5f734c8 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 12 Dec 2017 14:30:28 +0100 Subject: [PATCH 083/149] Update documents. --- Build/MQTTnet.nuspec | 1 + 1 file changed, 1 insertion(+) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index d1074617..c32772b8 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -15,6 +15,7 @@ * [Core] Performance optimizations. * [Core] Fixed a logging issue when dealing with IOExceptions. * [Core] Fixed a typo in the global logger class (BREAKING CHANGE! Please find new example in Wiki). +* [Core] Added support for project compilation under macOS (Thanks to @FourOnes). * [Client] The certificate for encryption is now loaded as a _X509Certificate2_ which prodives more data (Thanks to @cvellan). * [Client] Fixed an issue in _ManagedClient_ which can cause the client to stop when publishing subscriptions. * [Client] Fixed an issue in _ManagedClient_ which prevents changing the QoS of an existing subscription (BREAKING CHANGE!). From 44c07c20344a7f7221913c31c7ae6e674b7a8c90 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Thu, 14 Dec 2017 13:12:18 +0100 Subject: [PATCH 084/149] Fix broken ASP.NET Core integration. --- Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs b/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs index 7c7d3041..8e6761ad 100644 --- a/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs +++ b/Frameworks/MQTTnet.AspnetCore/MqttHostedServer.cs @@ -11,9 +11,9 @@ namespace MQTTnet.AspNetCore { public class MqttHostedServer : MqttServer, IHostedService { - private readonly MqttServerOptions _options; + private readonly IMqttServerOptions _options; - public MqttHostedServer(MqttServerOptions options, IEnumerable adapters, IMqttNetLogger logger) : base(adapters, logger) + public MqttHostedServer(IMqttServerOptions options, IEnumerable adapters, IMqttNetLogger logger) : base(adapters, logger) { _options = options ?? throw new ArgumentNullException(nameof(options)); } From e0284886b5ea5cc4c6dd2f38ff6fd256e055b687 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Thu, 14 Dec 2017 13:23:12 +0100 Subject: [PATCH 085/149] Added the bound IP address to the server options. --- .../Implementations/MqttServerAdapter.cs | 4 +- .../Server/IMqttServerOptions.cs | 12 ++++-- .../MqttServerDefaultEndpointOptions.cs | 6 ++- .../Server/MqttServerOptionsBuilder.cs | 37 ++++++++++++++----- .../Server/MqttServerTlsEndpointOptions.cs | 6 ++- 5 files changed, 48 insertions(+), 17 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs index c991c23a..b4869ffd 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs @@ -39,7 +39,7 @@ namespace MQTTnet.Implementations if (options.DefaultEndpointOptions.IsEnabled) { _defaultEndpointSocket = new Socket(SocketType.Stream, ProtocolType.Tcp); - _defaultEndpointSocket.Bind(new IPEndPoint(IPAddress.Any, options.GetDefaultEndpointPort())); + _defaultEndpointSocket.Bind(new IPEndPoint(options.DefaultEndpointOptions.BoundIPAddress, options.GetDefaultEndpointPort())); _defaultEndpointSocket.Listen(options.ConnectionBacklog); Task.Run(async () => await AcceptDefaultEndpointConnectionsAsync(_cancellationTokenSource.Token).ConfigureAwait(false), _cancellationTokenSource.Token).ConfigureAwait(false); @@ -59,7 +59,7 @@ namespace MQTTnet.Implementations } _tlsEndpointSocket = new Socket(SocketType.Stream, ProtocolType.Tcp); - _tlsEndpointSocket.Bind(new IPEndPoint(IPAddress.Any, options.GetTlsEndpointPort())); + _tlsEndpointSocket.Bind(new IPEndPoint(options.TlsEndpointOptions.BoundIPAddress, options.GetTlsEndpointPort())); _tlsEndpointSocket.Listen(options.ConnectionBacklog); Task.Run(async () => await AcceptTlsEndpointConnectionsAsync(_cancellationTokenSource.Token).ConfigureAwait(false), _cancellationTokenSource.Token).ConfigureAwait(false); diff --git a/Frameworks/MQTTnet.NetStandard/Server/IMqttServerOptions.cs b/Frameworks/MQTTnet.NetStandard/Server/IMqttServerOptions.cs index 92c1bfb7..d89d9150 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/IMqttServerOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/IMqttServerOptions.cs @@ -1,16 +1,20 @@ using System; +using System.Net; namespace MQTTnet.Server { public interface IMqttServerOptions { - Action ApplicationMessageInterceptor { get; } int ConnectionBacklog { get; } - Action ConnectionValidator { get; } TimeSpan DefaultCommunicationTimeout { get; } - MqttServerDefaultEndpointOptions DefaultEndpointOptions { get; } - IMqttServerStorage Storage { get; } + + Action ConnectionValidator { get; } Action SubscriptionInterceptor { get; } + Action ApplicationMessageInterceptor { get; } + + MqttServerDefaultEndpointOptions DefaultEndpointOptions { get; } MqttServerTlsEndpointOptions TlsEndpointOptions { get; } + + IMqttServerStorage Storage { get; } } } \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttServerDefaultEndpointOptions.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServerDefaultEndpointOptions.cs index 6dc21b32..545499b5 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttServerDefaultEndpointOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServerDefaultEndpointOptions.cs @@ -1,9 +1,13 @@ -namespace MQTTnet.Server +using System.Net; + +namespace MQTTnet.Server { public sealed class MqttServerDefaultEndpointOptions { public bool IsEnabled { get; set; } = true; public int? Port { get; set; } + + public IPAddress BoundIPAddress { get; set; } = IPAddress.Any; } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsBuilder.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsBuilder.cs index 34f36a95..18b2de29 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsBuilder.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServerOptionsBuilder.cs @@ -1,4 +1,5 @@ using System; +using System.Net; namespace MQTTnet.Server { @@ -18,33 +19,45 @@ namespace MQTTnet.Server return this; } - public MqttServerOptionsBuilder WithDefaultEndpointPort(int value) - { - _options.DefaultEndpointOptions.Port = value; - return this; - } - public MqttServerOptionsBuilder WithDefaultEndpoint() { _options.DefaultEndpointOptions.IsEnabled = true; return this; } + public MqttServerOptionsBuilder WithDefaultEndpointPort(int? value) + { + _options.DefaultEndpointOptions.Port = value; + return this; + } + + public MqttServerOptionsBuilder WithDefaultEndpointBoundIPAddress(IPAddress value) + { + _options.DefaultEndpointOptions.BoundIPAddress = value ?? IPAddress.Any; + return this; + } + public MqttServerOptionsBuilder WithoutDefaultEndpoint() { _options.DefaultEndpointOptions.IsEnabled = false; return this; } - + public MqttServerOptionsBuilder WithEncryptedEndpoint() { _options.TlsEndpointOptions.IsEnabled = true; return this; } - public MqttServerOptionsBuilder WithoutEncryptedEndpoint() + public MqttServerOptionsBuilder WithEncryptedEndpointPort(int? value) { - _options.TlsEndpointOptions.IsEnabled = false; + _options.TlsEndpointOptions.Port = value; + return this; + } + + public MqttServerOptionsBuilder WithEncryptedEndpointBoundIPAddress(IPAddress value) + { + _options.TlsEndpointOptions.BoundIPAddress = value; return this; } @@ -54,6 +67,12 @@ namespace MQTTnet.Server return this; } + public MqttServerOptionsBuilder WithoutEncryptedEndpoint() + { + _options.TlsEndpointOptions.IsEnabled = false; + return this; + } + public MqttServerOptionsBuilder WithStorage(IMqttServerStorage value) { _options.Storage = value; diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttServerTlsEndpointOptions.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServerTlsEndpointOptions.cs index 6c90a446..73be93c5 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttServerTlsEndpointOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServerTlsEndpointOptions.cs @@ -1,4 +1,6 @@ -namespace MQTTnet.Server +using System.Net; + +namespace MQTTnet.Server { public sealed class MqttServerTlsEndpointOptions { @@ -7,5 +9,7 @@ public int? Port { get; set; } public byte[] Certificate { get; set; } + + public IPAddress BoundIPAddress { get; set; } = IPAddress.Any; } } From 5ddb6b77e2d16f195141e1a555db036540ead766 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Thu, 14 Dec 2017 13:24:50 +0100 Subject: [PATCH 086/149] Update documentation --- Build/MQTTnet.nuspec | 1 + 1 file changed, 1 insertion(+) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index c32772b8..8faaf794 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -29,6 +29,7 @@ * [Server] Fixed a security issue which sends retained packages to a failed subscription. * [Server] Fixed the response (MaximumQoS) of a subscription (Thanks to @redbeans2017). * [Server] The keep alive timeouts are now checked for every client (Thanks to @RainerMueller82). +* [Server] The used IP addresses can be specified now (IPAddress.Any as default). Copyright Christian Kratky 2016-2017 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 312773d0549c5bd2b01881de8841ba6c6258d599 Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Fri, 22 Dec 2017 12:02:25 +0100 Subject: [PATCH 087/149] Add password protected code signing certificate to enable build process. --- .gitignore | 1 - .../MQTTnet.NetStandard/codeSigningKey.pfx | Bin 0 -> 1764 bytes 2 files changed, 1 deletion(-) create mode 100644 Frameworks/MQTTnet.NetStandard/codeSigningKey.pfx diff --git a/.gitignore b/.gitignore index 1e47707e..569e43ac 100644 --- a/.gitignore +++ b/.gitignore @@ -292,5 +292,4 @@ Build/nuget.exe *.js *.map -*codeSigningKey.pfx /Tests/MQTTnet.TestApp.NetCore/RetainedMessages.json diff --git a/Frameworks/MQTTnet.NetStandard/codeSigningKey.pfx b/Frameworks/MQTTnet.NetStandard/codeSigningKey.pfx new file mode 100644 index 0000000000000000000000000000000000000000..9374a5dbc11acc2a3a2c507ad3281f755fcbbf45 GIT binary patch literal 1764 zcmZXTcU0477sr1Y{u02E3Rsy6RF6!P5EC4TViG6<5|(8)6bdht4Pn**2~%VhDG)+r zRiF|;Rs(232}_WnBFNAn7@#7v0YUKX&z|>fPfyQ1_qpHuxzByh^T)kd7AS(l5Lgz- z1*NnSO%pfw!BDUw7MO-)fhiD9z_Jic|0p5Kkt{?hgl|D!0LuKYYp*m6Uc`boVOj7x ztTHJ5e+)goABkoX7*ju@%aL$6Y6!`KXGW>@w~Y-`14Vm$%t|J4kDqTZ6P+L4WA}$u z7G|cVzWO=rPM5wfIP-qtyt0lB$q9RZfl;2jH`j5_?H+F9>;~s$TY3gKglNc)7o8NO ze7LbE7vwGTl9VM=d7UKxRL#pd*=>j^2Jg!@OuS4?H+PszXH25Hvpu&B?YF0YC?2ia z+c&>@k2C6vei%8?-AgF9bj+B4I@jH@=B!s{pvnx1wN+0Re(2V7_ge?B>q zdHFIZ!gba3v|lxO;k{Ktous{`Tpu|>`6?-G4*zzsWxE>Vm%$<#P%2#|JnccIM@Gqd zu%^q)oXAITT6lZCy11?0+W2A<2)kju-CK_iCw7+hx$(4#6%wtm4UD_1$L&-yeOC1D zmu3aaXob)(G#136n~%L@2{jtY#{_RJg60lcTq+bM*J^Wp1$|~~>_y@66^1u&x1eXS zRL|PzXw*-N3Vxa7wlGgKJJiPOnwGfS+>U|9#YTA=tch(b{C>^w`GnH-F`6bV>NAP6 z(cu++Wu*^^YW(6UY~b)Kfu>97t4@NW-IbZWvAa&ROV=VtB^)iEv1e!4sc#)eUr1Nv z5v%-6b!#dA#_&$CS7%yR^_&pYgk7;{oG&UcmcgTazem_<<^YeCsRNmfSkStrT?e zS||EX*T5ariA5od^Pu_9SyT4-4idp#zIeEDdB8tyZZL-GpsZyp{I?z5?=WEz_0kH0xwYk_S$89R1TJ>r>J#A#5eptXD0belP2bQGR8iAa&O zHyoOzGlQiC{?4rp>Up{Euzr-RTR=2uUg|4vUU{gha4rG~C3YjItMBMNlp`7{q0 zWZ5(p98}3`bh?R*UvIrI7WnzB8Ykd<@d5MU)`l~za(|88==QO@{Kfm78_oTOp>}l2 zYgtdWF#dj^N|);q&cXzZ{ktJGdv$DwlyQ=;!>1b8+Pv0%5*l!MiRnRK6;yIwM5w=E z!aGh-ZaCyO2JWn-^J7$tVwc2uk2>|M6PFrc_-77iW?)aEi&C&)Nho#UYYz4-_6QaQ z?$O?lfGZ;9Ruv;2rrE~ZwaktU*j$VFvWM4^kCgM2S4msW`lZOXqIU#UV`58>!D@UO G;6DJc77}Ox literal 0 HcmV?d00001 From e1a9aa7d03911472a76f38e7b1cba199871d92cd Mon Sep 17 00:00:00 2001 From: kpreisser Date: Wed, 17 Jan 2018 11:10:39 +0100 Subject: [PATCH 088/149] Adjust the MqttClientPendingMessagesQueue and the MqttPacketReader to use asynchronous methods for long-running/blocking operations. Otherwise, Worker Threads from the .NET Threadpool are blocked while waiting for the next client message, and while waiting for the next message to send. --- .../Adapter/MqttChannelAdapter.cs | 2 +- .../Serializer/MqttPacketReader.cs | 23 +++++++++++-------- .../Server/MqttClientPendingMessagesQueue.cs | 16 +++++++++---- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index 0cbcc93e..491655d4 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -120,7 +120,7 @@ namespace MQTTnet.Adapter private static async Task ReceiveAsync(Stream stream, CancellationToken cancellationToken) { - var header = MqttPacketReader.ReadHeaderFromSource(stream, cancellationToken); + var header = await MqttPacketReader.ReadHeaderFromSourceAsync(stream, cancellationToken); if (header == null) { return null; diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs index a22707c1..ef078481 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs @@ -22,17 +22,18 @@ namespace MQTTnet.Serializer public bool EndOfRemainingData => BaseStream.Position == _header.BodyLength; - public static MqttPacketHeader ReadHeaderFromSource(Stream stream, CancellationToken cancellationToken) + public static async Task ReadHeaderFromSourceAsync(Stream stream, CancellationToken cancellationToken) { - var buffer = stream.ReadByte(); - if (buffer == -1) + byte[] singleByteBuf = new byte[1]; + var readCount = await stream.ReadAsync(singleByteBuf, 0, singleByteBuf.Length).ConfigureAwait(false); + if (readCount <= 0) { return null; } - - var fixedHeader = (byte)buffer; + + var fixedHeader = singleByteBuf[0]; var controlPacketType = (MqttControlPacketType)(fixedHeader >> 4); - var bodyLength = ReadBodyLengthFromSource(stream, cancellationToken); + var bodyLength = await ReadBodyLengthFromSourceAsync(stream, cancellationToken).ConfigureAwait(false); return new MqttPacketHeader { @@ -80,13 +81,15 @@ namespace MQTTnet.Serializer return ReadBytes(_header.BodyLength - (int)BaseStream.Position); } - private static int ReadBodyLengthFromSource(Stream stream, CancellationToken cancellationToken) + private static async Task ReadBodyLengthFromSourceAsync(Stream stream, CancellationToken cancellationToken) { // Alorithm taken from http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html. var multiplier = 1; var value = 0; byte encodedByte; + byte[] singleByteBuf = new byte[1]; + var readBytes = new List(); do { @@ -95,13 +98,13 @@ namespace MQTTnet.Serializer throw new TaskCanceledException(); } - var buffer = stream.ReadByte(); - if (buffer == -1) + int readCount = await stream.ReadAsync(singleByteBuf, 0, singleByteBuf.Length).ConfigureAwait(false); + if (readCount <= 0) { throw new MqttCommunicationException("Connection closed while reading remaining length data."); } - encodedByte = (byte)buffer; + encodedByte = singleByteBuf[0]; readBytes.Add(encodedByte); value += (byte)(encodedByte & 127) * multiplier; diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs index 2048d529..e092d3b1 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs @@ -12,7 +12,8 @@ namespace MQTTnet.Server { public sealed class MqttClientPendingMessagesQueue : IDisposable { - private readonly BlockingCollection _queue = new BlockingCollection(); + private readonly ConcurrentQueue _queue = new ConcurrentQueue(); + private readonly SemaphoreSlim _queueWaitSemaphore = new SemaphoreSlim(0); private readonly IMqttServerOptions _options; private readonly MqttClientSession _session; private readonly IMqttNetLogger _logger; @@ -40,7 +41,8 @@ namespace MQTTnet.Server { if (packet == null) throw new ArgumentNullException(nameof(packet)); - _queue.Add(packet); + _queue.Enqueue(packet); + _queueWaitSemaphore.Release(); _logger.Trace("Enqueued packet (ClientId: {0}).", _session.ClientId); } @@ -67,7 +69,10 @@ namespace MQTTnet.Server MqttBasePacket packet = null; try { - packet = _queue.Take(cancellationToken); + await _queueWaitSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + if (!_queue.TryDequeue(out packet)) { + throw new InvalidOperationException(); // should not happen + } await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, packet).ConfigureAwait(false); _logger.Trace("Enqueued packet sent (ClientId: {0}).", _session.ClientId); @@ -95,7 +100,8 @@ namespace MQTTnet.Server if (publishPacket.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) { publishPacket.Dup = true; - _queue.Add(packet, CancellationToken.None); + _queue.Enqueue(packet); + _queueWaitSemaphore.Release(); } } @@ -105,7 +111,7 @@ namespace MQTTnet.Server public void Dispose() { - _queue?.Dispose(); + _queueWaitSemaphore?.Dispose(); } } } From bb697e1bd9c9c2344c0eef6db817b97d8dde14ec Mon Sep 17 00:00:00 2001 From: kpreisser Date: Wed, 17 Jan 2018 11:29:48 +0100 Subject: [PATCH 089/149] Follow-Up: Add missing ConfigureAwait() call. --- Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index 491655d4..57b79725 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -120,7 +120,7 @@ namespace MQTTnet.Adapter private static async Task ReceiveAsync(Stream stream, CancellationToken cancellationToken) { - var header = await MqttPacketReader.ReadHeaderFromSourceAsync(stream, cancellationToken); + var header = await MqttPacketReader.ReadHeaderFromSourceAsync(stream, cancellationToken).ConfigureAwait(false); if (header == null) { return null; From 87731174938d7a3669bcbc9ed4c137f54371bb8e Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 21 Jan 2018 14:09:34 +0100 Subject: [PATCH 090/149] Fix an issue which adds a delay after every accepted connection. --- .../Implementations/MqttServerAdapter.cs | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs index b4869ffd..0d0429d3 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs @@ -110,22 +110,14 @@ namespace MQTTnet.Implementations { // It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed. } - catch (SocketException exception) + catch (Exception exception) { - if (exception.SocketErrorCode == SocketError.OperationAborted) + if (exception is SocketException s && s.SocketErrorCode == SocketError.OperationAborted) { return; } _logger.Error(exception, "Error while accepting connection at default endpoint."); - } - catch (Exception exception) - { - _logger.Error(exception, "Error while accepting connection at default endpoint."); - } - finally - { - //excessive CPU consumed if in endless loop of socket errors await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); } } @@ -153,22 +145,14 @@ namespace MQTTnet.Implementations { // It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed. } - catch (SocketException exception) + catch (Exception exception) { - if (exception.SocketErrorCode == SocketError.OperationAborted) + if (exception is SocketException s && s.SocketErrorCode == SocketError.OperationAborted) { return; } - _logger.Error(exception, "Error while accepting connection at default endpoint."); - } - catch (Exception exception) - { _logger.Error(exception, "Error while accepting connection at TLS endpoint."); - } - finally - { - //excessive CPU consumed if in endless loop of socket errors await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); } } From c7c84ad39b8a78e2d18a3e3742cf3b095d8ee618 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 21 Jan 2018 14:10:23 +0100 Subject: [PATCH 091/149] Make clients interfaces disposable. --- Frameworks/MQTTnet.NetStandard/Client/IMqttClient.cs | 2 +- Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs | 2 +- .../MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs | 2 +- .../MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Client/IMqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/IMqttClient.cs index 42ca0a4e..40d1a48a 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/IMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/IMqttClient.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; namespace MQTTnet.Client { - public interface IMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher + public interface IMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher, IDisposable { bool IsConnected { get; } diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs index 9625808b..78348160 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs @@ -12,7 +12,7 @@ using MQTTnet.Protocol; namespace MQTTnet.Client { - public class MqttClient : IMqttClient, IDisposable + public class MqttClient : IMqttClient { private readonly IMqttClientAdapterFactory _adapterFactory; private readonly MqttPacketDispatcher _packetDispatcher; diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs index 24759596..9d679086 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs @@ -5,7 +5,7 @@ using MQTTnet.Client; namespace MQTTnet.ManagedClient { - public interface IManagedMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher + public interface IManagedMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher, IDisposable { bool IsConnected { get; } diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs index 01fa4cd9..a7f5a1cf 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs @@ -11,7 +11,7 @@ using MQTTnet.Protocol; namespace MQTTnet.ManagedClient { - public class ManagedMqttClient : IManagedMqttClient, IDisposable + public class ManagedMqttClient : IManagedMqttClient { private readonly BlockingCollection _messageQueue = new BlockingCollection(); private readonly Dictionary _subscriptions = new Dictionary(); From 39672970e2e7124009ad90bf977f288ad0110a90 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 21 Jan 2018 14:13:50 +0100 Subject: [PATCH 092/149] Update 3rd-Partly libs --- Tests/MQTTnet.TestApp.AspNetCore2/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/MQTTnet.TestApp.AspNetCore2/package.json b/Tests/MQTTnet.TestApp.AspNetCore2/package.json index ad48ca10..56c9018c 100644 --- a/Tests/MQTTnet.TestApp.AspNetCore2/package.json +++ b/Tests/MQTTnet.TestApp.AspNetCore2/package.json @@ -6,7 +6,7 @@ }, "dependencies": { - "mqtt": "2.13.1", + "mqtt": "2.15.1", "@types/node": "8.0.46", "systemjs": "0.20.19", "typescript": "2.3.4" From ec9e64ebfb45b6fe40fecd2ad725fa2521b5b65e Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 21 Jan 2018 14:14:04 +0100 Subject: [PATCH 093/149] Update docs --- Build/MQTTnet.AspNetCore.nuspec | 8 ++++---- Build/MQTTnet.nuspec | 29 ++++++----------------------- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index 1510b2d8..2b099173 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -2,7 +2,7 @@ MQTTnet.AspNetCore - 2.6.0 + 2.7.0 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,13 +10,13 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false This is a support library to integrate MQTTnet into AspNetCore. - * Updated to MQTTnet 2.6.0. + * Updated to MQTTnet 2.7.0. - Copyright Christian Kratky 2016-2017 + Copyright Christian Kratky 2016-2018 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/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 8faaf794..b78c722c 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -2,7 +2,7 @@ MQTTnet - 2.6.0 + 2.7.0 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,28 +10,12 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * [Core] Merged projects (BREAKING CHANGE! But only namespace changes). -* [Core] Added a strong name for the assembly. -* [Core] Performance optimizations. -* [Core] Fixed a logging issue when dealing with IOExceptions. -* [Core] Fixed a typo in the global logger class (BREAKING CHANGE! Please find new example in Wiki). -* [Core] Added support for project compilation under macOS (Thanks to @FourOnes). -* [Client] The certificate for encryption is now loaded as a _X509Certificate2_ which prodives more data (Thanks to @cvellan). -* [Client] Fixed an issue in _ManagedClient_ which can cause the client to stop when publishing subscriptions. -* [Client] Fixed an issue in _ManagedClient_ which prevents changing the QoS of an existing subscription (BREAKING CHANGE!). -* [Client] Fixed an issue in _MqttClientOptionsBuilder_ which prevents adding TLS options to the client options when calling _Build()_. (Thanks to @cvellan). -* [Client] Added an overload for subscribing at both clients which reduces required code. -* [Client] Added the _ClientId_ to the application message interceptor context. -* [Server] The application message interceptor can now delete any received application message. -* [Server] Added a ConnectionValidator context to align with other APIs (BREAKING CHANGE! Please find new example in Wiki). -* [Server] Added an interface for the _MqttServerOptions_. -* [Server] Added packet statistics for the connected clients. -* [Server] Fixed a security issue which sends retained packages to a failed subscription. -* [Server] Fixed the response (MaximumQoS) of a subscription (Thanks to @redbeans2017). -* [Server] The keep alive timeouts are now checked for every client (Thanks to @RainerMueller82). -* [Server] The used IP addresses can be specified now (IPAddress.Any as default). + * [Core] Fixed some still thread blocking parts in the code (thanks to @kpreisser). +* [Core] Updated 3rd-Party packages. +* [Client] The client interfaces are now implementing _IDisposable_. +* [Server] Fixed an issue which lets the server block 1 second after accepting a new connection. - Copyright Christian Kratky 2016-2017 + Copyright Christian Kratky 2016-2018 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 @@ -75,7 +59,6 @@ - From f98f21ffdfe7d386a2a69b95997f02284a95b107 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 21 Jan 2018 14:29:36 +0100 Subject: [PATCH 094/149] Update libs --- Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj | 6 +++--- .../MQTTnet.TestApp.AspNetCore2.csproj | 2 +- .../MQTTnet.TestApp.UniversalWindows.csproj | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj b/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj index 1f23602d..a19f2b3b 100644 --- a/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj +++ b/Frameworks/MQTTnet.AspnetCore/MQTTnet.AspnetCore.csproj @@ -16,9 +16,9 @@ - - - + + + diff --git a/Tests/MQTTnet.TestApp.AspNetCore2/MQTTnet.TestApp.AspNetCore2.csproj b/Tests/MQTTnet.TestApp.AspNetCore2/MQTTnet.TestApp.AspNetCore2.csproj index 553b3417..0a720ca9 100644 --- a/Tests/MQTTnet.TestApp.AspNetCore2/MQTTnet.TestApp.AspNetCore2.csproj +++ b/Tests/MQTTnet.TestApp.AspNetCore2/MQTTnet.TestApp.AspNetCore2.csproj @@ -10,7 +10,7 @@ - + diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj index 5636dd20..2f4dd5f3 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj @@ -138,10 +138,10 @@ - 5.4.0 + 5.4.1 - 2.0.0 + 2.1.1 From 5e8d5b92198a11e0d8dfe0ec20594f25b301328f Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 21 Jan 2018 14:29:43 +0100 Subject: [PATCH 095/149] Add documents --- Documents/Import_CodeSigningKey.md | 6 ++ .../MQTTnet.NetStandard.csproj | 65 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 Documents/Import_CodeSigningKey.md create mode 100644 Frameworks/MQTTnet.Netstandard/MQTTnet.NetStandard.csproj diff --git a/Documents/Import_CodeSigningKey.md b/Documents/Import_CodeSigningKey.md new file mode 100644 index 00000000..66eb41f0 --- /dev/null +++ b/Documents/Import_CodeSigningKey.md @@ -0,0 +1,6 @@ +# Import codeSigningKey.pfx +In order to import the key for code signing on a new developer machine use the following command within the VS developer command line: + +> sn –i codeSigningKey.pfx VS_KEY_EFCA4C5B6DFD4B4F + +The container name may be different. \ No newline at end of file diff --git a/Frameworks/MQTTnet.Netstandard/MQTTnet.NetStandard.csproj b/Frameworks/MQTTnet.Netstandard/MQTTnet.NetStandard.csproj new file mode 100644 index 00000000..70415cd9 --- /dev/null +++ b/Frameworks/MQTTnet.Netstandard/MQTTnet.NetStandard.csproj @@ -0,0 +1,65 @@ + + + + netstandard1.3;netstandard2.0;net452;net461;uap10.0 + netstandard1.3;netstandard2.0 + MQTTnet + MQTTnet + False + Full + 0.0.0.0 + 0.0.0.0 + 0.0.0.0 + + + + + + true + codeSigningKey.pfx + false + + + + false + UAP,Version=v10.0 + UAP + 10.0.16299.0 + 10.0.10240.0 + .NETCore + v5.0 + $(DefineConstants);WINDOWS_UWP + $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets + + + + + + + + RELEASE;NETSTANDARD1_3 + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From d737f550c76c69c2feb6473bf20abfcea7c9e6c4 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 21 Jan 2018 14:33:29 +0100 Subject: [PATCH 096/149] Add encrypted code signing key --- .../MQTTnet.NetStandard/codeSigningKey.pfx | Bin 0 -> 1764 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Frameworks/MQTTnet.NetStandard/codeSigningKey.pfx diff --git a/Frameworks/MQTTnet.NetStandard/codeSigningKey.pfx b/Frameworks/MQTTnet.NetStandard/codeSigningKey.pfx new file mode 100644 index 0000000000000000000000000000000000000000..9374a5dbc11acc2a3a2c507ad3281f755fcbbf45 GIT binary patch literal 1764 zcmZXTcU0477sr1Y{u02E3Rsy6RF6!P5EC4TViG6<5|(8)6bdht4Pn**2~%VhDG)+r zRiF|;Rs(232}_WnBFNAn7@#7v0YUKX&z|>fPfyQ1_qpHuxzByh^T)kd7AS(l5Lgz- z1*NnSO%pfw!BDUw7MO-)fhiD9z_Jic|0p5Kkt{?hgl|D!0LuKYYp*m6Uc`boVOj7x ztTHJ5e+)goABkoX7*ju@%aL$6Y6!`KXGW>@w~Y-`14Vm$%t|J4kDqTZ6P+L4WA}$u z7G|cVzWO=rPM5wfIP-qtyt0lB$q9RZfl;2jH`j5_?H+F9>;~s$TY3gKglNc)7o8NO ze7LbE7vwGTl9VM=d7UKxRL#pd*=>j^2Jg!@OuS4?H+PszXH25Hvpu&B?YF0YC?2ia z+c&>@k2C6vei%8?-AgF9bj+B4I@jH@=B!s{pvnx1wN+0Re(2V7_ge?B>q zdHFIZ!gba3v|lxO;k{Ktous{`Tpu|>`6?-G4*zzsWxE>Vm%$<#P%2#|JnccIM@Gqd zu%^q)oXAITT6lZCy11?0+W2A<2)kju-CK_iCw7+hx$(4#6%wtm4UD_1$L&-yeOC1D zmu3aaXob)(G#136n~%L@2{jtY#{_RJg60lcTq+bM*J^Wp1$|~~>_y@66^1u&x1eXS zRL|PzXw*-N3Vxa7wlGgKJJiPOnwGfS+>U|9#YTA=tch(b{C>^w`GnH-F`6bV>NAP6 z(cu++Wu*^^YW(6UY~b)Kfu>97t4@NW-IbZWvAa&ROV=VtB^)iEv1e!4sc#)eUr1Nv z5v%-6b!#dA#_&$CS7%yR^_&pYgk7;{oG&UcmcgTazem_<<^YeCsRNmfSkStrT?e zS||EX*T5ariA5od^Pu_9SyT4-4idp#zIeEDdB8tyZZL-GpsZyp{I?z5?=WEz_0kH0xwYk_S$89R1TJ>r>J#A#5eptXD0belP2bQGR8iAa&O zHyoOzGlQiC{?4rp>Up{Euzr-RTR=2uUg|4vUU{gha4rG~C3YjItMBMNlp`7{q0 zWZ5(p98}3`bh?R*UvIrI7WnzB8Ykd<@d5MU)`l~za(|88==QO@{Kfm78_oTOp>}l2 zYgtdWF#dj^N|);q&cXzZ{ktJGdv$DwlyQ=;!>1b8+Pv0%5*l!MiRnRK6;yIwM5w=E z!aGh-ZaCyO2JWn-^J7$tVwc2uk2>|M6PFrc_-77iW?)aEi&C&)Nho#UYYz4-_6QaQ z?$O?lfGZ;9Ruv;2rrE~ZwaktU*j$VFvWM4^kCgM2S4msW`lZOXqIU#UV`58>!D@UO G;6DJc77}Ox literal 0 HcmV?d00001 From c060c379d3623f27691dcfb722aea836358e5884 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 22 Jan 2018 20:55:06 +0100 Subject: [PATCH 097/149] Add thrown exception for disconnected event --- .../MQTTnet.NetStandard/Client/MqttClient.cs | 25 ++++++++++--------- .../Client/MqttClientDisconnectedEventArgs.cs | 5 +++- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs index 78348160..a4ec82fa 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs @@ -75,7 +75,8 @@ namespace MQTTnet.Client catch (Exception exception) { _logger.Error(exception, "Error while connecting with server."); - await DisconnectInternalAsync().ConfigureAwait(false); + await DisconnectInternalAsync(exception).ConfigureAwait(false); + throw; } } @@ -93,7 +94,7 @@ namespace MQTTnet.Client } finally { - await DisconnectInternalAsync().ConfigureAwait(false); + await DisconnectInternalAsync(null).ConfigureAwait(false); } } @@ -216,7 +217,7 @@ namespace MQTTnet.Client if (IsConnected) throw new MqttProtocolViolationException(message); } - private async Task DisconnectInternalAsync() + private async Task DisconnectInternalAsync(Exception exception) { var clientWasConnected = IsConnected; IsConnected = false; @@ -236,14 +237,14 @@ namespace MQTTnet.Client await _adapter.DisconnectAsync(_options.CommunicationTimeout).ConfigureAwait(false); _logger.Info("Disconnected from adapter."); } - catch (Exception exception) + catch (Exception adapterException) { - _logger.Warning(exception, "Error while disconnecting from adapter."); + _logger.Warning(adapterException, "Error while disconnecting from adapter."); } finally { _logger.Info("Disconnected."); - Disconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(clientWasConnected)); + Disconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(clientWasConnected, exception)); } } @@ -363,7 +364,7 @@ namespace MQTTnet.Client return; } - await DisconnectInternalAsync().ConfigureAwait(false); + await DisconnectInternalAsync(null).ConfigureAwait(false); } catch (MqttCommunicationException exception) { @@ -373,12 +374,12 @@ namespace MQTTnet.Client } _logger.Warning(exception, "MQTT communication exception while sending/receiving keep alive packets."); - await DisconnectInternalAsync().ConfigureAwait(false); + await DisconnectInternalAsync(exception).ConfigureAwait(false); } catch (Exception exception) { _logger.Warning(exception, "Unhandled exception while sending/receiving keep alive packets."); - await DisconnectInternalAsync().ConfigureAwait(false); + await DisconnectInternalAsync(exception).ConfigureAwait(false); } finally { @@ -413,7 +414,7 @@ namespace MQTTnet.Client return; } - await DisconnectInternalAsync().ConfigureAwait(false); + await DisconnectInternalAsync(null).ConfigureAwait(false); } catch (MqttCommunicationException exception) { @@ -423,12 +424,12 @@ namespace MQTTnet.Client } _logger.Warning(exception, "MQTT communication exception while receiving packets."); - await DisconnectInternalAsync().ConfigureAwait(false); + await DisconnectInternalAsync(exception).ConfigureAwait(false); } catch (Exception exception) { _logger.Error(exception, "Unhandled exception while receiving packets."); - await DisconnectInternalAsync().ConfigureAwait(false); + await DisconnectInternalAsync(exception).ConfigureAwait(false); } finally { diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClientDisconnectedEventArgs.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientDisconnectedEventArgs.cs index 26125b9f..2161cc26 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClientDisconnectedEventArgs.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientDisconnectedEventArgs.cs @@ -4,11 +4,14 @@ namespace MQTTnet.Client { public class MqttClientDisconnectedEventArgs : EventArgs { - public MqttClientDisconnectedEventArgs(bool clientWasConnected) + public MqttClientDisconnectedEventArgs(bool clientWasConnected, Exception exception) { ClientWasConnected = clientWasConnected; + Exception = exception; } public bool ClientWasConnected { get; } + + public Exception Exception { get; } } } From 002e4b8d697095d2c3fcf1a6e2c8295107cb7505 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 22 Jan 2018 20:55:50 +0100 Subject: [PATCH 098/149] Fix broken unit tests --- .../Serializer/MqttPacketReader.cs | 16 ++++---- .../Server/MqttClientPendingMessagesQueue.cs | 5 ++- Tests/MQTTnet.Core.Tests/MqttClientTests.cs | 37 +++++++++++++++++++ .../MqttPacketReaderTests.cs | 2 +- .../MqttPacketSerializerTests.cs | 2 +- 5 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 Tests/MQTTnet.Core.Tests/MqttClientTests.cs diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs index ef078481..5359d99f 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs @@ -24,14 +24,17 @@ namespace MQTTnet.Serializer public static async Task ReadHeaderFromSourceAsync(Stream stream, CancellationToken cancellationToken) { - byte[] singleByteBuf = new byte[1]; - var readCount = await stream.ReadAsync(singleByteBuf, 0, singleByteBuf.Length).ConfigureAwait(false); + // Wait for the next package which starts with the header. At this point there will probably + // some large delay and thus the thread should be put back to the pool (await). So ReadByte() + // is not an option here. + var buffer = new byte[1]; + var readCount = await stream.ReadAsync(buffer, 0, 1, cancellationToken).ConfigureAwait(false); if (readCount <= 0) { return null; } - var fixedHeader = singleByteBuf[0]; + var fixedHeader = buffer[0]; var controlPacketType = (MqttControlPacketType)(fixedHeader >> 4); var bodyLength = await ReadBodyLengthFromSourceAsync(stream, cancellationToken).ConfigureAwait(false); @@ -88,8 +91,7 @@ namespace MQTTnet.Serializer var value = 0; byte encodedByte; - byte[] singleByteBuf = new byte[1]; - + var buffer = new byte[1]; var readBytes = new List(); do { @@ -98,13 +100,13 @@ namespace MQTTnet.Serializer throw new TaskCanceledException(); } - int readCount = await stream.ReadAsync(singleByteBuf, 0, singleByteBuf.Length).ConfigureAwait(false); + var readCount = await stream.ReadAsync(buffer, 0, 1, cancellationToken).ConfigureAwait(false); if (readCount <= 0) { throw new MqttCommunicationException("Connection closed while reading remaining length data."); } - encodedByte = singleByteBuf[0]; + encodedByte = buffer[0]; readBytes.Add(encodedByte); value += (byte)(encodedByte & 127) * multiplier; diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs index e092d3b1..62a4d78e 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs @@ -43,6 +43,7 @@ namespace MQTTnet.Server _queue.Enqueue(packet); _queueWaitSemaphore.Release(); + _logger.Trace("Enqueued packet (ClientId: {0}).", _session.ClientId); } @@ -70,9 +71,11 @@ namespace MQTTnet.Server try { await _queueWaitSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - if (!_queue.TryDequeue(out packet)) { + if (!_queue.TryDequeue(out packet)) + { throw new InvalidOperationException(); // should not happen } + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, packet).ConfigureAwait(false); _logger.Trace("Enqueued packet sent (ClientId: {0}).", _session.ClientId); diff --git a/Tests/MQTTnet.Core.Tests/MqttClientTests.cs b/Tests/MQTTnet.Core.Tests/MqttClientTests.cs new file mode 100644 index 00000000..d4343259 --- /dev/null +++ b/Tests/MQTTnet.Core.Tests/MqttClientTests.cs @@ -0,0 +1,37 @@ +using System; +using System.Net.Sockets; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MQTTnet.Client; +using MQTTnet.Exceptions; + +namespace MQTTnet.Core.Tests +{ + [TestClass] + public class MqttClientTests + { + + [TestMethod] + public async Task ClientDisconnectException() + { + var factory = new MqttFactory(); + var client = factory.CreateMqttClient(); + + var exceptionIsCorrect = false; + client.Disconnected += (s, e) => + { + exceptionIsCorrect = e.Exception is MqttCommunicationException c && c.InnerException is SocketException; + }; + + try + { + await client.ConnectAsync(new MqttClientOptionsBuilder().WithTcpServer("wrong-server").Build()); + } + catch + { + } + + Assert.IsTrue(exceptionIsCorrect); + } + } +} diff --git a/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs b/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs index 606d1daf..4d0e9b00 100644 --- a/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs @@ -12,7 +12,7 @@ namespace MQTTnet.Core.Tests public void MqttPacketReader_EmptyStream() { var memStream = new MemoryStream(); - var header = MqttPacketReader.ReadHeaderFromSource(memStream, CancellationToken.None); + var header = MqttPacketReader.ReadHeaderFromSourceAsync(memStream, CancellationToken.None).GetAwaiter().GetResult(); Assert.IsNull(header); } diff --git a/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs b/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs index 9f51b86f..5a754908 100644 --- a/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs @@ -405,7 +405,7 @@ namespace MQTTnet.Core.Tests using (var headerStream = new MemoryStream(Join(buffer1))) { - var header = MqttPacketReader.ReadHeaderFromSource(headerStream, CancellationToken.None); + var header = MqttPacketReader.ReadHeaderFromSourceAsync(headerStream, CancellationToken.None).GetAwaiter().GetResult(); using (var bodyStream = new MemoryStream(Join(buffer1), (int)headerStream.Position, header.BodyLength)) { From 40c33ac6399d6cbf0713e19404d9df5f3d1664ad Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 22 Jan 2018 21:11:35 +0100 Subject: [PATCH 099/149] Refactoring --- Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs | 2 +- Frameworks/MQTTnet.NetStandard/Internal/TaskExtensions.cs | 2 +- Frameworks/MQTTnet.NetStandard/Server/IMqttServerOptions.cs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs index 48755898..2404bb6f 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs @@ -83,7 +83,7 @@ namespace MQTTnet.Client { _packetByResponseType[responseType] = tcs; } - + return tcs; } diff --git a/Frameworks/MQTTnet.NetStandard/Internal/TaskExtensions.cs b/Frameworks/MQTTnet.NetStandard/Internal/TaskExtensions.cs index bfa01bdb..876c5495 100644 --- a/Frameworks/MQTTnet.NetStandard/Internal/TaskExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/Internal/TaskExtensions.cs @@ -30,7 +30,7 @@ namespace MQTTnet.Internal if (task.IsFaulted) { - throw new MqttCommunicationException(task.Exception.GetBaseException()); + throw new MqttCommunicationException(task.Exception?.GetBaseException()); } } finally diff --git a/Frameworks/MQTTnet.NetStandard/Server/IMqttServerOptions.cs b/Frameworks/MQTTnet.NetStandard/Server/IMqttServerOptions.cs index d89d9150..cc58eeb8 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/IMqttServerOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/IMqttServerOptions.cs @@ -1,5 +1,4 @@ using System; -using System.Net; namespace MQTTnet.Server { From 8b2b8d41dfb1f501764d2543768580c1a4f1ee87 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 22 Jan 2018 21:11:44 +0100 Subject: [PATCH 100/149] Update docs --- Build/MQTTnet.nuspec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index b78c722c..172d3603 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -13,7 +13,8 @@ * [Core] Fixed some still thread blocking parts in the code (thanks to @kpreisser). * [Core] Updated 3rd-Party packages. * [Client] The client interfaces are now implementing _IDisposable_. -* [Server] Fixed an issue which lets the server block 1 second after accepting a new connection. +* [Client] The disconnected event now contains the exception which was thrown and causing the disconnect. +* [Server] Fixed an issue which lets the server block 1 second after accepting a new connection (thanks to @kpreisser). Copyright Christian Kratky 2016-2018 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 d020e809a1a980ccdfddf64d6074d7d2cfd67442 Mon Sep 17 00:00:00 2001 From: kpreisser Date: Tue, 23 Jan 2018 10:45:58 +0100 Subject: [PATCH 101/149] Fix infinite loop that can occur when the client closes the connection before sending the complete packet body. --- .../MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index 57b79725..a4300ec1 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -137,6 +137,12 @@ namespace MQTTnet.Adapter do { var readBytesCount = await stream.ReadAsync(body, offset, body.Length - offset, cancellationToken).ConfigureAwait(false); + // Check if the client closed the connection before sending the full body. + if (readBytesCount == 0) + { + throw new MqttCommunicationException("Connection closed while reading remaining packet body."); + } + offset += readBytesCount; } while (offset < header.BodyLength); From 88de5047bc13f7999e76e460dc0035ac9eb53a5c Mon Sep 17 00:00:00 2001 From: kpreisser Date: Wed, 24 Jan 2018 15:32:36 +0100 Subject: [PATCH 102/149] Fix the algorithm for decoding the remaining length to allow a length greater than 2,097,151 bytes. See: https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os.html#_Toc442180732 --- Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs index 5359d99f..bcab98d7 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs @@ -86,7 +86,7 @@ namespace MQTTnet.Serializer private static async Task ReadBodyLengthFromSourceAsync(Stream stream, CancellationToken cancellationToken) { - // Alorithm taken from http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html. + // Alorithm taken from https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html. var multiplier = 1; var value = 0; byte encodedByte; @@ -110,11 +110,11 @@ namespace MQTTnet.Serializer readBytes.Add(encodedByte); value += (byte)(encodedByte & 127) * multiplier; - multiplier *= 128; if (multiplier > 128 * 128 * 128) { throw new MqttProtocolViolationException($"Remaining length is invalid (Data={string.Join(",", readBytes)})."); } + multiplier *= 128; } while ((encodedByte & 128) != 0); return value; From e56203faaccc05dc4d6f6c9986e02ccafbd7a11b Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 24 Jan 2018 20:16:47 +0100 Subject: [PATCH 103/149] Update docs --- Build/MQTTnet.nuspec | 2 ++ Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs | 1 + 2 files changed, 3 insertions(+) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 172d3603..946154ff 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -12,6 +12,8 @@ MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). * [Core] Fixed some still thread blocking parts in the code (thanks to @kpreisser). * [Core] Updated 3rd-Party packages. +* [Core] Fixed an issue when reading the body of a package from a disconnected sender (thanks to @kpreisser). +* [Core] Fixed wrong parsing of the body length (thanks to @kpreisser). * [Client] The client interfaces are now implementing _IDisposable_. * [Client] The disconnected event now contains the exception which was thrown and causing the disconnect. * [Server] Fixed an issue which lets the server block 1 second after accepting a new connection (thanks to @kpreisser). diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs index bcab98d7..b54085fb 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs @@ -114,6 +114,7 @@ namespace MQTTnet.Serializer { throw new MqttProtocolViolationException($"Remaining length is invalid (Data={string.Join(",", readBytes)})."); } + multiplier *= 128; } while ((encodedByte & 128) != 0); From 1415e4b878488a62741bb9be98e39a36365b6141 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 24 Jan 2018 20:49:47 +0100 Subject: [PATCH 104/149] Covnert the body buffer to a memory stream which will grow automatically. --- .../Adapter/MqttChannelAdapter.cs | 67 +++++++++++-------- .../Adapter/ReceivedMqttPacket.cs | 12 +++- .../Serializer/IMqttPacketSerializer.cs | 3 +- .../Serializer/MqttPacketReader.cs | 6 +- .../Serializer/MqttPacketSerializer.cs | 5 +- .../MqttPacketReaderTests.cs | 2 +- .../MqttPacketSerializerTests.cs | 4 +- 7 files changed, 57 insertions(+), 42 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index a4300ec1..76ac0505 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -17,8 +17,7 @@ namespace MQTTnet.Adapter public class MqttChannelAdapter : IMqttChannelAdapter { private const uint ErrorOperationAborted = 0x800703E3; - - private static readonly byte[] EmptyBody = new byte[0]; + private const int ReadBufferSize = 4096; // TODO: Move buffer size to config private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly IMqttNetLogger _logger; @@ -91,28 +90,35 @@ namespace MQTTnet.Adapter MqttBasePacket packet = null; await ExecuteAndWrapExceptionAsync(async () => { - ReceivedMqttPacket receivedMqttPacket; - if (timeout > TimeSpan.Zero) + ReceivedMqttPacket receivedMqttPacket = null; + try { - receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false); - } - else - { - receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).ConfigureAwait(false); - } + if (timeout > TimeSpan.Zero) + { + receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false); + } + else + { + receivedMqttPacket = await ReceiveAsync(_channel.ReceiveStream, cancellationToken).ConfigureAwait(false); + } - if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested) - { - throw new TaskCanceledException(); - } + if (receivedMqttPacket == null || cancellationToken.IsCancellationRequested) + { + throw new TaskCanceledException(); + } - packet = PacketSerializer.Deserialize(receivedMqttPacket.Header, receivedMqttPacket.Body); - if (packet == null) - { - throw new MqttProtocolViolationException("Received malformed packet."); - } + packet = PacketSerializer.Deserialize(receivedMqttPacket.Header, receivedMqttPacket.Body); + if (packet == null) + { + throw new MqttProtocolViolationException("Received malformed packet."); + } - _logger.Trace("RX <<< {0}", packet); + _logger.Trace("RX <<< {0}", packet); + } + finally + { + receivedMqttPacket?.Dispose(); + } }).ConfigureAwait(false); return packet; @@ -120,7 +126,7 @@ namespace MQTTnet.Adapter private static async Task ReceiveAsync(Stream stream, CancellationToken cancellationToken) { - var header = await MqttPacketReader.ReadHeaderFromSourceAsync(stream, cancellationToken).ConfigureAwait(false); + var header = await MqttPacketReader.ReadHeaderAsync(stream, cancellationToken).ConfigureAwait(false); if (header == null) { return null; @@ -128,23 +134,26 @@ namespace MQTTnet.Adapter if (header.BodyLength == 0) { - return new ReceivedMqttPacket(header, EmptyBody); + return new ReceivedMqttPacket(header, new MemoryStream(new byte[0], false)); } - var body = new byte[header.BodyLength]; - - var offset = 0; - do + var body = header.BodyLength <= ReadBufferSize ? new MemoryStream(new byte[header.BodyLength]) : new MemoryStream(); + + var buffer = new byte[ReadBufferSize]; + while (body.Length < header.BodyLength) { - var readBytesCount = await stream.ReadAsync(body, offset, body.Length - offset, cancellationToken).ConfigureAwait(false); + var readBytesCount = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false); + // Check if the client closed the connection before sending the full body. if (readBytesCount == 0) { throw new MqttCommunicationException("Connection closed while reading remaining packet body."); } - offset += readBytesCount; - } while (offset < header.BodyLength); + body.Write(buffer, 0, readBytesCount); + } + + body.Seek(0L, SeekOrigin.Begin); return new ReceivedMqttPacket(header, body); } diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/ReceivedMqttPacket.cs b/Frameworks/MQTTnet.NetStandard/Adapter/ReceivedMqttPacket.cs index c92f9d0d..a44fb54e 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/ReceivedMqttPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/ReceivedMqttPacket.cs @@ -1,11 +1,12 @@ using System; +using System.IO; using MQTTnet.Packets; namespace MQTTnet.Adapter { - public class ReceivedMqttPacket + public sealed class ReceivedMqttPacket : IDisposable { - public ReceivedMqttPacket(MqttPacketHeader header, byte[] body) + public ReceivedMqttPacket(MqttPacketHeader header, MemoryStream body) { Header = header ?? throw new ArgumentNullException(nameof(header)); Body = body ?? throw new ArgumentNullException(nameof(body)); @@ -13,6 +14,11 @@ namespace MQTTnet.Adapter public MqttPacketHeader Header { get; } - public byte[] Body { get; } + public MemoryStream Body { get; } + + public void Dispose() + { + Body?.Dispose(); + } } } diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs b/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs index 20686411..6577b0ad 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/IMqttPacketSerializer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using MQTTnet.Packets; namespace MQTTnet.Serializer @@ -10,6 +11,6 @@ namespace MQTTnet.Serializer ICollection> Serialize(MqttBasePacket mqttPacket); - MqttBasePacket Deserialize(MqttPacketHeader header, byte[] body); + MqttBasePacket Deserialize(MqttPacketHeader header, MemoryStream body); } } \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs index b54085fb..9b793ccf 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs @@ -22,7 +22,7 @@ namespace MQTTnet.Serializer public bool EndOfRemainingData => BaseStream.Position == _header.BodyLength; - public static async Task ReadHeaderFromSourceAsync(Stream stream, CancellationToken cancellationToken) + public static async Task ReadHeaderAsync(Stream stream, CancellationToken cancellationToken) { // Wait for the next package which starts with the header. At this point there will probably // some large delay and thus the thread should be put back to the pool (await). So ReadByte() @@ -36,7 +36,7 @@ namespace MQTTnet.Serializer var fixedHeader = buffer[0]; var controlPacketType = (MqttControlPacketType)(fixedHeader >> 4); - var bodyLength = await ReadBodyLengthFromSourceAsync(stream, cancellationToken).ConfigureAwait(false); + var bodyLength = await ReadBodyLengthAsync(stream, cancellationToken).ConfigureAwait(false); return new MqttPacketHeader { @@ -84,7 +84,7 @@ namespace MQTTnet.Serializer return ReadBytes(_header.BodyLength - (int)BaseStream.Position); } - private static async Task ReadBodyLengthFromSourceAsync(Stream stream, CancellationToken cancellationToken) + private static async Task ReadBodyLengthAsync(Stream stream, CancellationToken cancellationToken) { // Alorithm taken from https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html. var multiplier = 1; diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs index 88414d5d..6491e281 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs @@ -42,13 +42,12 @@ namespace MQTTnet.Serializer } } - public MqttBasePacket Deserialize(MqttPacketHeader header, byte[] body) + public MqttBasePacket Deserialize(MqttPacketHeader header, MemoryStream body) { if (header == null) throw new ArgumentNullException(nameof(header)); if (body == null) throw new ArgumentNullException(nameof(body)); - using (var bodyStream = new MemoryStream(body)) - using (var reader = new MqttPacketReader(header, bodyStream)) + using (var reader = new MqttPacketReader(header, body)) { return Deserialize(header, reader); } diff --git a/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs b/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs index 4d0e9b00..4d28035e 100644 --- a/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttPacketReaderTests.cs @@ -12,7 +12,7 @@ namespace MQTTnet.Core.Tests public void MqttPacketReader_EmptyStream() { var memStream = new MemoryStream(); - var header = MqttPacketReader.ReadHeaderFromSourceAsync(memStream, CancellationToken.None).GetAwaiter().GetResult(); + var header = MqttPacketReader.ReadHeaderAsync(memStream, CancellationToken.None).GetAwaiter().GetResult(); Assert.IsNull(header); } diff --git a/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs b/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs index 5a754908..072e1a93 100644 --- a/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs @@ -405,11 +405,11 @@ namespace MQTTnet.Core.Tests using (var headerStream = new MemoryStream(Join(buffer1))) { - var header = MqttPacketReader.ReadHeaderFromSourceAsync(headerStream, CancellationToken.None).GetAwaiter().GetResult(); + var header = MqttPacketReader.ReadHeaderAsync(headerStream, CancellationToken.None).GetAwaiter().GetResult(); using (var bodyStream = new MemoryStream(Join(buffer1), (int)headerStream.Position, header.BodyLength)) { - var deserializedPacket = serializer.Deserialize(header, bodyStream.ToArray()); + var deserializedPacket = serializer.Deserialize(header, bodyStream); var buffer2 = serializer.Serialize(deserializedPacket); Assert.AreEqual(expectedBase64Value, Convert.ToBase64String(Join(buffer2))); From 751ac19c4b21da8a7f11006ed00e47e4e4156783 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 26 Jan 2018 21:25:56 +0100 Subject: [PATCH 105/149] Fix reading more data than required for the body. --- .../MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index 76ac0505..4b8bafd6 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -142,7 +142,13 @@ namespace MQTTnet.Adapter var buffer = new byte[ReadBufferSize]; while (body.Length < header.BodyLength) { - var readBytesCount = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false); + var bytesLeft = header.BodyLength - (int)body.Length; + if (bytesLeft > buffer.Length) + { + bytesLeft = buffer.Length; + } + + var readBytesCount = await stream.ReadAsync(buffer, 0, bytesLeft, cancellationToken).ConfigureAwait(false); // Check if the client closed the connection before sending the full body. if (readBytesCount == 0) @@ -150,6 +156,8 @@ namespace MQTTnet.Adapter throw new MqttCommunicationException("Connection closed while reading remaining packet body."); } + // Here is no need to await because internally only an array is used and no real I/O operation is made. + // Using async here will only generate overhead. body.Write(buffer, 0, readBytesCount); } From 30754433eb1d0b8260e12ac6c869b4894af06661 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 26 Jan 2018 22:06:21 +0100 Subject: [PATCH 106/149] Add server methods for controlling the client subscriptions. --- .../MQTTnet.NetStandard/Server/IMqttServer.cs | 3 ++ .../Server/MqttClientSession.cs | 26 ++++++++++-- .../Server/MqttClientSessionsManager.cs | 42 +++++++++++++++++++ .../Server/MqttClientSubscriptionsManager.cs | 12 +++--- .../MQTTnet.NetStandard/Server/MqttServer.cs | 22 +++++++--- .../MqttSubscriptionsManagerTests.cs | 20 ++++----- 6 files changed, 101 insertions(+), 24 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs b/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs index 926ab9d1..99ad0a07 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs @@ -12,6 +12,9 @@ namespace MQTTnet.Server Task> GetConnectedClientsAsync(); + Task SubscribeAsync(string clientId, IList topicFilters); + Task UnsubscribeAsync(string clientId, IList topicFilters); + Task StartAsync(IMqttServerOptions options); Task StopAsync(); } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index 9615f86e..40986162 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -43,7 +44,7 @@ namespace MQTTnet.Server ClientId = clientId; - _subscriptionsManager = new MqttClientSubscriptionsManager(_options); + _subscriptionsManager = new MqttClientSubscriptionsManager(_options, clientId); _pendingMessagesQueue = new MqttClientPendingMessagesQueue(_options, this, _logger); } @@ -143,6 +144,24 @@ namespace MQTTnet.Server _pendingMessagesQueue.Enqueue(publishPacket); } + public Task SubscribeAsync(IList topicFilters) + { + return _subscriptionsManager.SubscribeAsync(new MqttSubscribePacket + { + TopicFilters = topicFilters + }); + } + + public Task UnsubscribeAsync(IList topicFilters) + { + if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); + + return _subscriptionsManager.UnsubscribeAsync(new MqttUnsubscribePacket + { + TopicFilters = topicFilters + }); + } + public void Dispose() { _pendingMessagesQueue?.Dispose(); @@ -231,7 +250,7 @@ namespace MQTTnet.Server private async Task HandleIncomingSubscribePacketAsync(IMqttChannelAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken) { - var subscribeResult = await _subscriptionsManager.SubscribeAsync(subscribePacket, ClientId); + var subscribeResult = await _subscriptionsManager.SubscribeAsync(subscribePacket).ConfigureAwait(false); await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, subscribeResult.ResponsePacket).ConfigureAwait(false); if (subscribeResult.CloseConnection) @@ -245,8 +264,7 @@ namespace MQTTnet.Server private async Task HandleIncomingUnsubscribePacketAsync(IMqttChannelAdapter adapter, MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken) { - var unsubscribeResult = await _subscriptionsManager.UnsubscribeAsync(unsubscribePacket); - + var unsubscribeResult = await _subscriptionsManager.UnsubscribeAsync(unsubscribePacket).ConfigureAwait(false); await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, unsubscribeResult); } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index 28dac0d7..6fc8a712 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -168,6 +168,48 @@ namespace MQTTnet.Server } } + public async Task SubscribeAsync(string clientId, IList topicFilters) + { + if (clientId == null) throw new ArgumentNullException(nameof(clientId)); + if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); + + await _semaphore.WaitAsync().ConfigureAwait(false); + try + { + if (!_sessions.TryGetValue(clientId, out var session)) + { + throw new InvalidOperationException($"Client session {clientId} is unknown."); + } + + await session.SubscribeAsync(topicFilters); + } + finally + { + _semaphore.Release(); + } + } + + public async Task UnsubscribeAsync(string clientId, IList topicFilters) + { + if (clientId == null) throw new ArgumentNullException(nameof(clientId)); + if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); + + await _semaphore.WaitAsync().ConfigureAwait(false); + try + { + if (!_sessions.TryGetValue(clientId, out var session)) + { + throw new InvalidOperationException($"Client session {clientId} is unknown."); + } + + await session.UnsubscribeAsync(topicFilters); + } + finally + { + _semaphore.Release(); + } + } + private MqttApplicationMessage InterceptApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage) { if (_options.ApplicationMessageInterceptor == null) diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs index 2151f77b..77949d4c 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs @@ -13,13 +13,15 @@ namespace MQTTnet.Server private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly Dictionary _subscriptions = new Dictionary(); private readonly IMqttServerOptions _options; + private readonly string _clientId; - public MqttClientSubscriptionsManager(IMqttServerOptions options) + public MqttClientSubscriptionsManager(IMqttServerOptions options, string clientId) { _options = options ?? throw new ArgumentNullException(nameof(options)); + _clientId = clientId ?? throw new ArgumentNullException(nameof(clientId)); } - public async Task SubscribeAsync(MqttSubscribePacket subscribePacket, string clientId) + public async Task SubscribeAsync(MqttSubscribePacket subscribePacket) { if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket)); @@ -34,7 +36,7 @@ namespace MQTTnet.Server { foreach (var topicFilter in subscribePacket.TopicFilters) { - var interceptorContext = InterceptSubscribe(clientId, topicFilter); + var interceptorContext = InterceptSubscribe(topicFilter); if (!interceptorContext.AcceptSubscription) { result.ResponsePacket.SubscribeReturnCodes.Add(MqttSubscribeReturnCode.Failure); @@ -117,9 +119,9 @@ namespace MQTTnet.Server } } - private MqttSubscriptionInterceptorContext InterceptSubscribe(string clientId, TopicFilter topicFilter) + private MqttSubscriptionInterceptorContext InterceptSubscribe(TopicFilter topicFilter) { - var interceptorContext = new MqttSubscriptionInterceptorContext(clientId, topicFilter); + var interceptorContext = new MqttSubscriptionInterceptorContext(_clientId, topicFilter); _options.SubscriptionInterceptor?.Invoke(interceptorContext); return interceptorContext; } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs index 461842fe..ac3b6d14 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs @@ -20,13 +20,9 @@ namespace MQTTnet.Server public MqttServer(IEnumerable adapters, IMqttNetLogger logger) { + if (adapters == null) throw new ArgumentNullException(nameof(adapters)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - if (adapters == null) - { - throw new ArgumentNullException(nameof(adapters)); - } - _adapters = adapters.ToList(); } @@ -40,6 +36,22 @@ namespace MQTTnet.Server return _clientSessionsManager.GetConnectedClientsAsync(); } + public Task SubscribeAsync(string clientId, IList topicFilters) + { + if (clientId == null) throw new ArgumentNullException(nameof(clientId)); + if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); + + return _clientSessionsManager.SubscribeAsync(clientId, topicFilters); + } + + public Task UnsubscribeAsync(string clientId, IList topicFilters) + { + if (clientId == null) throw new ArgumentNullException(nameof(clientId)); + if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); + + return _clientSessionsManager.UnsubscribeAsync(clientId, topicFilters); + } + public async Task PublishAsync(IEnumerable applicationMessages) { if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages)); diff --git a/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs b/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs index 50acd617..8b2863af 100644 --- a/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttSubscriptionsManagerTests.cs @@ -11,12 +11,12 @@ namespace MQTTnet.Core.Tests [TestMethod] public void MqttSubscriptionsManager_SubscribeSingleSuccess() { - var sm = new MqttClientSubscriptionsManager(new MqttServerOptions()); + var sm = new MqttClientSubscriptionsManager(new MqttServerOptions(), ""); var sp = new MqttSubscribePacket(); sp.TopicFilters.Add(new TopicFilterBuilder().WithTopic("A/B/C").Build()); - sm.SubscribeAsync(sp, "").Wait(); + sm.SubscribeAsync(sp).Wait(); var pp = new MqttApplicationMessage { @@ -32,12 +32,12 @@ namespace MQTTnet.Core.Tests [TestMethod] public void MqttSubscriptionsManager_SubscribeDifferentQoSSuccess() { - var sm = new MqttClientSubscriptionsManager(new MqttServerOptions()); + var sm = new MqttClientSubscriptionsManager(new MqttServerOptions(), ""); var sp = new MqttSubscribePacket(); sp.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.AtMostOnce)); - sm.SubscribeAsync(sp, "").Wait(); + sm.SubscribeAsync(sp).Wait(); var pp = new MqttApplicationMessage { @@ -53,13 +53,13 @@ namespace MQTTnet.Core.Tests [TestMethod] public void MqttSubscriptionsManager_SubscribeTwoTimesSuccess() { - var sm = new MqttClientSubscriptionsManager(new MqttServerOptions()); + var sm = new MqttClientSubscriptionsManager(new MqttServerOptions(), ""); var sp = new MqttSubscribePacket(); sp.TopicFilters.Add(new TopicFilter("#", MqttQualityOfServiceLevel.AtMostOnce)); sp.TopicFilters.Add(new TopicFilter("A/B/C", MqttQualityOfServiceLevel.AtLeastOnce)); - sm.SubscribeAsync(sp, "").Wait(); + sm.SubscribeAsync(sp).Wait(); var pp = new MqttApplicationMessage { @@ -75,12 +75,12 @@ namespace MQTTnet.Core.Tests [TestMethod] public void MqttSubscriptionsManager_SubscribeSingleNoSuccess() { - var sm = new MqttClientSubscriptionsManager(new MqttServerOptions()); + var sm = new MqttClientSubscriptionsManager(new MqttServerOptions(), ""); var sp = new MqttSubscribePacket(); sp.TopicFilters.Add(new TopicFilterBuilder().WithTopic("A/B/C").Build()); - sm.SubscribeAsync(sp, "").Wait(); + sm.SubscribeAsync(sp).Wait(); var pp = new MqttApplicationMessage { @@ -94,12 +94,12 @@ namespace MQTTnet.Core.Tests [TestMethod] public void MqttSubscriptionsManager_SubscribeAndUnsubscribeSingle() { - var sm = new MqttClientSubscriptionsManager(new MqttServerOptions()); + var sm = new MqttClientSubscriptionsManager(new MqttServerOptions(), ""); var sp = new MqttSubscribePacket(); sp.TopicFilters.Add(new TopicFilterBuilder().WithTopic("A/B/C").Build()); - sm.SubscribeAsync(sp, "").Wait(); + sm.SubscribeAsync(sp).Wait(); var pp = new MqttApplicationMessage { From 8856a7aa344ddbc05e1916ee520df8a130789c95 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 26 Jan 2018 23:56:22 +0100 Subject: [PATCH 107/149] Fix broken package reader --- .../Adapter/MqttChannelAdapter.cs | 2 +- Tests/MQTTnet.Core.Tests/MqttClientTests.cs | 3 +- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 37 ++++++++++++++++++- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index 4b8bafd6..b94cf612 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -137,7 +137,7 @@ namespace MQTTnet.Adapter return new ReceivedMqttPacket(header, new MemoryStream(new byte[0], false)); } - var body = header.BodyLength <= ReadBufferSize ? new MemoryStream(new byte[header.BodyLength]) : new MemoryStream(); + var body = header.BodyLength <= ReadBufferSize ? new MemoryStream(header.BodyLength) : new MemoryStream(); var buffer = new byte[ReadBufferSize]; while (body.Length < header.BodyLength) diff --git a/Tests/MQTTnet.Core.Tests/MqttClientTests.cs b/Tests/MQTTnet.Core.Tests/MqttClientTests.cs index d4343259..1334a803 100644 --- a/Tests/MQTTnet.Core.Tests/MqttClientTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttClientTests.cs @@ -1,5 +1,4 @@ -using System; -using System.Net.Sockets; +using System.Net.Sockets; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using MQTTnet.Client; diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index 5081dfc6..26c07df5 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -299,7 +299,7 @@ namespace MQTTnet.Core.Tests var serverAdapter = new TestMqttServerAdapter(); var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); - + try { var options = new MqttServerOptions { ApplicationMessageInterceptor = Interceptor }; @@ -330,6 +330,41 @@ namespace MQTTnet.Core.Tests } } + [TestMethod] + public async Task MqttServer_Body() + { + var serverAdapter = new TestMqttServerAdapter(); + var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); + + var bodyIsMatching = false; + try + { + await s.StartAsync(new MqttServerOptions()); + + var c1 = await serverAdapter.ConnectTestClient(s, "c1"); + var c2 = await serverAdapter.ConnectTestClient(s, "c2"); + + c1.ApplicationMessageReceived += (_, e) => + { + if (Encoding.UTF8.GetString(e.ApplicationMessage.Payload) == "The body") + { + bodyIsMatching = true; + } + }; + + await c1.SubscribeAsync("A", MqttQualityOfServiceLevel.AtMostOnce); + await c2.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("A").WithPayload(Encoding.UTF8.GetBytes("The body")).Build()); + + await Task.Delay(500); + } + finally + { + await s.StopAsync(); + } + + Assert.IsTrue(bodyIsMatching); + } + private class TestStorage : IMqttServerStorage { private IList _messages = new List(); From 5f7725589378c270467f7fbf538ee761229e2b3f Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 27 Jan 2018 14:12:54 +0100 Subject: [PATCH 108/149] Update docs --- Build/MQTTnet.nuspec | 1 + 1 file changed, 1 insertion(+) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 946154ff..96034234 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -17,6 +17,7 @@ * [Client] The client interfaces are now implementing _IDisposable_. * [Client] The disconnected event now contains the exception which was thrown and causing the disconnect. * [Server] Fixed an issue which lets the server block 1 second after accepting a new connection (thanks to @kpreisser). +* [Server] The server now allows managing client subscriptions. Copyright Christian Kratky 2016-2018 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 26cd84c88c177ac685a0976377de9453a74af416 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 2 Feb 2018 00:46:47 +0100 Subject: [PATCH 109/149] Fix generation of packet identifier. --- Build/MQTTnet.nuspec | 1 + .../MQTTnet.NetStandard/Client/MqttClient.cs | 17 ++++------ .../Client/MqttPacketIdentifierProvider.cs | 32 +++++++++++++++++++ .../MqttPacketIdentifierProviderTests.cs | 32 +++++++++++++++++++ 4 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 Frameworks/MQTTnet.NetStandard/Client/MqttPacketIdentifierProvider.cs create mode 100644 Tests/MQTTnet.Core.Tests/MqttPacketIdentifierProviderTests.cs diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 96034234..9c2e0d30 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -12,6 +12,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). * [Core] Fixed some still thread blocking parts in the code (thanks to @kpreisser). * [Core] Updated 3rd-Party packages. +* [Core] Fixed wrong packet identifier calculation (thanks to @benpittoors). * [Core] Fixed an issue when reading the body of a package from a disconnected sender (thanks to @kpreisser). * [Core] Fixed wrong parsing of the body length (thanks to @kpreisser). * [Client] The client interfaces are now implementing _IDisposable_. diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs index a4ec82fa..f71ada1c 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs @@ -14,13 +14,13 @@ namespace MQTTnet.Client { public class MqttClient : IMqttClient { + private readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider(); private readonly IMqttClientAdapterFactory _adapterFactory; private readonly MqttPacketDispatcher _packetDispatcher; private readonly IMqttNetLogger _logger; private IMqttClientOptions _options; private bool _isReceivingPackets; - private int _latestPacketIdentifier; private CancellationTokenSource _cancellationTokenSource; private IMqttChannelAdapter _adapter; @@ -49,7 +49,7 @@ namespace MQTTnet.Client { _options = options; _cancellationTokenSource = new CancellationTokenSource(); - _latestPacketIdentifier = 0; + _packetIdentifierProvider.Reset(); _packetDispatcher.Reset(); _adapter = _adapterFactory.CreateClientAdapter(options.ChannelOptions, _logger); @@ -106,7 +106,7 @@ namespace MQTTnet.Client var subscribePacket = new MqttSubscribePacket { - PacketIdentifier = GetNewPacketIdentifier(), + PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier(), TopicFilters = topicFilters.ToList() }; @@ -128,7 +128,7 @@ namespace MQTTnet.Client var unsubscribePacket = new MqttUnsubscribePacket { - PacketIdentifier = GetNewPacketIdentifier(), + PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier(), TopicFilters = topicFilters.ToList() }; @@ -156,7 +156,7 @@ namespace MQTTnet.Client { foreach (var publishPacket in qosGroup) { - publishPacket.PacketIdentifier = GetNewPacketIdentifier(); + publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier(); await SendAndReceiveAsync(publishPacket).ConfigureAwait(false); } @@ -166,7 +166,7 @@ namespace MQTTnet.Client { foreach (var publishPacket in qosGroup) { - publishPacket.PacketIdentifier = GetNewPacketIdentifier(); + publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier(); var pubRecPacket = await SendAndReceiveAsync(publishPacket).ConfigureAwait(false); await SendAndReceiveAsync(pubRecPacket.CreateResponse()).ConfigureAwait(false); } @@ -340,11 +340,6 @@ namespace MQTTnet.Client return (TResponsePacket)await packetAwaiter.ConfigureAwait(false); } - private ushort GetNewPacketIdentifier() - { - return (ushort)Interlocked.Increment(ref _latestPacketIdentifier); - } - private async Task SendKeepAliveMessagesAsync(CancellationToken cancellationToken) { _logger.Info("Start sending keep alive packets."); diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttPacketIdentifierProvider.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttPacketIdentifierProvider.cs new file mode 100644 index 00000000..dc099183 --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttPacketIdentifierProvider.cs @@ -0,0 +1,32 @@ +namespace MQTTnet.Client +{ + public class MqttPacketIdentifierProvider + { + private readonly object _syncRoot = new object(); + private ushort _value; + + public void Reset() + { + lock (_syncRoot) + { + _value = 0; + } + } + + public ushort GetNewPacketIdentifier() + { + lock (_syncRoot) + { + _value++; + + if (_value == 0) + { + // As per official MQTT documentation the package identifier should never be 0. + _value = 1; + } + + return _value; + } + } + } +} diff --git a/Tests/MQTTnet.Core.Tests/MqttPacketIdentifierProviderTests.cs b/Tests/MQTTnet.Core.Tests/MqttPacketIdentifierProviderTests.cs new file mode 100644 index 00000000..ab7070ee --- /dev/null +++ b/Tests/MQTTnet.Core.Tests/MqttPacketIdentifierProviderTests.cs @@ -0,0 +1,32 @@ +using Microsoft.VisualStudio.TestTools .UnitTesting; +using MQTTnet.Client; + +namespace MQTTnet.Core.Tests +{ + [TestClass] + public class MqttPacketIdentifierProviderTests + { + [TestMethod] + public void Reset() + { + var p = new MqttPacketIdentifierProvider(); + Assert.AreEqual(1, p.GetNewPacketIdentifier()); + Assert.AreEqual(2, p.GetNewPacketIdentifier()); + p.Reset(); + Assert.AreEqual(1, p.GetNewPacketIdentifier()); + } + + [TestMethod] + public void ReachBoundaries() + { + var p = new MqttPacketIdentifierProvider(); + + for (ushort i = 0; i < ushort.MaxValue; i++) + { + Assert.AreEqual(i + 1, p.GetNewPacketIdentifier()); + } + + Assert.AreEqual(1, p.GetNewPacketIdentifier()); + } + } +} From a204d233f60c9d03e6fbdb96b027ed4a7da9b617 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 2 Feb 2018 00:47:00 +0100 Subject: [PATCH 110/149] Update configs --- Build/MQTTnet.AspNetCore.nuspec | 2 +- MQTTnet.sln.DotSettings | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index 2b099173..86c7cc06 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -16,7 +16,7 @@ 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/MQTTnet.sln.DotSettings b/MQTTnet.sln.DotSettings index ef034942..023e3d60 100644 --- a/MQTTnet.sln.DotSettings +++ b/MQTTnet.sln.DotSettings @@ -1,7 +1,13 @@  + NEVER False False False + True + True + True + True True + True True True \ No newline at end of file From 59dcbf4c0c0207688b1c78d9559b7547fbe80fe7 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 2 Feb 2018 22:44:21 +0100 Subject: [PATCH 111/149] Add server events for subscribed and unsubscribed topics. Add pending messages count for connected clients. --- Build/MQTTnet.nuspec | 1 + .../Server/ConnectedMqttClient.cs | 2 + .../MQTTnet.NetStandard/Server/IMqttServer.cs | 7 ++- .../Server/MqttClientPendingMessagesQueue.cs | 24 +++++---- .../Server/MqttClientSession.cs | 49 ++++++++++------- .../Server/MqttClientSessionsManager.cs | 54 ++++++++++++++----- .../MqttClientSubscribedTopicEventArgs.cs | 17 ++++++ .../Server/MqttClientSubscriptionsManager.cs | 36 ++++++++----- .../MqttClientUnSubscribedTopicEventArgs.cs | 17 ++++++ .../Server/MqttRetainedMessagesManager.cs | 7 ++- .../MQTTnet.NetStandard/Server/MqttServer.cs | 43 ++++++++++----- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 22 +++++++- 12 files changed, 205 insertions(+), 74 deletions(-) create mode 100644 Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscribedTopicEventArgs.cs create mode 100644 Frameworks/MQTTnet.NetStandard/Server/MqttClientUnSubscribedTopicEventArgs.cs diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 9c2e0d30..7823d38a 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -19,6 +19,7 @@ * [Client] The disconnected event now contains the exception which was thrown and causing the disconnect. * [Server] Fixed an issue which lets the server block 1 second after accepting a new connection (thanks to @kpreisser). * [Server] The server now allows managing client subscriptions. +* [Server] Added events for topic subscriptions. Copyright Christian Kratky 2016-2018 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/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs index cd941930..4fa8e4ea 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/ConnectedMqttClient.cs @@ -12,5 +12,7 @@ namespace MQTTnet.Server public TimeSpan LastPacketReceived { get; set; } public TimeSpan LastNonKeepAlivePacketReceived { get; set; } + + public int PendingApplicationMessages { get; set; } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs b/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs index 99ad0a07..956014b5 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs @@ -6,10 +6,13 @@ namespace MQTTnet.Server { public interface IMqttServer : IApplicationMessageReceiver, IApplicationMessagePublisher { - event EventHandler ClientConnected; - event EventHandler ClientDisconnected; event EventHandler Started; + event EventHandler ClientConnected; + event EventHandler ClientDisconnected; + event EventHandler ClientSubscribedTopic; + event EventHandler ClientUnsubscribedTopic; + Task> GetConnectedClientsAsync(); Task SubscribeAsync(string clientId, IList topicFilters); diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs index 62a4d78e..27dd49d9 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs @@ -15,16 +15,18 @@ namespace MQTTnet.Server private readonly ConcurrentQueue _queue = new ConcurrentQueue(); private readonly SemaphoreSlim _queueWaitSemaphore = new SemaphoreSlim(0); private readonly IMqttServerOptions _options; - private readonly MqttClientSession _session; + private readonly MqttClientSession _clientSession; private readonly IMqttNetLogger _logger; - public MqttClientPendingMessagesQueue(IMqttServerOptions options, MqttClientSession session, IMqttNetLogger logger) + public MqttClientPendingMessagesQueue(IMqttServerOptions options, MqttClientSession clientSession, IMqttNetLogger logger) { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _session = session ?? throw new ArgumentNullException(nameof(session)); _options = options ?? throw new ArgumentNullException(nameof(options)); + _clientSession = clientSession ?? throw new ArgumentNullException(nameof(clientSession)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } + public int Count => _queue.Count; + public void Start(IMqttChannelAdapter adapter, CancellationToken cancellationToken) { if (adapter == null) throw new ArgumentNullException(nameof(adapter)); @@ -44,7 +46,7 @@ namespace MQTTnet.Server _queue.Enqueue(packet); _queueWaitSemaphore.Release(); - _logger.Trace("Enqueued packet (ClientId: {0}).", _session.ClientId); + _logger.Trace("Enqueued packet (ClientId: {0}).", _clientSession.ClientId); } private async Task SendQueuedPacketsAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken) @@ -61,7 +63,7 @@ namespace MQTTnet.Server } catch (Exception exception) { - _logger.Error(exception, "Unhandled exception while sending enqueued packet (ClientId: {0}).", _session.ClientId); + _logger.Error(exception, "Unhandled exception while sending enqueued packet (ClientId: {0}).", _clientSession.ClientId); } } @@ -78,24 +80,24 @@ namespace MQTTnet.Server await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, packet).ConfigureAwait(false); - _logger.Trace("Enqueued packet sent (ClientId: {0}).", _session.ClientId); + _logger.Trace("Enqueued packet sent (ClientId: {0}).", _clientSession.ClientId); } catch (Exception exception) { if (exception is MqttCommunicationTimedOutException) { - _logger.Warning(exception, "Sending publish packet failed due to timeout (ClientId: {0}).", _session.ClientId); + _logger.Warning(exception, "Sending publish packet failed due to timeout (ClientId: {0}).", _clientSession.ClientId); } else if (exception is MqttCommunicationException) { - _logger.Warning(exception, "Sending publish packet failed due to communication exception (ClientId: {0}).", _session.ClientId); + _logger.Warning(exception, "Sending publish packet failed due to communication exception (ClientId: {0}).", _clientSession.ClientId); } else if (exception is OperationCanceledException) { } else { - _logger.Error(exception, "Sending publish packet failed (ClientId: {0}).", _session.ClientId); + _logger.Error(exception, "Sending publish packet failed (ClientId: {0}).", _clientSession.ClientId); } if (packet is MqttPublishPacket publishPacket) @@ -108,7 +110,7 @@ namespace MQTTnet.Server } } - await _session.StopAsync(); + await _clientSession.StopAsync(); } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index 40986162..c0e9e0c8 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -21,10 +21,7 @@ namespace MQTTnet.Server private readonly IMqttServerOptions _options; private readonly IMqttNetLogger _logger; - private readonly MqttClientSessionsManager _sessionsManager; private readonly MqttRetainedMessagesManager _retainedMessagesManager; - private readonly MqttClientSubscriptionsManager _subscriptionsManager; - private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue; private IMqttChannelAdapter _adapter; private CancellationTokenSource _cancellationTokenSource; @@ -34,20 +31,24 @@ namespace MQTTnet.Server string clientId, IMqttServerOptions options, MqttRetainedMessagesManager retainedMessagesManager, - MqttClientSessionsManager sessionsManager, IMqttNetLogger logger) { _options = options ?? throw new ArgumentNullException(nameof(options)); _retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager)); - _sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); ClientId = clientId; - _subscriptionsManager = new MqttClientSubscriptionsManager(_options, clientId); - _pendingMessagesQueue = new MqttClientPendingMessagesQueue(_options, this, _logger); + SubscriptionsManager = new MqttClientSubscriptionsManager(_options, clientId); + PendingMessagesQueue = new MqttClientPendingMessagesQueue(_options, this, _logger); } + public Func ApplicationMessageReceivedCallback { get; set; } + + public MqttClientSubscriptionsManager SubscriptionsManager { get; } + + public MqttClientPendingMessagesQueue PendingMessagesQueue { get; } + public string ClientId { get; } public MqttProtocolVersion? ProtocolVersion => _adapter?.PacketSerializer.ProtocolVersion; @@ -71,7 +72,7 @@ namespace MQTTnet.Server _adapter = adapter; _cancellationTokenSource = cancellationTokenSource; - _pendingMessagesQueue.Start(adapter, cancellationTokenSource.Token); + PendingMessagesQueue.Start(adapter, cancellationTokenSource.Token); _lastPacketReceivedTracker.Restart(); _lastNonKeepAlivePacketReceivedTracker.Restart(); @@ -123,7 +124,7 @@ namespace MQTTnet.Server if (willMessage != null) { _willMessage = null; //clear willmessage so it is send just once - await _sessionsManager.DispatchApplicationMessageAsync(this, willMessage).ConfigureAwait(false); + await ApplicationMessageReceivedCallback(this, willMessage).ConfigureAwait(false); } } } @@ -132,7 +133,7 @@ namespace MQTTnet.Server { if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); - var result = await _subscriptionsManager.CheckSubscriptionsAsync(applicationMessage); + var result = await SubscriptionsManager.CheckSubscriptionsAsync(applicationMessage); if (!result.IsSubscribed) { return; @@ -141,30 +142,40 @@ namespace MQTTnet.Server var publishPacket = applicationMessage.ToPublishPacket(); publishPacket.QualityOfServiceLevel = result.QualityOfServiceLevel; - _pendingMessagesQueue.Enqueue(publishPacket); + PendingMessagesQueue.Enqueue(publishPacket); } public Task SubscribeAsync(IList topicFilters) { - return _subscriptionsManager.SubscribeAsync(new MqttSubscribePacket + if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); + + var response = SubscriptionsManager.SubscribeAsync(new MqttSubscribePacket { TopicFilters = topicFilters }); + + return response; } public Task UnsubscribeAsync(IList topicFilters) { if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); - return _subscriptionsManager.UnsubscribeAsync(new MqttUnsubscribePacket + var response = SubscriptionsManager.UnsubscribeAsync(new MqttUnsubscribePacket { TopicFilters = topicFilters }); + + return response; } public void Dispose() { - _pendingMessagesQueue?.Dispose(); + ApplicationMessageReceivedCallback = null; + + SubscriptionsManager?.Dispose(); + PendingMessagesQueue?.Dispose(); + _cancellationTokenSource?.Dispose(); } @@ -250,7 +261,7 @@ namespace MQTTnet.Server private async Task HandleIncomingSubscribePacketAsync(IMqttChannelAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken) { - var subscribeResult = await _subscriptionsManager.SubscribeAsync(subscribePacket).ConfigureAwait(false); + var subscribeResult = await SubscriptionsManager.SubscribeAsync(subscribePacket).ConfigureAwait(false); await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, subscribeResult.ResponsePacket).ConfigureAwait(false); if (subscribeResult.CloseConnection) @@ -264,7 +275,7 @@ namespace MQTTnet.Server private async Task HandleIncomingUnsubscribePacketAsync(IMqttChannelAdapter adapter, MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken) { - var unsubscribeResult = await _subscriptionsManager.UnsubscribeAsync(unsubscribePacket).ConfigureAwait(false); + var unsubscribeResult = await SubscriptionsManager.UnsubscribeAsync(unsubscribePacket).ConfigureAwait(false); await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, unsubscribeResult); } @@ -285,7 +296,7 @@ namespace MQTTnet.Server { case MqttQualityOfServiceLevel.AtMostOnce: { - return _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage); + return ApplicationMessageReceivedCallback?.Invoke(this, applicationMessage); } case MqttQualityOfServiceLevel.AtLeastOnce: { @@ -304,7 +315,7 @@ namespace MQTTnet.Server private async Task HandleIncomingPublishPacketWithQoS1(IMqttChannelAdapter adapter, MqttApplicationMessage applicationMessage, MqttPublishPacket publishPacket, CancellationToken cancellationToken) { - await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false); + await ApplicationMessageReceivedCallback(this, applicationMessage).ConfigureAwait(false); var response = new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }; await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response).ConfigureAwait(false); @@ -313,7 +324,7 @@ namespace MQTTnet.Server private async Task HandleIncomingPublishPacketWithQoS2(IMqttChannelAdapter adapter, MqttApplicationMessage applicationMessage, MqttPublishPacket publishPacket, CancellationToken cancellationToken) { // QoS 2 is implement as method "B" [4.3.3 QoS 2: Exactly once delivery] - await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false); + await ApplicationMessageReceivedCallback(this, applicationMessage).ConfigureAwait(false); var response = new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }; await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response).ConfigureAwait(false); diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index 6fc8a712..d580dd23 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -12,27 +12,32 @@ using MQTTnet.Serializer; namespace MQTTnet.Server { - public sealed class MqttClientSessionsManager + public sealed class MqttClientSessionsManager : IDisposable { private readonly Dictionary _sessions = new Dictionary(); private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly IMqttServerOptions _options; - private readonly MqttServer _server; private readonly MqttRetainedMessagesManager _retainedMessagesManager; private readonly IMqttNetLogger _logger; - public MqttClientSessionsManager(IMqttServerOptions options, MqttRetainedMessagesManager retainedMessagesManager, MqttServer server, IMqttNetLogger logger) + public MqttClientSessionsManager(IMqttServerOptions options, MqttRetainedMessagesManager retainedMessagesManager, IMqttNetLogger logger) { - _server = server ?? throw new ArgumentNullException(nameof(server)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _options = options ?? throw new ArgumentNullException(nameof(options)); _retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager)); } - public async Task RunClientSessionAsync(IMqttChannelAdapter clientAdapter, CancellationToken cancellationToken) + public Action ClientConnectedCallback { get; set; } + public Action ClientDisconnectedCallback { get; set; } + public Action ClientSubscribedTopicCallback { get; set; } + public Action ClientUnsubscribedTopicCallback { get; set; } + public Action ApplicationMessageReceivedCallback { get; set; } + + public async Task RunSessionAsync(IMqttChannelAdapter clientAdapter, CancellationToken cancellationToken) { var clientId = string.Empty; + MqttClientSession clientSession = null; try { if (!(await clientAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout, cancellationToken).ConfigureAwait(false) is MqttConnectPacket connectPacket)) @@ -56,21 +61,22 @@ namespace MQTTnet.Server return; } - var clientSession = await GetOrCreateClientSessionAsync(connectPacket).ConfigureAwait(false); + var result = await GetOrCreateClientSessionAsync(connectPacket).ConfigureAwait(false); + clientSession = result.Session; await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttConnAckPacket { ConnectReturnCode = connectReturnCode, - IsSessionPresent = clientSession.IsExistingSession + IsSessionPresent = result.IsExistingSession }).ConfigureAwait(false); - _server.OnClientConnected(new ConnectedMqttClient + ClientConnectedCallback?.Invoke(new ConnectedMqttClient { ClientId = clientId, ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion }); - await clientSession.Session.RunAsync(connectPacket, clientAdapter).ConfigureAwait(false); + await clientSession.RunAsync(connectPacket, clientAdapter).ConfigureAwait(false); } catch (Exception exception) { @@ -87,10 +93,11 @@ namespace MQTTnet.Server // ignored } - _server.OnClientDisconnected(new ConnectedMqttClient + ClientDisconnectedCallback?.Invoke(new ConnectedMqttClient { ClientId = clientId, - ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion + ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion, + PendingApplicationMessages = clientSession?.PendingMessagesQueue.Count ?? 0 }); } } @@ -123,7 +130,8 @@ namespace MQTTnet.Server ClientId = s.Value.ClientId, ProtocolVersion = s.Value.ProtocolVersion ?? MqttProtocolVersion.V311, LastPacketReceived = s.Value.LastPacketReceived, - LastNonKeepAlivePacketReceived = s.Value.LastNonKeepAlivePacketReceived + LastNonKeepAlivePacketReceived = s.Value.LastNonKeepAlivePacketReceived, + PendingApplicationMessages = s.Value.PendingMessagesQueue.Count }).ToList(); } finally @@ -147,7 +155,7 @@ namespace MQTTnet.Server await _retainedMessagesManager.HandleMessageAsync(senderClientSession?.ClientId, applicationMessage).ConfigureAwait(false); } - _server.OnApplicationMessageReceived(senderClientSession?.ClientId, applicationMessage); + ApplicationMessageReceivedCallback?.Invoke(senderClientSession?.ClientId, applicationMessage); } catch (Exception exception) { @@ -271,7 +279,14 @@ namespace MQTTnet.Server { isExistingSession = false; - clientSession = new MqttClientSession(connectPacket.ClientId, _options, _retainedMessagesManager, this, _logger); + clientSession = new MqttClientSession(connectPacket.ClientId, _options, _retainedMessagesManager, _logger) + { + ApplicationMessageReceivedCallback = DispatchApplicationMessageAsync + }; + + clientSession.SubscriptionsManager.TopicSubscribedCallback = ClientSubscribedTopicCallback; + clientSession.SubscriptionsManager.TopicUnsubscribedCallback = ClientUnsubscribedTopicCallback; + _sessions[connectPacket.ClientId] = clientSession; _logger.Trace("Created a new session for client '{0}'.", connectPacket.ClientId); @@ -284,5 +299,16 @@ namespace MQTTnet.Server _semaphore.Release(); } } + + public void Dispose() + { + ClientConnectedCallback = null; + ClientDisconnectedCallback = null; + ClientSubscribedTopicCallback = null; + ClientUnsubscribedTopicCallback = null; + ApplicationMessageReceivedCallback = null; + + _semaphore?.Dispose(); + } } } \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscribedTopicEventArgs.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscribedTopicEventArgs.cs new file mode 100644 index 00000000..11f5c063 --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscribedTopicEventArgs.cs @@ -0,0 +1,17 @@ +using System; + +namespace MQTTnet.Server +{ + public class MqttClientSubscribedTopicEventArgs : EventArgs + { + public MqttClientSubscribedTopicEventArgs(string clientId, TopicFilter topicFilter) + { + ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId)); + TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter)); + } + + public string ClientId { get; } + + public TopicFilter TopicFilter { get; } + } +} diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs index 77949d4c..97b9f047 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs @@ -8,19 +8,22 @@ using MQTTnet.Protocol; namespace MQTTnet.Server { - public sealed class MqttClientSubscriptionsManager + public sealed class MqttClientSubscriptionsManager : IDisposable { private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly Dictionary _subscriptions = new Dictionary(); private readonly IMqttServerOptions _options; private readonly string _clientId; - + public MqttClientSubscriptionsManager(IMqttServerOptions options, string clientId) { _options = options ?? throw new ArgumentNullException(nameof(options)); _clientId = clientId ?? throw new ArgumentNullException(nameof(clientId)); } + public Action TopicSubscribedCallback { get; set; } + public Action TopicUnsubscribedCallback { get; set; } + public async Task SubscribeAsync(MqttSubscribePacket subscribePacket) { if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket)); @@ -54,6 +57,7 @@ namespace MQTTnet.Server if (interceptorContext.AcceptSubscription) { _subscriptions[topicFilter.Topic] = topicFilter.QualityOfServiceLevel; + TopicSubscribedCallback?.Invoke(_clientId, topicFilter); } } } @@ -75,6 +79,7 @@ namespace MQTTnet.Server foreach (var topicFilter in unsubscribePacket.TopicFilters) { _subscriptions.Remove(topicFilter); + TopicUnsubscribedCallback?.Invoke(_clientId, topicFilter); } } finally @@ -119,6 +124,22 @@ namespace MQTTnet.Server } } + public void Dispose() + { + _semaphore?.Dispose(); + } + + private static MqttSubscribeReturnCode ConvertToMaximumQoS(MqttQualityOfServiceLevel qualityOfServiceLevel) + { + switch (qualityOfServiceLevel) + { + case MqttQualityOfServiceLevel.AtMostOnce: return MqttSubscribeReturnCode.SuccessMaximumQoS0; + case MqttQualityOfServiceLevel.AtLeastOnce: return MqttSubscribeReturnCode.SuccessMaximumQoS1; + case MqttQualityOfServiceLevel.ExactlyOnce: return MqttSubscribeReturnCode.SuccessMaximumQoS2; + default: return MqttSubscribeReturnCode.Failure; + } + } + private MqttSubscriptionInterceptorContext InterceptSubscribe(TopicFilter topicFilter) { var interceptorContext = new MqttSubscriptionInterceptorContext(_clientId, topicFilter); @@ -148,16 +169,5 @@ namespace MQTTnet.Server QualityOfServiceLevel = effectiveQoS }; } - - private static MqttSubscribeReturnCode ConvertToMaximumQoS(MqttQualityOfServiceLevel qualityOfServiceLevel) - { - switch (qualityOfServiceLevel) - { - case MqttQualityOfServiceLevel.AtMostOnce: return MqttSubscribeReturnCode.SuccessMaximumQoS0; - case MqttQualityOfServiceLevel.AtLeastOnce: return MqttSubscribeReturnCode.SuccessMaximumQoS1; - case MqttQualityOfServiceLevel.ExactlyOnce: return MqttSubscribeReturnCode.SuccessMaximumQoS2; - default: return MqttSubscribeReturnCode.Failure; - } - } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientUnSubscribedTopicEventArgs.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientUnSubscribedTopicEventArgs.cs new file mode 100644 index 00000000..d76347e0 --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientUnSubscribedTopicEventArgs.cs @@ -0,0 +1,17 @@ +using System; + +namespace MQTTnet.Server +{ + public class MqttClientUnsubscribedTopicEventArgs : EventArgs + { + public MqttClientUnsubscribedTopicEventArgs(string clientId, string topicFilter) + { + ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId)); + TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter)); + } + + public string ClientId { get; } + + public string TopicFilter { get; } + } +} diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs index 2c0b2602..7b90209c 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs @@ -8,7 +8,7 @@ using MQTTnet.Packets; namespace MQTTnet.Server { - public sealed class MqttRetainedMessagesManager + public sealed class MqttRetainedMessagesManager : IDisposable { private readonly Dictionary _retainedMessages = new Dictionary(); private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); @@ -102,6 +102,11 @@ namespace MQTTnet.Server return retainedMessages; } + public void Dispose() + { + _semaphore?.Dispose(); + } + private async Task HandleMessageInternalAsync(string clientId, MqttApplicationMessage applicationMessage) { var saveIsRequired = false; diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs index ac3b6d14..3a4a0187 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs @@ -27,8 +27,12 @@ namespace MQTTnet.Server } public event EventHandler Started; + public event EventHandler ClientConnected; public event EventHandler ClientDisconnected; + public event EventHandler ClientSubscribedTopic; + public event EventHandler ClientUnsubscribedTopic; + public event EventHandler ApplicationMessageReceived; public Task> GetConnectedClientsAsync() @@ -71,11 +75,19 @@ namespace MQTTnet.Server if (_cancellationTokenSource != null) throw new InvalidOperationException("The server is already started."); _cancellationTokenSource = new CancellationTokenSource(); - _retainedMessagesManager = new MqttRetainedMessagesManager(_options, _logger); - _clientSessionsManager = new MqttClientSessionsManager(_options, _retainedMessagesManager, this, _logger); + _retainedMessagesManager = new MqttRetainedMessagesManager(_options, _logger); await _retainedMessagesManager.LoadMessagesAsync(); + _clientSessionsManager = new MqttClientSessionsManager(_options, _retainedMessagesManager, _logger) + { + ClientConnectedCallback = OnClientConnected, + ClientDisconnectedCallback = OnClientDisconnected, + ClientSubscribedTopicCallback = OnClientSubscribedTopic, + ClientUnsubscribedTopicCallback = OnClientUnsubscribedTopic, + ApplicationMessageReceivedCallback = OnApplicationMessageReceived + }; + foreach (var adapter in _adapters) { adapter.ClientAccepted += OnClientAccepted; @@ -110,39 +122,46 @@ namespace MQTTnet.Server } finally { + _clientSessionsManager?.Dispose(); + _retainedMessagesManager?.Dispose(); + _cancellationTokenSource = null; _retainedMessagesManager = null; _clientSessionsManager = null; } } - internal void OnClientConnected(ConnectedMqttClient client) + private void OnClientConnected(ConnectedMqttClient client) { - if (client == null) throw new ArgumentNullException(nameof(client)); - _logger.Info("Client '{0}': Connected.", client.ClientId); ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(client)); } - internal void OnClientDisconnected(ConnectedMqttClient client) + private void OnClientDisconnected(ConnectedMqttClient client) { - if (client == null) throw new ArgumentNullException(nameof(client)); - _logger.Info("Client '{0}': Disconnected.", client.ClientId); ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(client)); } - - internal void OnApplicationMessageReceived(string clientId, MqttApplicationMessage applicationMessage) + + private void OnClientSubscribedTopic(string clientId, TopicFilter topicFilter) { - if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); + ClientSubscribedTopic?.Invoke(this, new MqttClientSubscribedTopicEventArgs(clientId, topicFilter)); + } + private void OnClientUnsubscribedTopic(string clientId, string topicFilter) + { + ClientUnsubscribedTopic?.Invoke(this, new MqttClientUnsubscribedTopicEventArgs(clientId, topicFilter)); + } + + private void OnApplicationMessageReceived(string clientId, MqttApplicationMessage applicationMessage) + { ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(clientId, applicationMessage)); } private void OnClientAccepted(object sender, MqttServerAdapterClientAcceptedEventArgs eventArgs) { eventArgs.SessionTask = Task.Run( - async () => await _clientSessionsManager.RunClientSessionAsync(eventArgs.Client, _cancellationTokenSource.Token).ConfigureAwait(false), + async () => await _clientSessionsManager.RunSessionAsync(eventArgs.Client, _cancellationTokenSource.Token).ConfigureAwait(false), _cancellationTokenSource.Token); } } diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index 26c07df5..7cf8bf32 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -79,7 +79,7 @@ namespace MQTTnet.Core.Tests } [TestMethod] - public async Task MqttServer_Unsubscribe() + public async Task MqttServer_SubscribeUnsubscribe() { var serverAdapter = new TestMqttServerAdapter(); var s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); @@ -99,13 +99,31 @@ namespace MQTTnet.Core.Tests await c2.PublishAsync(message); Assert.AreEqual(0, receivedMessagesCount); + var subscribeEventCalled = false; + s.ClientSubscribedTopic += (_, e) => + { + subscribeEventCalled = e.TopicFilter.Topic == "a" && e.ClientId == "c1"; + }; + await c1.SubscribeAsync(new TopicFilter("a", MqttQualityOfServiceLevel.AtLeastOnce)); + await Task.Delay(100); + Assert.IsTrue(subscribeEventCalled, "Subscribe event not called."); + await c2.PublishAsync(message); await Task.Delay(500); Assert.AreEqual(1, receivedMessagesCount); + var unsubscribeEventCalled = false; + s.ClientUnsubscribedTopic += (_, e) => + { + unsubscribeEventCalled = e.TopicFilter == "a" && e.ClientId == "c1"; + }; + await c1.UnsubscribeAsync("a"); + await Task.Delay(100); + Assert.IsTrue(unsubscribeEventCalled, "Unsubscribe event not called."); + await c2.PublishAsync(message); await Task.Delay(500); @@ -343,7 +361,7 @@ namespace MQTTnet.Core.Tests var c1 = await serverAdapter.ConnectTestClient(s, "c1"); var c2 = await serverAdapter.ConnectTestClient(s, "c2"); - + c1.ApplicationMessageReceived += (_, e) => { if (Encoding.UTF8.GetString(e.ApplicationMessage.Payload) == "The body") From e9db9d65acc4e3e7ddb1599458d4a403335ce7fe Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 4 Feb 2018 20:05:34 +0100 Subject: [PATCH 112/149] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b0858369..931f95ac 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,12 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov * TLS 1.2 support for client and server (but not UWP servers) * Extensible communication channels (i.e. In-Memory, TCP, TCP+TLS, WS) * Lightweight (only the low level implementation of MQTT, no overhead) -* Performance optimized (processing ~30.000 messages / second)* +* Performance optimized (processing ~40.000 messages / second)* * Interfaces included for mocking and testing * Access to internal trace messages * Unit tested (70+ tests) -\* Tested on local machine with MQTTnet client and server running in the same process using the TCP channel. The app for verification is part of this repository and stored in _/Tests/MQTTnet.TestApp.NetCore_. +\* Tested on local machine (Intel i7 8700K) with MQTTnet client and server running in the same process using the TCP channel. The app for verification is part of this repository and stored in _/Tests/MQTTnet.TestApp.NetCore_. ### Client From b426ae1198cecca192ff853a5d97948ca1836382 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 4 Feb 2018 20:06:01 +0100 Subject: [PATCH 113/149] Update docs --- Build/MQTTnet.AspNetCore.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index 86c7cc06..2b099173 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -16,7 +16,7 @@ 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 2341d66192ecf312c64ee8fec322cfc7a8c82704 Mon Sep 17 00:00:00 2001 From: Lassi Laati Date: Tue, 20 Feb 2018 09:23:47 +0200 Subject: [PATCH 114/149] Fix ManagedMqttClient missing call to unsubscribe topics --- .../ManagedClient/ManagedMqttClient.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs index a7f5a1cf..98c99841 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs @@ -16,6 +16,7 @@ namespace MQTTnet.ManagedClient private readonly BlockingCollection _messageQueue = new BlockingCollection(); private readonly Dictionary _subscriptions = new Dictionary(); private readonly SemaphoreSlim _subscriptionsSemaphore = new SemaphoreSlim(1, 1); + private readonly List _unsubscriptions = new List(); private readonly IMqttClient _mqttClient; private readonly IMqttNetLogger _logger; @@ -129,6 +130,7 @@ namespace MQTTnet.ManagedClient { if (_subscriptions.Remove(topic)) { + _unsubscriptions.Add(topic); _subscriptionsNotPushed = true; } } @@ -274,16 +276,26 @@ namespace MQTTnet.ManagedClient _logger.Info(nameof(ManagedMqttClient), "Synchronizing subscriptions"); List subscriptions; + List unsubscriptions; + await _subscriptionsSemaphore.WaitAsync().ConfigureAwait(false); try { subscriptions = _subscriptions.Select(i => new TopicFilter(i.Key, i.Value)).ToList(); + + unsubscriptions = new List(_unsubscriptions); + _unsubscriptions.Clear(); + _subscriptionsNotPushed = false; } finally { _subscriptionsSemaphore.Release(); } + if (unsubscriptions.Any()) + { + await _mqttClient.UnsubscribeAsync(unsubscriptions); + } if (!subscriptions.Any()) { From 76c7b319b8d474c37f3e88c6e0fab744c59ab628 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 21 Feb 2018 20:42:05 +0100 Subject: [PATCH 115/149] Fix build errors --- Build/MQTTnet.nuspec | 16 +++++----------- Build/build.ps1 | 18 ++++++++++-------- Build/codeSigningKey.pfx | Bin 0 -> 1764 bytes Documents/Import_CodeSigningKey.md | 5 ++++- .../MQTTnet.Extensions.Rpc.csproj | 1 + .../MQTTnet.Netstandard.csproj | 4 ++-- 6 files changed, 22 insertions(+), 22 deletions(-) create mode 100644 Build/codeSigningKey.pfx diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 7823d38a..fe60e586 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -2,7 +2,7 @@ MQTTnet - 2.7.0 + 2.7.1 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,16 +10,10 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * [Core] Fixed some still thread blocking parts in the code (thanks to @kpreisser). -* [Core] Updated 3rd-Party packages. -* [Core] Fixed wrong packet identifier calculation (thanks to @benpittoors). -* [Core] Fixed an issue when reading the body of a package from a disconnected sender (thanks to @kpreisser). -* [Core] Fixed wrong parsing of the body length (thanks to @kpreisser). -* [Client] The client interfaces are now implementing _IDisposable_. -* [Client] The disconnected event now contains the exception which was thrown and causing the disconnect. -* [Server] Fixed an issue which lets the server block 1 second after accepting a new connection (thanks to @kpreisser). -* [Server] The server now allows managing client subscriptions. -* [Server] Added events for topic subscriptions. + * [Client] The _ManagedClient_ now has an event which is fired after a queued application message was processed (including exception). +* [Client] The _ManagedClient_ now supports unsubscribing (thanks to @lerppana) +* [Server] Fixed some minor async issues. +* [Server] Fixed wrong comparison of the topic and QoS for retained messages. Copyright Christian Kratky 2016-2018 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/Build/build.ps1 b/Build/build.ps1 index 2b4ee5f2..021ca1d6 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -1,6 +1,7 @@ param([string]$assemblyVersion, [string]$nugetVersion) -if ([string]::IsNullOrEmpty($version)) {$version = "0.0.1"} +if ([string]::IsNullOrEmpty($assemblyVersion)) {$assemblyVersion = "0.0.1"} +if ([string]::IsNullOrEmpty($nugetVersion)) {$nugetVersion = "0.0.1"} $vswhere = ${Env:\ProgramFiles(x86)} + '\Microsoft Visual Studio\Installer\vswhere' @@ -9,14 +10,14 @@ if ($path) { $msbuild = join-path $path 'MSBuild\15.0\Bin\MSBuild.exe' # Build the core library - &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m - &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net461" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m - &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard1.3" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m - &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m - &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m + &$msbuild ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.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 ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.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 ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.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 ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.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 ..\Frameworks\MQTTnet.Netstandard\MQTTnet.Netstandard.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 ..\Frameworks\MQTTnet.AspNetCore\MQTTnet.AspNetCore.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m + &$msbuild ..\Frameworks\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 ..\Extensions\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="net452" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m @@ -25,7 +26,8 @@ if ($path) { &$msbuild ..\Extensions\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="netstandard2.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m &$msbuild ..\Extensions\MQTTnet.Extensions.Rpc\MQTTnet.Extensions.Rpc.csproj /t:Build /p:Configuration="Release" /p:TargetFramework="uap10.0" /p:FileVersion=$assemblyVersion /p:AssemblyVersion=$assemblyVersion /verbosity:m - Remove-Item .\NuGet -Force -Recurse + Remove-Item .\NuGet -Force -Recurse -ErrorAction SilentlyContinue + New-Item -ItemType Directory -Force -Path .\NuGet .\NuGet.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion .\NuGet.exe pack MQTTnet.AspNetCore.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion diff --git a/Build/codeSigningKey.pfx b/Build/codeSigningKey.pfx new file mode 100644 index 0000000000000000000000000000000000000000..9374a5dbc11acc2a3a2c507ad3281f755fcbbf45 GIT binary patch literal 1764 zcmZXTcU0477sr1Y{u02E3Rsy6RF6!P5EC4TViG6<5|(8)6bdht4Pn**2~%VhDG)+r zRiF|;Rs(232}_WnBFNAn7@#7v0YUKX&z|>fPfyQ1_qpHuxzByh^T)kd7AS(l5Lgz- z1*NnSO%pfw!BDUw7MO-)fhiD9z_Jic|0p5Kkt{?hgl|D!0LuKYYp*m6Uc`boVOj7x ztTHJ5e+)goABkoX7*ju@%aL$6Y6!`KXGW>@w~Y-`14Vm$%t|J4kDqTZ6P+L4WA}$u z7G|cVzWO=rPM5wfIP-qtyt0lB$q9RZfl;2jH`j5_?H+F9>;~s$TY3gKglNc)7o8NO ze7LbE7vwGTl9VM=d7UKxRL#pd*=>j^2Jg!@OuS4?H+PszXH25Hvpu&B?YF0YC?2ia z+c&>@k2C6vei%8?-AgF9bj+B4I@jH@=B!s{pvnx1wN+0Re(2V7_ge?B>q zdHFIZ!gba3v|lxO;k{Ktous{`Tpu|>`6?-G4*zzsWxE>Vm%$<#P%2#|JnccIM@Gqd zu%^q)oXAITT6lZCy11?0+W2A<2)kju-CK_iCw7+hx$(4#6%wtm4UD_1$L&-yeOC1D zmu3aaXob)(G#136n~%L@2{jtY#{_RJg60lcTq+bM*J^Wp1$|~~>_y@66^1u&x1eXS zRL|PzXw*-N3Vxa7wlGgKJJiPOnwGfS+>U|9#YTA=tch(b{C>^w`GnH-F`6bV>NAP6 z(cu++Wu*^^YW(6UY~b)Kfu>97t4@NW-IbZWvAa&ROV=VtB^)iEv1e!4sc#)eUr1Nv z5v%-6b!#dA#_&$CS7%yR^_&pYgk7;{oG&UcmcgTazem_<<^YeCsRNmfSkStrT?e zS||EX*T5ariA5od^Pu_9SyT4-4idp#zIeEDdB8tyZZL-GpsZyp{I?z5?=WEz_0kH0xwYk_S$89R1TJ>r>J#A#5eptXD0belP2bQGR8iAa&O zHyoOzGlQiC{?4rp>Up{Euzr-RTR=2uUg|4vUU{gha4rG~C3YjItMBMNlp`7{q0 zWZ5(p98}3`bh?R*UvIrI7WnzB8Ykd<@d5MU)`l~za(|88==QO@{Kfm78_oTOp>}l2 zYgtdWF#dj^N|);q&cXzZ{ktJGdv$DwlyQ=;!>1b8+Pv0%5*l!MiRnRK6;yIwM5w=E z!aGh-ZaCyO2JWn-^J7$tVwc2uk2>|M6PFrc_-77iW?)aEi&C&)Nho#UYYz4-_6QaQ z?$O?lfGZ;9Ruv;2rrE~ZwaktU*j$VFvWM4^kCgM2S4msW`lZOXqIU#UV`58>!D@UO G;6DJc77}Ox literal 0 HcmV?d00001 diff --git a/Documents/Import_CodeSigningKey.md b/Documents/Import_CodeSigningKey.md index 66eb41f0..7e966e4a 100644 --- a/Documents/Import_CodeSigningKey.md +++ b/Documents/Import_CodeSigningKey.md @@ -3,4 +3,7 @@ In order to import the key for code signing on a new developer machine use the f > sn –i codeSigningKey.pfx VS_KEY_EFCA4C5B6DFD4B4F -The container name may be different. \ No newline at end of file +The container name may be different. + +# Check if the assembly has a strong name +> sn -vf MQTTnet.dll \ No newline at end of file diff --git a/Extensions/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj b/Extensions/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj index fd16072b..3f4128e0 100644 --- a/Extensions/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj +++ b/Extensions/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj @@ -20,6 +20,7 @@ .NETCore v5.0 $(DefineConstants);WINDOWS_UWP + en $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets diff --git a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj index 70415cd9..cb154c24 100644 --- a/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj +++ b/Frameworks/MQTTnet.NetStandard/MQTTnet.Netstandard.csproj @@ -15,8 +15,7 @@ - true - codeSigningKey.pfx + false false @@ -29,6 +28,7 @@ .NETCore v5.0 $(DefineConstants);WINDOWS_UWP + en $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets From 034e7fd750d017edabef3e9463fa3d9ce98045b8 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 21 Feb 2018 20:42:39 +0100 Subject: [PATCH 116/149] Add event for processed application message (managed client only) --- .../ApplicationMessageProcessedEventArgs.cs | 19 ++++++++++++++ .../ManagedClient/IManagedMqttClient.cs | 2 ++ .../ManagedClient/ManagedMqttClient.cs | 25 +++++++++++++------ 3 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 Frameworks/MQTTnet.NetStandard/ManagedClient/ApplicationMessageProcessedEventArgs.cs diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ApplicationMessageProcessedEventArgs.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ApplicationMessageProcessedEventArgs.cs new file mode 100644 index 00000000..fa82c0a4 --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ApplicationMessageProcessedEventArgs.cs @@ -0,0 +1,19 @@ +using System; + +namespace MQTTnet.ManagedClient +{ + public class ApplicationMessageProcessedEventArgs : EventArgs + { + public ApplicationMessageProcessedEventArgs(MqttApplicationMessage applicationMessage, Exception exception) + { + ApplicationMessage = applicationMessage ?? throw new ArgumentNullException(nameof(applicationMessage)); + Exception = exception; + } + + public MqttApplicationMessage ApplicationMessage { get; } + public Exception Exception { get; } + + public bool HasFailed => Exception != null; + public bool HasSucceeded => Exception == null; + } +} diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs index 9d679086..6f435d5f 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs @@ -12,6 +12,8 @@ namespace MQTTnet.ManagedClient event EventHandler Connected; event EventHandler Disconnected; + event EventHandler ApplicationMessageProcessed; + Task StartAsync(IManagedMqttClientOptions options); Task StopAsync(); diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs index a7f5a1cf..b18d678f 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs @@ -27,7 +27,7 @@ namespace MQTTnet.ManagedClient private IManagedMqttClientOptions _options; private bool _subscriptionsNotPushed; - + public ManagedMqttClient(IMqttClient mqttClient, IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -43,6 +43,7 @@ namespace MQTTnet.ManagedClient public event EventHandler Connected; public event EventHandler Disconnected; public event EventHandler ApplicationMessageReceived; + public event EventHandler ApplicationMessageProcessed; public async Task StartAsync(IManagedMqttClientOptions options) { @@ -57,7 +58,7 @@ namespace MQTTnet.ManagedClient if (_connectionCancellationToken != null) throw new InvalidOperationException("The managed client is already started."); _options = options; - + if (_options.Storage != null) { _storageManager = new ManagedMqttClientStorageManager(_options.Storage); @@ -65,7 +66,7 @@ namespace MQTTnet.ManagedClient } _connectionCancellationToken = new CancellationTokenSource(); - + #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed Task.Run(async () => await MaintainConnectionAsync(_connectionCancellationToken.Token), _connectionCancellationToken.Token).ConfigureAwait(false); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed @@ -85,7 +86,7 @@ namespace MQTTnet.ManagedClient return Task.FromResult(0); } - + public async Task PublishAsync(IEnumerable applicationMessages) { if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages)); @@ -96,7 +97,7 @@ namespace MQTTnet.ManagedClient { await _storageManager.AddAsync(applicationMessage).ConfigureAwait(false); } - + _messageQueue.Add(applicationMessage); } } @@ -188,7 +189,7 @@ namespace MQTTnet.ManagedClient StartPublishing(); - + return; } @@ -209,7 +210,7 @@ namespace MQTTnet.ManagedClient _logger.Error(exception, "Unhandled exception while maintaining connection."); } } - + private async Task PublishQueuedMessagesAsync(CancellationToken cancellationToken) { try @@ -227,7 +228,7 @@ namespace MQTTnet.ManagedClient continue; } - await TryPublishQueuedMessageAsync(message).ConfigureAwait(false); + await TryPublishQueuedMessageAsync(message).ConfigureAwait(false); } } catch (OperationCanceledException) @@ -245,6 +246,7 @@ namespace MQTTnet.ManagedClient private async Task TryPublishQueuedMessageAsync(MqttApplicationMessage message) { + Exception transmitException = null; try { await _mqttClient.PublishAsync(message).ConfigureAwait(false); @@ -256,6 +258,8 @@ namespace MQTTnet.ManagedClient } catch (MqttCommunicationException exception) { + transmitException = exception; + _logger.Warning(exception, "Publishing application message failed."); if (message.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) @@ -265,8 +269,13 @@ namespace MQTTnet.ManagedClient } catch (Exception exception) { + transmitException = exception; _logger.Error(exception, "Unhandled exception while publishing queued application message."); } + finally + { + ApplicationMessageProcessed?.Invoke(this, new ApplicationMessageProcessedEventArgs(message, transmitException)); + } } private async Task PushSubscriptionsAsync() From 1760dc7d353e28cbc14ce81f44682b9902e499a3 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 21 Feb 2018 20:43:09 +0100 Subject: [PATCH 117/149] Fix async issues --- .../Server/MqttClientSession.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index c0e9e0c8..91e5b8b7 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -145,16 +145,16 @@ namespace MQTTnet.Server PendingMessagesQueue.Enqueue(publishPacket); } - public Task SubscribeAsync(IList topicFilters) + public async Task SubscribeAsync(IList topicFilters) { if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); - var response = SubscriptionsManager.SubscribeAsync(new MqttSubscribePacket + await SubscriptionsManager.SubscribeAsync(new MqttSubscribePacket { TopicFilters = topicFilters - }); + }).ConfigureAwait(false); - return response; + await EnqueueSubscribedRetainedMessagesAsync(topicFilters).ConfigureAwait(false); } public Task UnsubscribeAsync(IList topicFilters) @@ -270,7 +270,7 @@ namespace MQTTnet.Server await StopAsync().ConfigureAwait(false); } - await EnqueueSubscribedRetainedMessagesAsync(subscribePacket).ConfigureAwait(false); + await EnqueueSubscribedRetainedMessagesAsync(subscribePacket.TopicFilters).ConfigureAwait(false); } private async Task HandleIncomingUnsubscribePacketAsync(IMqttChannelAdapter adapter, MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken) @@ -279,12 +279,12 @@ namespace MQTTnet.Server await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, unsubscribeResult); } - private async Task EnqueueSubscribedRetainedMessagesAsync(MqttSubscribePacket subscribePacket) + private async Task EnqueueSubscribedRetainedMessagesAsync(ICollection topicFilters) { - var retainedMessages = await _retainedMessagesManager.GetSubscribedMessagesAsync(subscribePacket); - foreach (var publishPacket in retainedMessages) + var retainedMessages = await _retainedMessagesManager.GetSubscribedMessagesAsync(topicFilters); + foreach (var applicationMessage in retainedMessages) { - await EnqueueApplicationMessageAsync(publishPacket); + await EnqueueApplicationMessageAsync(applicationMessage).ConfigureAwait(false); } } From abb216c055571b0b587311742a77e80bd35f1ef4 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 21 Feb 2018 20:43:22 +0100 Subject: [PATCH 118/149] Fix retained message handling --- .../Server/MqttClientSessionsManager.cs | 5 +++-- .../Server/MqttRetainedMessagesManager.cs | 10 ++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index d580dd23..a9e68bcc 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -220,7 +220,8 @@ namespace MQTTnet.Server private MqttApplicationMessage InterceptApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage) { - if (_options.ApplicationMessageInterceptor == null) + var interceptor = _options.ApplicationMessageInterceptor; + if (interceptor == null) { return applicationMessage; } @@ -229,7 +230,7 @@ namespace MQTTnet.Server senderClientSession.ClientId, applicationMessage); - _options.ApplicationMessageInterceptor(interceptorContext); + interceptor(interceptorContext); return interceptorContext.ApplicationMessage; } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs index 7b90209c..11cac24f 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MQTTnet.Diagnostics; -using MQTTnet.Packets; namespace MQTTnet.Server { @@ -68,7 +67,7 @@ namespace MQTTnet.Server } } - public async Task> GetSubscribedMessagesAsync(MqttSubscribePacket subscribePacket) + public async Task> GetSubscribedMessagesAsync(ICollection topicFilters) { var retainedMessages = new List(); @@ -77,13 +76,8 @@ namespace MQTTnet.Server { foreach (var retainedMessage in _retainedMessages.Values) { - foreach (var topicFilter in subscribePacket.TopicFilters) + foreach (var topicFilter in topicFilters) { - if (retainedMessage.QualityOfServiceLevel < topicFilter.QualityOfServiceLevel) - { - continue; - } - if (!MqttTopicFilterComparer.IsMatch(retainedMessage.Topic, topicFilter.Topic)) { continue; From 3b34fd4750da7b3a3b37909145bff6ab31f7da42 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 21 Feb 2018 20:44:05 +0100 Subject: [PATCH 119/149] Fix build --- Frameworks/MQTTnet.Netstandard/MQTTnet.NetStandard.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Frameworks/MQTTnet.Netstandard/MQTTnet.NetStandard.csproj b/Frameworks/MQTTnet.Netstandard/MQTTnet.NetStandard.csproj index 70415cd9..cb154c24 100644 --- a/Frameworks/MQTTnet.Netstandard/MQTTnet.NetStandard.csproj +++ b/Frameworks/MQTTnet.Netstandard/MQTTnet.NetStandard.csproj @@ -15,8 +15,7 @@ - true - codeSigningKey.pfx + false false @@ -29,6 +28,7 @@ .NETCore v5.0 $(DefineConstants);WINDOWS_UWP + en $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets From c26555aca593ddf347f334c70d6269f5e3b36232 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 21 Feb 2018 21:32:21 +0100 Subject: [PATCH 120/149] Refactor ManagedClient --- .../ManagedClient/ManagedMqttClient.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs index d068aee4..5a392c30 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs @@ -69,7 +69,7 @@ namespace MQTTnet.ManagedClient _connectionCancellationToken = new CancellationTokenSource(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - Task.Run(async () => await MaintainConnectionAsync(_connectionCancellationToken.Token), _connectionCancellationToken.Token).ConfigureAwait(false); + Task.Run(async () => await MaintainConnectionAsync(_connectionCancellationToken.Token).ConfigureAwait(false), _connectionCancellationToken.Token).ConfigureAwait(false); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed _logger.Info("Started"); @@ -156,7 +156,7 @@ namespace MQTTnet.ManagedClient { while (!cancellationToken.IsCancellationRequested) { - await TryMaintainConnectionAsync(cancellationToken); + await TryMaintainConnectionAsync(cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException) @@ -187,7 +187,7 @@ namespace MQTTnet.ManagedClient if (connectionState == ReconnectionResult.Reconnected || _subscriptionsNotPushed) { - await PushSubscriptionsAsync().ConfigureAwait(false); + await SynchronizeSubscriptionsAsync().ConfigureAwait(false); StartPublishing(); @@ -280,7 +280,7 @@ namespace MQTTnet.ManagedClient } } - private async Task PushSubscriptionsAsync() + private async Task SynchronizeSubscriptionsAsync() { _logger.Info(nameof(ManagedMqttClient), "Synchronizing subscriptions"); @@ -301,12 +301,8 @@ namespace MQTTnet.ManagedClient { _subscriptionsSemaphore.Release(); } - if (unsubscriptions.Any()) - { - await _mqttClient.UnsubscribeAsync(unsubscriptions); - } - - if (!subscriptions.Any()) + + if (!subscriptions.Any() && !unsubscriptions.Any()) { return; } @@ -314,6 +310,7 @@ namespace MQTTnet.ManagedClient try { await _mqttClient.SubscribeAsync(subscriptions).ConfigureAwait(false); + await _mqttClient.UnsubscribeAsync(unsubscriptions).ConfigureAwait(false); } catch (Exception exception) { From f85ad4965b337335eff361b714aa1c772b0d5626 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 28 Feb 2018 21:43:19 +0100 Subject: [PATCH 121/149] Refactor keep alive monitoring and add unit tests. --- Build/MQTTnet.nuspec | 1 + .../MQTTnet.NetStandard/Server/IMqttServer.cs | 2 + .../Server/MqttClientKeepAliveMonitor.cs | 88 +++++++++++++++++++ .../Server/MqttClientSession.cs | 81 +++-------------- .../Server/MqttClientSessionsManager.cs | 4 +- .../MQTTnet.NetStandard/Server/MqttServer.cs | 15 ++-- README.md | 1 + .../MqttKeepAliveMonitorTests.cs | 66 ++++++++++++++ 8 files changed, 182 insertions(+), 76 deletions(-) create mode 100644 Frameworks/MQTTnet.NetStandard/Server/MqttClientKeepAliveMonitor.cs create mode 100644 Tests/MQTTnet.Core.Tests/MqttKeepAliveMonitorTests.cs diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index fe60e586..429099a3 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -14,6 +14,7 @@ * [Client] The _ManagedClient_ now supports unsubscribing (thanks to @lerppana) * [Server] Fixed some minor async issues. * [Server] Fixed wrong comparison of the topic and QoS for retained messages. +* [Server] Added a property which provides access to the used options (read only). Copyright Christian Kratky 2016-2018 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/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs b/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs index 956014b5..229e79c5 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/IMqttServer.cs @@ -13,6 +13,8 @@ namespace MQTTnet.Server event EventHandler ClientSubscribedTopic; event EventHandler ClientUnsubscribedTopic; + IMqttServerOptions Options { get; } + Task> GetConnectedClientsAsync(); Task SubscribeAsync(string clientId, IList topicFilters); diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientKeepAliveMonitor.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientKeepAliveMonitor.cs new file mode 100644 index 00000000..fb67c8d1 --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientKeepAliveMonitor.cs @@ -0,0 +1,88 @@ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using MQTTnet.Diagnostics; +using MQTTnet.Packets; + +namespace MQTTnet.Server +{ + public sealed class MqttClientKeepAliveMonitor + { + private readonly Stopwatch _lastPacketReceivedTracker = new Stopwatch(); + private readonly Stopwatch _lastNonKeepAlivePacketReceivedTracker = new Stopwatch(); + + private readonly string _clientId; + private readonly Func _timeoutCallback; + private readonly IMqttNetLogger _logger; + + public MqttClientKeepAliveMonitor(string clientId, Func timeoutCallback, IMqttNetLogger logger) + { + _clientId = clientId; + _timeoutCallback = timeoutCallback; + _logger = logger; + } + + public TimeSpan LastPacketReceived => _lastPacketReceivedTracker.Elapsed; + + public TimeSpan LastNonKeepAlivePacketReceived => _lastNonKeepAlivePacketReceivedTracker.Elapsed; + + public void Start(int keepAlivePeriod, CancellationToken cancellationToken) + { + if (keepAlivePeriod == 0) + { + return; + } + + Task.Run(async () => await RunAsync(keepAlivePeriod, cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false); + } + + private async Task RunAsync(int keepAlivePeriod, CancellationToken cancellationToken) + { + try + { + _lastPacketReceivedTracker.Restart(); + _lastNonKeepAlivePacketReceivedTracker.Restart(); + + while (!cancellationToken.IsCancellationRequested) + { + // Values described here: [MQTT-3.1.2-24]. + if (_lastPacketReceivedTracker.Elapsed.TotalSeconds > keepAlivePeriod * 1.5D) + { + _logger.Warning("Client '{0}': Did not receive any packet or keep alive signal.", _clientId); + + if (_timeoutCallback != null) + { + await _timeoutCallback().ConfigureAwait(false); + } + + return; + } + + await Task.Delay(keepAlivePeriod, cancellationToken).ConfigureAwait(false); + } + } + catch (OperationCanceledException) + { + } + catch (Exception exception) + { + _logger.Error(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", _clientId); + } + finally + { + _logger.Trace("Client {0}: Stopped checking keep alive timeout.", _clientId); + } + } + + public void PacketReceived(MqttBasePacket packet) + { + _lastPacketReceivedTracker.Restart(); + + if (!(packet is MqttPingReqPacket)) + { + _lastNonKeepAlivePacketReceivedTracker.Restart(); + } + } + } +} diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index 91e5b8b7..aee4351c 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using MQTTnet.Adapter; @@ -15,12 +14,8 @@ namespace MQTTnet.Server { public sealed class MqttClientSession : IDisposable { - private readonly Stopwatch _lastPacketReceivedTracker = Stopwatch.StartNew(); - private readonly Stopwatch _lastNonKeepAlivePacketReceivedTracker = Stopwatch.StartNew(); - private readonly IMqttServerOptions _options; private readonly IMqttNetLogger _logger; - private readonly MqttRetainedMessagesManager _retainedMessagesManager; private IMqttChannelAdapter _adapter; @@ -38,7 +33,8 @@ namespace MQTTnet.Server _logger = logger ?? throw new ArgumentNullException(nameof(logger)); ClientId = clientId; - + + KeepAliveMonitor = new MqttClientKeepAliveMonitor(clientId, StopDueToKeepAliveTimeoutAsync, _logger); SubscriptionsManager = new MqttClientSubscriptionsManager(_options, clientId); PendingMessagesQueue = new MqttClientPendingMessagesQueue(_options, this, _logger); } @@ -49,14 +45,12 @@ namespace MQTTnet.Server public MqttClientPendingMessagesQueue PendingMessagesQueue { get; } + public MqttClientKeepAliveMonitor KeepAliveMonitor { get; } + public string ClientId { get; } public MqttProtocolVersion? ProtocolVersion => _adapter?.PacketSerializer.ProtocolVersion; - public TimeSpan LastPacketReceived => _lastPacketReceivedTracker.Elapsed; - - public TimeSpan LastNonKeepAlivePacketReceived => _lastNonKeepAlivePacketReceivedTracker.Elapsed; - public bool IsConnected => _adapter != null; public async Task RunAsync(MqttConnectPacket connectPacket, IMqttChannelAdapter adapter) @@ -73,14 +67,7 @@ namespace MQTTnet.Server _cancellationTokenSource = cancellationTokenSource; PendingMessagesQueue.Start(adapter, cancellationTokenSource.Token); - - _lastPacketReceivedTracker.Restart(); - _lastNonKeepAlivePacketReceivedTracker.Restart(); - - if (connectPacket.KeepAlivePeriod > 0) - { - StartCheckingKeepAliveTimeout(TimeSpan.FromSeconds(connectPacket.KeepAlivePeriod), cancellationTokenSource.Token); - } + KeepAliveMonitor.Start(connectPacket.KeepAlivePeriod, cancellationTokenSource.Token); await ReceivePacketsAsync(adapter, cancellationTokenSource.Token).ConfigureAwait(false); } @@ -123,7 +110,7 @@ namespace MQTTnet.Server var willMessage = _willMessage; if (willMessage != null) { - _willMessage = null; //clear willmessage so it is send just once + _willMessage = null; // clear willmessage so it is send just once await ApplicationMessageReceivedCallback(this, willMessage).ConfigureAwait(false); } } @@ -161,12 +148,10 @@ namespace MQTTnet.Server { if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); - var response = SubscriptionsManager.UnsubscribeAsync(new MqttUnsubscribePacket + return SubscriptionsManager.UnsubscribeAsync(new MqttUnsubscribePacket { TopicFilters = topicFilters }); - - return response; } public void Dispose() @@ -179,6 +164,12 @@ namespace MQTTnet.Server _cancellationTokenSource?.Dispose(); } + private Task StopDueToKeepAliveTimeoutAsync() + { + _logger.Info("Client '{0}': Timeout while waiting for KeepAlive packet.", ClientId); + return StopAsync(); + } + private async Task ReceivePacketsAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken) { try @@ -186,14 +177,7 @@ namespace MQTTnet.Server while (!cancellationToken.IsCancellationRequested) { var packet = await adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(false); - - _lastPacketReceivedTracker.Restart(); - - if (!(packet is MqttPingReqPacket)) - { - _lastNonKeepAlivePacketReceivedTracker.Restart(); - } - + KeepAliveMonitor.PacketReceived(packet); await ProcessReceivedPacketAsync(adapter, packet, cancellationToken).ConfigureAwait(false); } } @@ -335,42 +319,5 @@ namespace MQTTnet.Server var response = new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier }; return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response); } - - private void StartCheckingKeepAliveTimeout(TimeSpan keepAlivePeriod, CancellationToken cancellationToken) - { - Task.Run( - async () => await CheckKeepAliveTimeoutAsync(keepAlivePeriod, cancellationToken).ConfigureAwait(false) - , cancellationToken); - } - - private async Task CheckKeepAliveTimeoutAsync(TimeSpan keepAlivePeriod, CancellationToken cancellationToken) - { - try - { - while (!cancellationToken.IsCancellationRequested) - { - // Values described here: [MQTT-3.1.2-24]. - if (_lastPacketReceivedTracker.Elapsed.TotalSeconds > keepAlivePeriod.TotalSeconds * 1.5D) - { - _logger.Warning("Client '{0}': Did not receive any packet or keep alive signal.", ClientId); - await StopAsync(); - return; - } - - await Task.Delay(keepAlivePeriod, cancellationToken); - } - } - catch (OperationCanceledException) - { - } - catch (Exception exception) - { - _logger.Error(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", ClientId); - } - finally - { - _logger.Trace("Client {0}: Stopped checking keep alive timeout.", ClientId); - } - } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index a9e68bcc..bc94e7f5 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -129,8 +129,8 @@ namespace MQTTnet.Server { ClientId = s.Value.ClientId, ProtocolVersion = s.Value.ProtocolVersion ?? MqttProtocolVersion.V311, - LastPacketReceived = s.Value.LastPacketReceived, - LastNonKeepAlivePacketReceived = s.Value.LastNonKeepAlivePacketReceived, + LastPacketReceived = s.Value.KeepAliveMonitor.LastPacketReceived, + LastNonKeepAlivePacketReceived = s.Value.KeepAliveMonitor.LastNonKeepAlivePacketReceived, PendingApplicationMessages = s.Value.PendingMessagesQueue.Count }).ToList(); } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs index 3a4a0187..de33800a 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs @@ -16,7 +16,6 @@ namespace MQTTnet.Server private MqttClientSessionsManager _clientSessionsManager; private MqttRetainedMessagesManager _retainedMessagesManager; private CancellationTokenSource _cancellationTokenSource; - private IMqttServerOptions _options; public MqttServer(IEnumerable adapters, IMqttNetLogger logger) { @@ -35,6 +34,8 @@ namespace MQTTnet.Server public event EventHandler ApplicationMessageReceived; + public IMqttServerOptions Options { get; private set; } + public Task> GetConnectedClientsAsync() { return _clientSessionsManager.GetConnectedClientsAsync(); @@ -70,16 +71,16 @@ namespace MQTTnet.Server public async Task StartAsync(IMqttServerOptions options) { - _options = options ?? throw new ArgumentNullException(nameof(options)); + Options = options ?? throw new ArgumentNullException(nameof(options)); if (_cancellationTokenSource != null) throw new InvalidOperationException("The server is already started."); _cancellationTokenSource = new CancellationTokenSource(); - _retainedMessagesManager = new MqttRetainedMessagesManager(_options, _logger); + _retainedMessagesManager = new MqttRetainedMessagesManager(Options, _logger); await _retainedMessagesManager.LoadMessagesAsync(); - _clientSessionsManager = new MqttClientSessionsManager(_options, _retainedMessagesManager, _logger) + _clientSessionsManager = new MqttClientSessionsManager(Options, _retainedMessagesManager, _logger) { ClientConnectedCallback = OnClientConnected, ClientDisconnectedCallback = OnClientDisconnected, @@ -91,7 +92,7 @@ namespace MQTTnet.Server foreach (var adapter in _adapters) { adapter.ClientAccepted += OnClientAccepted; - await adapter.StartAsync(_options); + await adapter.StartAsync(Options); } _logger.Info("Started."); @@ -142,7 +143,7 @@ namespace MQTTnet.Server _logger.Info("Client '{0}': Disconnected.", client.ClientId); ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(client)); } - + private void OnClientSubscribedTopic(string clientId, TopicFilter topicFilter) { ClientSubscribedTopic?.Invoke(this, new MqttClientSubscribedTopicEventArgs(clientId, topicFilter)); @@ -152,7 +153,7 @@ namespace MQTTnet.Server { ClientUnsubscribedTopic?.Invoke(this, new MqttClientUnsubscribedTopicEventArgs(clientId, topicFilter)); } - + private void OnApplicationMessageReceived(string clientId, MqttApplicationMessage applicationMessage) { ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(clientId, applicationMessage)); diff --git a/README.md b/README.md index 931f95ac..b2e40ed3 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov * Retained messages are supported including persisting via interface methods (own implementation required) * WebSockets supported (via ASP.NET Core 2.0, separate nuget) * A custom message interceptor can be added which allows transforming or extending every received application message +* Validate subscriptions and deny subscribing of certain topics depending on requesting clients ## Supported frameworks diff --git a/Tests/MQTTnet.Core.Tests/MqttKeepAliveMonitorTests.cs b/Tests/MQTTnet.Core.Tests/MqttKeepAliveMonitorTests.cs new file mode 100644 index 00000000..206942f4 --- /dev/null +++ b/Tests/MQTTnet.Core.Tests/MqttKeepAliveMonitorTests.cs @@ -0,0 +1,66 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MQTTnet.Diagnostics; +using MQTTnet.Packets; +using MQTTnet.Server; + +namespace MQTTnet.Core.Tests +{ + [TestClass] + public class MqttKeepAliveMonitorTests + { + [TestMethod] + public void KeepAlive_Timeout() + { + var timeoutCalledCount = 0; + + var monitor = new MqttClientKeepAliveMonitor(string.Empty, delegate + { + timeoutCalledCount++; + return Task.FromResult(0); + }, new MqttNetLogger()); + + Assert.AreEqual(0, timeoutCalledCount); + + monitor.Start(1, CancellationToken.None); + + Assert.AreEqual(0, timeoutCalledCount); + + Thread.Sleep(2000); // Internally the keep alive timeout is multiplied with 1.5 as per protocol specification. + + Assert.AreEqual(1, timeoutCalledCount); + } + + [TestMethod] + public void KeepAlive_NoTimeout() + { + var timeoutCalledCount = 0; + + var monitor = new MqttClientKeepAliveMonitor(string.Empty, delegate + { + timeoutCalledCount++; + return Task.FromResult(0); + }, new MqttNetLogger()); + + Assert.AreEqual(0, timeoutCalledCount); + + monitor.Start(1, CancellationToken.None); + + Assert.AreEqual(0, timeoutCalledCount); + + // Simulate traffic. + Thread.Sleep(1000); // Internally the keep alive timeout is multiplied with 1.5 as per protocol specification. + monitor.PacketReceived(new MqttPublishPacket()); + Thread.Sleep(1000); + monitor.PacketReceived(new MqttPublishPacket()); + Thread.Sleep(1000); + + Assert.AreEqual(0, timeoutCalledCount); + + Thread.Sleep(2000); + + Assert.AreEqual(1, timeoutCalledCount); + } + } +} From b3a25fb9e8badf9d243db4935edbd09bebf0dee9 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 5 Mar 2018 20:43:37 +0100 Subject: [PATCH 122/149] Fix subscription handling of _ManagedClient_. --- .../ManagedClient/ManagedMqttClient.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs index 5a392c30..ffb86394 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs @@ -45,6 +45,7 @@ namespace MQTTnet.ManagedClient public event EventHandler Disconnected; public event EventHandler ApplicationMessageReceived; public event EventHandler ApplicationMessageProcessed; + public event EventHandler SynchronizingSubscriptionsFailed; public async Task StartAsync(IManagedMqttClientOptions options) { @@ -309,13 +310,22 @@ namespace MQTTnet.ManagedClient try { - await _mqttClient.SubscribeAsync(subscriptions).ConfigureAwait(false); - await _mqttClient.UnsubscribeAsync(unsubscriptions).ConfigureAwait(false); + if (subscriptions.Any()) + { + await _mqttClient.SubscribeAsync(subscriptions).ConfigureAwait(false); + } + + if (unsubscriptions.Any()) + { + await _mqttClient.UnsubscribeAsync(unsubscriptions).ConfigureAwait(false); + } } catch (Exception exception) { - _logger.Warning(exception, "Synchronizing subscriptions failed"); + _logger.Warning(exception, "Synchronizing subscriptions failed."); _subscriptionsNotPushed = true; + + SynchronizingSubscriptionsFailed?.Invoke(this, EventArgs.Empty); } } From 90098c20063377c66f2a0d9f2b19351eb04dd8fe Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 13 Mar 2018 20:22:13 +0100 Subject: [PATCH 123/149] Optimize dispatcher --- .../MQTTnet.NetStandard/Client/MqttClient.cs | 8 ++- .../Client/MqttPacketDispatcher.cs | 64 +++++++------------ 2 files changed, 31 insertions(+), 41 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs index f71ada1c..ffdc7f26 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs @@ -335,7 +335,13 @@ namespace MQTTnet.Client private async Task SendAndReceiveAsync(MqttBasePacket requestPacket) where TResponsePacket : MqttBasePacket { - var packetAwaiter = _packetDispatcher.WaitForPacketAsync(requestPacket, typeof(TResponsePacket), _options.CommunicationTimeout); + ushort identifier = 0; + if (requestPacket is IMqttPacketWithIdentifier requestPacketWithIdentifier) + { + identifier = requestPacketWithIdentifier.PacketIdentifier; + } + + var packetAwaiter = _packetDispatcher.WaitForPacketAsync(typeof(TResponsePacket), identifier, _options.CommunicationTimeout); await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, requestPacket).ConfigureAwait(false); return (TResponsePacket)await packetAwaiter.ConfigureAwait(false); } diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs index 2404bb6f..ca759311 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs @@ -10,8 +10,7 @@ namespace MQTTnet.Client { public class MqttPacketDispatcher { - private readonly ConcurrentDictionary> _packetByResponseType = new ConcurrentDictionary>(); - private readonly ConcurrentDictionary>> _packetByResponseTypeAndIdentifier = new ConcurrentDictionary>>(); + private readonly ConcurrentDictionary>> _awaiters = new ConcurrentDictionary>>(); private readonly IMqttNetLogger _logger; public MqttPacketDispatcher(IMqttNetLogger logger) @@ -19,11 +18,9 @@ namespace MQTTnet.Client _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } - public async Task WaitForPacketAsync(MqttBasePacket request, Type responseType, TimeSpan timeout) + public async Task WaitForPacketAsync(Type responseType, ushort identifier, TimeSpan timeout) { - if (request == null) throw new ArgumentNullException(nameof(request)); - - var packetAwaiter = AddPacketAwaiter(request, responseType); + var packetAwaiter = AddPacketAwaiter(responseType, identifier); try { return await packetAwaiter.Task.TimeoutAfter(timeout).ConfigureAwait(false); @@ -35,7 +32,7 @@ namespace MQTTnet.Client } finally { - RemovePacketAwaiter(request, responseType); + RemovePacketAwaiter(responseType, identifier); } } @@ -44,21 +41,20 @@ namespace MQTTnet.Client if (packet == null) throw new ArgumentNullException(nameof(packet)); var type = packet.GetType(); - if (packet is IMqttPacketWithIdentifier withIdentifier) + + if (_awaiters.TryGetValue(type, out var byId)) { - if (_packetByResponseTypeAndIdentifier.TryGetValue(type, out var byid)) + ushort identifier = 0; + if (packet is IMqttPacketWithIdentifier packetWithIdentifier) { - if (byid.TryRemove(withIdentifier.PacketIdentifier, out var tcs)) - { - tcs.TrySetResult(packet); - return; - } + identifier = packetWithIdentifier.PacketIdentifier; + } + + if (byId.TryRemove(identifier, out var tcs)) + { + tcs.TrySetResult(packet); + return; } - } - else if (_packetByResponseType.TryRemove(type, out var tcs)) - { - tcs.TrySetResult(packet); - return; } throw new InvalidOperationException($"Packet of type '{type.Name}' not handled or dispatched."); @@ -66,38 +62,26 @@ namespace MQTTnet.Client public void Reset() { - _packetByResponseTypeAndIdentifier.Clear(); - _packetByResponseType.Clear(); + _awaiters.Clear(); } - private TaskCompletionSource AddPacketAwaiter(MqttBasePacket request, Type responseType) + private TaskCompletionSource AddPacketAwaiter(Type responseType, ushort identifier) { var tcs = new TaskCompletionSource(); - if (request is IMqttPacketWithIdentifier requestWithIdentifier) + var byId = _awaiters.GetOrAdd(responseType, key => new ConcurrentDictionary>()); + if (!byId.TryAdd(identifier, tcs)) { - var byId = _packetByResponseTypeAndIdentifier.GetOrAdd(responseType, key => new ConcurrentDictionary>()); - byId[requestWithIdentifier.PacketIdentifier] = tcs; + throw new InvalidOperationException($"The packet dispatcher already has an awaiter for packet of type '{responseType}' with identifier {identifier}."); } - else - { - _packetByResponseType[responseType] = tcs; - } - + return tcs; } - private void RemovePacketAwaiter(MqttBasePacket request, Type responseType) + private void RemovePacketAwaiter(Type responseType, ushort identifier) { - if (request is IMqttPacketWithIdentifier requestWithIdentifier) - { - var byId = _packetByResponseTypeAndIdentifier.GetOrAdd(responseType, key => new ConcurrentDictionary>()); - byId.TryRemove(requestWithIdentifier.PacketIdentifier, out var _); - } - else - { - _packetByResponseType.TryRemove(responseType, out var _); - } + var byId = _awaiters.GetOrAdd(responseType, key => new ConcurrentDictionary>()); + byId.TryRemove(identifier, out var _); } } } \ No newline at end of file From e1d86973312075ae3a5d79a70759908f36dfd350 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 13 Mar 2018 20:22:48 +0100 Subject: [PATCH 124/149] Fix wrong parsing and generating of MqttConnAck for version 3.1.0 --- .../Serializer/MqttPacketSerializer.cs | 35 ++++++++++++------- .../MqttPacketSerializerTests.cs | 19 +++++++--- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs index 6491e281..63a3c646 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs @@ -75,7 +75,7 @@ namespace MQTTnet.Serializer } } - private static MqttBasePacket Deserialize(MqttPacketHeader header, MqttPacketReader reader) + private MqttBasePacket Deserialize(MqttPacketHeader header, MqttPacketReader reader) { switch (header.ControlPacketType) { @@ -278,20 +278,22 @@ namespace MQTTnet.Serializer return packet; } - private static MqttBasePacket DeserializeConnAck(MqttPacketReader reader) + private MqttBasePacket DeserializeConnAck(MqttPacketReader reader) { - var variableHeader1 = reader.ReadByte(); - var variableHeader2 = reader.ReadByte(); + var packet = new MqttConnAckPacket(); - var packet = new MqttConnAckPacket + var firstByteReader = new ByteReader(reader.ReadByte()); + + if (ProtocolVersion == MqttProtocolVersion.V311) { - IsSessionPresent = new ByteReader(variableHeader1).Read(), - ConnectReturnCode = (MqttConnectReturnCode)variableHeader2 - }; + packet.IsSessionPresent = firstByteReader.Read(); + } + + packet.ConnectReturnCode = (MqttConnectReturnCode)reader.ReadByte(); return packet; } - + private static void ValidateConnectPacket(MqttConnectPacket packet) { if (packet == null) throw new ArgumentNullException(nameof(packet)); @@ -373,14 +375,21 @@ namespace MQTTnet.Serializer private byte Serialize(MqttConnAckPacket packet, MqttPacketWriter writer) { - var connectAcknowledgeFlags = new ByteWriter(); - - if (ProtocolVersion == MqttProtocolVersion.V311) + if (ProtocolVersion == MqttProtocolVersion.V310) { + writer.Write(0); + } + else if (ProtocolVersion == MqttProtocolVersion.V311) + { + var connectAcknowledgeFlags = new ByteWriter(); connectAcknowledgeFlags.Write(packet.IsSessionPresent); + writer.Write(connectAcknowledgeFlags); + } + else + { + throw new MqttProtocolViolationException("Protocol version not supported."); } - writer.Write(connectAcknowledgeFlags); writer.Write((byte)packet.ConnectReturnCode); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.ConnAck); diff --git a/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs b/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs index 072e1a93..1111d907 100644 --- a/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttPacketSerializerTests.cs @@ -119,10 +119,10 @@ namespace MQTTnet.Core.Tests { var p = new MqttConnAckPacket { - ConnectReturnCode = MqttConnectReturnCode.ConnectionAccepted + ConnectReturnCode = MqttConnectReturnCode.ConnectionRefusedNotAuthorized }; - SerializeAndCompare(p, "IAIAAA==", MqttProtocolVersion.V310); + SerializeAndCompare(p, "IAIABQ==", MqttProtocolVersion.V310); } [TestMethod] @@ -137,6 +137,17 @@ namespace MQTTnet.Core.Tests DeserializeAndCompare(p, "IAIBBQ=="); } + [TestMethod] + public void DeserializeV310_MqttConnAckPacket() + { + var p = new MqttConnAckPacket + { + ConnectReturnCode = MqttConnectReturnCode.ConnectionRefusedNotAuthorized + }; + + DeserializeAndCompare(p, "IAIABQ==", MqttProtocolVersion.V310); + } + [TestMethod] public void SerializeV311_MqttDisconnectPacket() { @@ -397,9 +408,9 @@ namespace MQTTnet.Core.Tests Assert.AreEqual(expectedBase64Value, Convert.ToBase64String(Join(chunks))); } - private static void DeserializeAndCompare(MqttBasePacket packet, string expectedBase64Value) + private static void DeserializeAndCompare(MqttBasePacket packet, string expectedBase64Value, MqttProtocolVersion protocolVersion = MqttProtocolVersion.V311) { - var serializer = new MqttPacketSerializer(); + var serializer = new MqttPacketSerializer { ProtocolVersion = protocolVersion }; var buffer1 = serializer.Serialize(packet); From 6e828d091f3ead9f9bed922873baadf2a4b03b97 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 13 Mar 2018 20:23:07 +0100 Subject: [PATCH 125/149] Override ToString() for LogMessage --- .../Diagnostics/MqttNetLogMessage.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogMessage.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogMessage.cs index d118fd09..6035a89c 100644 --- a/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogMessage.cs +++ b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogMessage.cs @@ -28,5 +28,16 @@ namespace MQTTnet.Diagnostics public string Message { get; } public Exception Exception { get; } + + public override string ToString() + { + var result = $"[{Timestamp:O}] [{LogId}] [{ThreadId}] [{Source}] [{Level}]: {Message}"; + if (Exception != null) + { + result += Environment.NewLine + Exception; + } + + return result; + } } } From 56acc82445b0d064525bfe72b2dfb69f1476bf5e Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 13 Mar 2018 20:23:22 +0100 Subject: [PATCH 126/149] Fix null ref in server when using interceptor --- .../MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index bc94e7f5..fe57552f 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -227,7 +227,7 @@ namespace MQTTnet.Server } var interceptorContext = new MqttApplicationMessageInterceptorContext( - senderClientSession.ClientId, + senderClientSession?.ClientId, applicationMessage); interceptor(interceptorContext); From e57ec11ed811776f83e7edd01bf52e9c8b32a56d Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 13 Mar 2018 20:23:31 +0100 Subject: [PATCH 127/149] Update libs --- .../MQTTnet.TestApp.UniversalWindows.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj index 2f4dd5f3..0e7656f2 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj @@ -138,10 +138,10 @@ - 5.4.1 + 6.0.8 - 2.1.1 + 2.2.0 From c5d22f4b271f5bef6a23c3215f008ed0cb86d418 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 13 Mar 2018 20:23:36 +0100 Subject: [PATCH 128/149] Update docs --- Build/MQTTnet.nuspec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 429099a3..87140eb5 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -10,11 +10,15 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * [Client] The _ManagedClient_ now has an event which is fired after a queued application message was processed (including exception). + * [Core] Fixed wrong parsing of ConnAck packet for protocol version 3.1.0. +* [Core] Log messages are now overriding ToString() and providing a ready to use text representation. +* [Client] Optimized package dispatcher and added several new exceptions. +* [Client] The _ManagedClient_ now has an event which is fired after a queued application message was processed (including exception). * [Client] The _ManagedClient_ now supports unsubscribing (thanks to @lerppana) * [Server] Fixed some minor async issues. * [Server] Fixed wrong comparison of the topic and QoS for retained messages. * [Server] Added a property which provides access to the used options (read only). +* [Server] Fixed a null ref expection when using an interceptor and publishing via the server directly. Copyright Christian Kratky 2016-2018 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 bb9d5586f0f2bf1c8aad8ffff12243b1b6d59003 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 13 Mar 2018 20:31:01 +0100 Subject: [PATCH 129/149] Update nuspec --- Build/MQTTnet.AspNetCore.nuspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index 2b099173..3f5cd0be 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -2,7 +2,7 @@ MQTTnet.AspNetCore - 2.7.0 + 2.7.1 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,13 +10,13 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false This is a support library to integrate MQTTnet into AspNetCore. - * Updated to MQTTnet 2.7.0. + * Updated to MQTTnet 2.7.1. Copyright Christian Kratky 2016-2018 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 49da66dcffe5e3421b0175f34491ae27163852bf Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 13 Mar 2018 23:28:50 +0100 Subject: [PATCH 130/149] Fix issue when disconnecting on UWP --- .../Implementations/MqttTcpChannel.Uwp.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs index fa96a8f8..c65f789f 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs @@ -69,12 +69,6 @@ namespace MQTTnet.Implementations public void Dispose() { - SendStream?.Dispose(); - SendStream = null; - - ReceiveStream?.Dispose(); - ReceiveStream = null; - _socket?.Dispose(); _socket = null; } From 45b4c058675260e12a46f332f2f16c476187d6b5 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 25 Mar 2018 14:38:16 +0200 Subject: [PATCH 131/149] Update version --- .../MQTTnet.TestApp.UniversalWindows.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj index 0e7656f2..b5d2dbd9 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MQTTnet.TestApp.UniversalWindows.csproj @@ -12,7 +12,7 @@ en-US UAP 10.0.16299.0 - 10.0.15063.0 + 10.0.16299.0 14 512 {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} From b3eaeea8a4dc83add1865e2b2b5831e32ce643c6 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 25 Mar 2018 14:38:36 +0200 Subject: [PATCH 132/149] Fix log issue in UWP test app. --- Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml | 2 +- .../MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml index dcdee000..3698613f 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml @@ -148,7 +148,7 @@ - + diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index a48b7ee5..3ed12bf4 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -42,7 +42,8 @@ namespace MQTTnet.TestApp.UniversalWindows foreach (var traceMessage in _traceMessages) { logText.AppendFormat( - "[{0:yyyy-MM-dd HH:mm:ss.fff}] [{1}] [{2}] [{3}] [{4}]{5}", traceMessage.Timestamp, + "[{0:yyyy-MM-dd HH:mm:ss.fff}] [{1}] [{2}] [{3}] [{4}]{5}", + traceMessage.Timestamp, traceMessage.Level, traceMessage.Source, traceMessage.ThreadId, @@ -197,8 +198,13 @@ namespace MQTTnet.TestApp.UniversalWindows } } - private void Clear(object sender, RoutedEventArgs e) + private void ClearLog(object sender, RoutedEventArgs e) { + while (_traceMessages.Count > 0) + { + _traceMessages.TryDequeue(out _); + } + Trace.Text = string.Empty; } From 447b2aa2c682dffe73ce8e7a4f790ad2d2b02996 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 25 Mar 2018 14:39:44 +0200 Subject: [PATCH 133/149] Add new extension methods. --- .../ApplicationMessagePublisherExtensions.cs | 31 +++++++++++++++++-- .../Client/MqttClientExtensions.cs | 8 +++++ .../ManagedMqttClientOptionsBuilder.cs | 31 +++++++++++++++++-- .../MqttApplicationMessageExtensions.cs | 25 +++++++++++++++ 4 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 Frameworks/MQTTnet.NetStandard/MqttApplicationMessageExtensions.cs diff --git a/Frameworks/MQTTnet.NetStandard/ApplicationMessagePublisherExtensions.cs b/Frameworks/MQTTnet.NetStandard/ApplicationMessagePublisherExtensions.cs index 73328de9..b1bf62f5 100644 --- a/Frameworks/MQTTnet.NetStandard/ApplicationMessagePublisherExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/ApplicationMessagePublisherExtensions.cs @@ -1,16 +1,41 @@ using System; using System.Threading.Tasks; +using MQTTnet.Protocol; namespace MQTTnet { public static class ApplicationMessagePublisherExtensions { - public static Task PublishAsync(this IApplicationMessagePublisher client, params MqttApplicationMessage[] applicationMessages) + public static Task PublishAsync(this IApplicationMessagePublisher publisher, params MqttApplicationMessage[] applicationMessages) { - if (client == null) throw new ArgumentNullException(nameof(client)); + if (publisher == null) throw new ArgumentNullException(nameof(publisher)); if (applicationMessages == null) throw new ArgumentNullException(nameof(applicationMessages)); - return client.PublishAsync(applicationMessages); + return publisher.PublishAsync(applicationMessages); + } + + public static Task PublishAsync(this IApplicationMessagePublisher publisher, string topic) + { + if (publisher == null) throw new ArgumentNullException(nameof(publisher)); + if (topic == null) throw new ArgumentNullException(nameof(topic)); + + return publisher.PublishAsync(new MqttApplicationMessageBuilder().WithTopic(topic).Build()); + } + + public static Task PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload) + { + if (publisher == null) throw new ArgumentNullException(nameof(publisher)); + if (topic == null) throw new ArgumentNullException(nameof(topic)); + + return publisher.PublishAsync(new MqttApplicationMessageBuilder().WithTopic(topic).WithPayload(payload).Build()); + } + + public static Task PublishAsync(this IApplicationMessagePublisher publisher, string topic, string payload, MqttQualityOfServiceLevel qualityOfServiceLevel) + { + if (publisher == null) throw new ArgumentNullException(nameof(publisher)); + if (topic == null) throw new ArgumentNullException(nameof(topic)); + + return publisher.PublishAsync(new MqttApplicationMessageBuilder().WithTopic(topic).WithPayload(payload).WithQualityOfServiceLevel(qualityOfServiceLevel).Build()); } } } diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClientExtensions.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientExtensions.cs index 73f4d40c..a7548dee 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClientExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientExtensions.cs @@ -24,6 +24,14 @@ namespace MQTTnet.Client return client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build()); } + public static Task> SubscribeAsync(this IMqttClient client, string topic) + { + if (client == null) throw new ArgumentNullException(nameof(client)); + if (topic == null) throw new ArgumentNullException(nameof(topic)); + + return client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).Build()); + } + public static Task UnsubscribeAsync(this IMqttClient client, params string[] topicFilters) { if (client == null) throw new ArgumentNullException(nameof(client)); diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptionsBuilder.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptionsBuilder.cs index 7c753064..38aadcfe 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptionsBuilder.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptionsBuilder.cs @@ -6,6 +6,7 @@ namespace MQTTnet.ManagedClient public class ManagedMqttClientOptionsBuilder { private readonly ManagedMqttClientOptions _options = new ManagedMqttClientOptions(); + private MqttClientOptionsBuilder _clientOptionsBuilder; public ManagedMqttClientOptionsBuilder WithAutoReconnectDelay(TimeSpan value) { @@ -21,7 +22,24 @@ namespace MQTTnet.ManagedClient public ManagedMqttClientOptionsBuilder WithClientOptions(IMqttClientOptions value) { + if (_clientOptionsBuilder != null) + { + throw new InvalidOperationException("Cannot use client options builder and client options at the same time."); + } + _options.ClientOptions = value ?? throw new ArgumentNullException(nameof(value)); + + return this; + } + + public ManagedMqttClientOptionsBuilder WithClientOptions(MqttClientOptionsBuilder builder) + { + if (_options.ClientOptions != null) + { + throw new InvalidOperationException("Cannot use client options builder and client options at the same time."); + } + + _clientOptionsBuilder = builder; return this; } @@ -29,15 +47,22 @@ namespace MQTTnet.ManagedClient { if (options == null) throw new ArgumentNullException(nameof(options)); - var builder = new MqttClientOptionsBuilder(); - options(builder); - _options.ClientOptions = builder.Build(); + if (_clientOptionsBuilder != null) + { + _clientOptionsBuilder = new MqttClientOptionsBuilder(); + } + options(_clientOptionsBuilder); return this; } public ManagedMqttClientOptions Build() { + if (_clientOptionsBuilder != null) + { + _options.ClientOptions = _clientOptionsBuilder.Build(); + } + if (_options.ClientOptions == null) { throw new InvalidOperationException("The ClientOptions cannot be null."); diff --git a/Frameworks/MQTTnet.NetStandard/MqttApplicationMessageExtensions.cs b/Frameworks/MQTTnet.NetStandard/MqttApplicationMessageExtensions.cs new file mode 100644 index 00000000..dac9998a --- /dev/null +++ b/Frameworks/MQTTnet.NetStandard/MqttApplicationMessageExtensions.cs @@ -0,0 +1,25 @@ +using System; +using System.Text; + +namespace MQTTnet +{ + public static class MqttApplicationMessageExtensions + { + public static string ConvertPayloadToString(this MqttApplicationMessage applicationMessage) + { + if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage)); + + if (applicationMessage.Payload == null) + { + return null; + } + + if (applicationMessage.Payload.Length == 0) + { + return string.Empty; + } + + return Encoding.UTF8.GetString(applicationMessage.Payload, 0, applicationMessage.Payload.Length); + } + } +} From 7a9ddfc2b5287fb840fc08dc0ccaa099c00189d3 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 25 Mar 2018 14:41:12 +0200 Subject: [PATCH 134/149] Fix packet identifier which is sent from the server. --- .../Adapter/MqttChannelAdapter.cs | 8 +-- .../Adapter/MqttChannelAdapterExtensions.cs | 17 ----- .../Packets/IMqttPacketWithIdentifier.cs | 2 +- .../Packets/MqttBasePublishPacket.cs | 2 +- .../Packets/MqttPacketExtensions.cs | 26 -------- .../Packets/MqttSubAckPacket.cs | 2 +- .../Packets/MqttSubscribePacket.cs | 2 +- .../Packets/MqttUnsubAckPacket.cs | 2 +- .../Packets/MqttUnsubscribe.cs | 2 +- .../Serializer/MqttPacketSerializer.cs | 65 ++++++++++++++++--- .../Server/MqttClientPendingMessagesQueue.cs | 2 +- .../Server/MqttClientSession.cs | 28 +++++--- .../Server/MqttClientSessionsManager.cs | 8 +-- .../Server/MqttClientSubscriptionsManager.cs | 13 +++- 14 files changed, 100 insertions(+), 79 deletions(-) delete mode 100644 Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapterExtensions.cs delete mode 100644 Frameworks/MQTTnet.NetStandard/Packets/MqttPacketExtensions.cs diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index b94cf612..0ad382a1 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -138,7 +138,7 @@ namespace MQTTnet.Adapter } var body = header.BodyLength <= ReadBufferSize ? new MemoryStream(header.BodyLength) : new MemoryStream(); - + var buffer = new byte[ReadBufferSize]; while (body.Length < header.BodyLength) { @@ -149,7 +149,7 @@ namespace MQTTnet.Adapter } var readBytesCount = await stream.ReadAsync(buffer, 0, bytesLeft, cancellationToken).ConfigureAwait(false); - + // Check if the client closed the connection before sending the full body. if (readBytesCount == 0) { @@ -162,7 +162,7 @@ namespace MQTTnet.Adapter } body.Seek(0L, SeekOrigin.Begin); - + return new ReceivedMqttPacket(header, body); } @@ -190,7 +190,7 @@ namespace MQTTnet.Adapter } catch (COMException comException) { - if ((uint) comException.HResult == ErrorOperationAborted) + if ((uint)comException.HResult == ErrorOperationAborted) { throw new OperationCanceledException(); } diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapterExtensions.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapterExtensions.cs deleted file mode 100644 index 58258ab6..00000000 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapterExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using MQTTnet.Packets; - -namespace MQTTnet.Adapter -{ - public static class MqttChannelAdapterExtensions - { - public static Task SendPacketsAsync(this IMqttChannelAdapter adapter, TimeSpan timeout, CancellationToken cancellationToken, params MqttBasePacket[] packets) - { - if (adapter == null) throw new ArgumentNullException(nameof(adapter)); - - return adapter.SendPacketsAsync(timeout, cancellationToken, packets); - } - } -} \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Packets/IMqttPacketWithIdentifier.cs b/Frameworks/MQTTnet.NetStandard/Packets/IMqttPacketWithIdentifier.cs index 5f7f8e97..6bbce0cb 100644 --- a/Frameworks/MQTTnet.NetStandard/Packets/IMqttPacketWithIdentifier.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/IMqttPacketWithIdentifier.cs @@ -2,6 +2,6 @@ { public interface IMqttPacketWithIdentifier { - ushort PacketIdentifier { get; set; } + ushort? PacketIdentifier { get; set; } } } diff --git a/Frameworks/MQTTnet.NetStandard/Packets/MqttBasePublishPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttBasePublishPacket.cs index 6218c154..ffafc537 100644 --- a/Frameworks/MQTTnet.NetStandard/Packets/MqttBasePublishPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttBasePublishPacket.cs @@ -2,6 +2,6 @@ { public class MqttBasePublishPacket : MqttBasePacket, IMqttPacketWithIdentifier { - public ushort PacketIdentifier { get; set; } + public ushort? PacketIdentifier { get; set; } } } diff --git a/Frameworks/MQTTnet.NetStandard/Packets/MqttPacketExtensions.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttPacketExtensions.cs deleted file mode 100644 index a3df53c8..00000000 --- a/Frameworks/MQTTnet.NetStandard/Packets/MqttPacketExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; - -namespace MQTTnet.Packets -{ - public static class MqttPacketExtensions - { - public static TResponsePacket CreateResponse(this MqttBasePacket packet) - { - if (packet == null) throw new ArgumentNullException(nameof(packet)); - - var responsePacket = Activator.CreateInstance(); - - if (responsePacket is IMqttPacketWithIdentifier responsePacketWithIdentifier) - { - if (!(packet is IMqttPacketWithIdentifier requestPacketWithIdentifier)) - { - throw new InvalidOperationException("Response packet has PacketIdentifier but request packet does not."); - } - - responsePacketWithIdentifier.PacketIdentifier = requestPacketWithIdentifier.PacketIdentifier; - } - - return responsePacket; - } - } -} diff --git a/Frameworks/MQTTnet.NetStandard/Packets/MqttSubAckPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttSubAckPacket.cs index c4c1a886..3b8cf7a8 100644 --- a/Frameworks/MQTTnet.NetStandard/Packets/MqttSubAckPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttSubAckPacket.cs @@ -6,7 +6,7 @@ namespace MQTTnet.Packets { public sealed class MqttSubAckPacket : MqttBasePacket, IMqttPacketWithIdentifier { - public ushort PacketIdentifier { get; set; } + public ushort? PacketIdentifier { get; set; } public IList SubscribeReturnCodes { get; } = new List(); diff --git a/Frameworks/MQTTnet.NetStandard/Packets/MqttSubscribePacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttSubscribePacket.cs index 25536e3a..63aede16 100644 --- a/Frameworks/MQTTnet.NetStandard/Packets/MqttSubscribePacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttSubscribePacket.cs @@ -5,7 +5,7 @@ namespace MQTTnet.Packets { public sealed class MqttSubscribePacket : MqttBasePacket, IMqttPacketWithIdentifier { - public ushort PacketIdentifier { get; set; } + public ushort? PacketIdentifier { get; set; } public IList TopicFilters { get; set; } = new List(); diff --git a/Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubAckPacket.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubAckPacket.cs index 4797d0a4..688195fa 100644 --- a/Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubAckPacket.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubAckPacket.cs @@ -2,7 +2,7 @@ { public sealed class MqttUnsubAckPacket : MqttBasePacket, IMqttPacketWithIdentifier { - public ushort PacketIdentifier { get; set; } + public ushort? PacketIdentifier { get; set; } public override string ToString() { diff --git a/Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubscribe.cs b/Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubscribe.cs index 2c47cbbd..6c24a477 100644 --- a/Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubscribe.cs +++ b/Frameworks/MQTTnet.NetStandard/Packets/MqttUnsubscribe.cs @@ -4,7 +4,7 @@ namespace MQTTnet.Packets { public sealed class MqttUnsubscribePacket : MqttBasePacket, IMqttPacketWithIdentifier { - public ushort PacketIdentifier { get; set; } + public ushort? PacketIdentifier { get; set; } public IList TopicFilters { get; set; } = new List(); diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs index 63a3c646..0904c759 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketSerializer.cs @@ -397,7 +397,12 @@ namespace MQTTnet.Serializer private static byte Serialize(MqttPubRelPacket packet, MqttPacketWriter writer) { - writer.Write(packet.PacketIdentifier); + if (!packet.PacketIdentifier.HasValue) + { + throw new MqttProtocolViolationException("PubRel packet has no packet identifier."); + } + + writer.Write(packet.PacketIdentifier.Value); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRel, 0x02); } @@ -410,7 +415,12 @@ namespace MQTTnet.Serializer if (packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce) { - writer.Write(packet.PacketIdentifier); + if (!packet.PacketIdentifier.HasValue) + { + throw new MqttProtocolViolationException("Publish packet has no packet identifier."); + } + + writer.Write(packet.PacketIdentifier.Value); } else { @@ -444,21 +454,36 @@ namespace MQTTnet.Serializer private static byte Serialize(MqttPubAckPacket packet, MqttPacketWriter writer) { - writer.Write(packet.PacketIdentifier); + if (!packet.PacketIdentifier.HasValue) + { + throw new MqttProtocolViolationException("PubAck packet has no packet identifier."); + } + + writer.Write(packet.PacketIdentifier.Value); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubAck); } private static byte Serialize(MqttPubRecPacket packet, MqttPacketWriter writer) { - writer.Write(packet.PacketIdentifier); + if (!packet.PacketIdentifier.HasValue) + { + throw new MqttProtocolViolationException("PubRec packet has no packet identifier."); + } + + writer.Write(packet.PacketIdentifier.Value); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubRec); } private static byte Serialize(MqttPubCompPacket packet, MqttPacketWriter writer) { - writer.Write(packet.PacketIdentifier); + if (!packet.PacketIdentifier.HasValue) + { + throw new MqttProtocolViolationException("PubComp packet has no packet identifier."); + } + + writer.Write(packet.PacketIdentifier.Value); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubComp); } @@ -467,7 +492,12 @@ namespace MQTTnet.Serializer { if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.8.3-3]."); - writer.Write(packet.PacketIdentifier); + if (!packet.PacketIdentifier.HasValue) + { + throw new MqttProtocolViolationException("Subscribe packet has no packet identifier."); + } + + writer.Write(packet.PacketIdentifier.Value); if (packet.TopicFilters?.Count > 0) { @@ -483,7 +513,12 @@ namespace MQTTnet.Serializer private static byte Serialize(MqttSubAckPacket packet, MqttPacketWriter writer) { - writer.Write(packet.PacketIdentifier); + if (!packet.PacketIdentifier.HasValue) + { + throw new MqttProtocolViolationException("SubAck packet has no packet identifier."); + } + + writer.Write(packet.PacketIdentifier.Value); if (packet.SubscribeReturnCodes?.Any() == true) { @@ -500,7 +535,12 @@ namespace MQTTnet.Serializer { if (!packet.TopicFilters.Any()) throw new MqttProtocolViolationException("At least one topic filter must be set [MQTT-3.10.3-2]."); - writer.Write(packet.PacketIdentifier); + if (!packet.PacketIdentifier.HasValue) + { + throw new MqttProtocolViolationException("Unsubscribe packet has no packet identifier."); + } + + writer.Write(packet.PacketIdentifier.Value); if (packet.TopicFilters?.Any() == true) { @@ -513,9 +553,14 @@ namespace MQTTnet.Serializer return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Unsubscibe, 0x02); } - private static byte Serialize(IMqttPacketWithIdentifier packet, BinaryWriter writer) + private static byte Serialize(MqttUnsubAckPacket packet, BinaryWriter writer) { - writer.Write(packet.PacketIdentifier); + if (!packet.PacketIdentifier.HasValue) + { + throw new MqttProtocolViolationException("UnsubAck packet has no packet identifier."); + } + + writer.Write(packet.PacketIdentifier.Value); return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.UnsubAck); } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs index 27dd49d9..2469eded 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs @@ -78,7 +78,7 @@ namespace MQTTnet.Server throw new InvalidOperationException(); // should not happen } - await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, packet).ConfigureAwait(false); + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { packet }).ConfigureAwait(false); _logger.Trace("Enqueued packet sent (ClientId: {0}).", _clientSession.ClientId); } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index aee4351c..62bb39fc 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MQTTnet.Adapter; +using MQTTnet.Client; using MQTTnet.Diagnostics; using MQTTnet.Exceptions; using MQTTnet.Internal; @@ -14,6 +15,7 @@ namespace MQTTnet.Server { public sealed class MqttClientSession : IDisposable { + private readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider(); private readonly IMqttServerOptions _options; private readonly IMqttNetLogger _logger; private readonly MqttRetainedMessagesManager _retainedMessagesManager; @@ -129,6 +131,11 @@ namespace MQTTnet.Server var publishPacket = applicationMessage.ToPublishPacket(); publishPacket.QualityOfServiceLevel = result.QualityOfServiceLevel; + if (publishPacket.QualityOfServiceLevel > 0) + { + publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier(); + } + PendingMessagesQueue.Enqueue(publishPacket); } @@ -205,7 +212,7 @@ namespace MQTTnet.Server if (packet is MqttPingReqPacket) { - return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttPingRespPacket()); + return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { new MqttPingRespPacket() }); } if (packet is MqttPubRelPacket pubRelPacket) @@ -215,7 +222,12 @@ namespace MQTTnet.Server if (packet is MqttPubRecPacket pubRecPacket) { - return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, pubRecPacket.CreateResponse()); + var responsePacket = new MqttPubRelPacket + { + PacketIdentifier = pubRecPacket.PacketIdentifier + }; + + return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { responsePacket }); } if (packet is MqttPubAckPacket || packet is MqttPubCompPacket) @@ -246,11 +258,11 @@ namespace MQTTnet.Server private async Task HandleIncomingSubscribePacketAsync(IMqttChannelAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken) { var subscribeResult = await SubscriptionsManager.SubscribeAsync(subscribePacket).ConfigureAwait(false); - await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, subscribeResult.ResponsePacket).ConfigureAwait(false); + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { subscribeResult.ResponsePacket }).ConfigureAwait(false); if (subscribeResult.CloseConnection) { - await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttDisconnectPacket()).ConfigureAwait(false); + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { new MqttDisconnectPacket() }).ConfigureAwait(false); await StopAsync().ConfigureAwait(false); } @@ -260,7 +272,7 @@ namespace MQTTnet.Server private async Task HandleIncomingUnsubscribePacketAsync(IMqttChannelAdapter adapter, MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken) { var unsubscribeResult = await SubscriptionsManager.UnsubscribeAsync(unsubscribePacket).ConfigureAwait(false); - await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, unsubscribeResult); + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { unsubscribeResult }); } private async Task EnqueueSubscribedRetainedMessagesAsync(ICollection topicFilters) @@ -302,7 +314,7 @@ namespace MQTTnet.Server await ApplicationMessageReceivedCallback(this, applicationMessage).ConfigureAwait(false); var response = new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }; - await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response).ConfigureAwait(false); + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { response }).ConfigureAwait(false); } private async Task HandleIncomingPublishPacketWithQoS2(IMqttChannelAdapter adapter, MqttApplicationMessage applicationMessage, MqttPublishPacket publishPacket, CancellationToken cancellationToken) @@ -311,13 +323,13 @@ namespace MQTTnet.Server await ApplicationMessageReceivedCallback(this, applicationMessage).ConfigureAwait(false); var response = new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }; - await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response).ConfigureAwait(false); + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { response }).ConfigureAwait(false); } private Task HandleIncomingPubRelPacketAsync(IMqttChannelAdapter adapter, MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken) { var response = new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier }; - return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response); + return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { response }); } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index fe57552f..f1580891 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -53,10 +53,10 @@ namespace MQTTnet.Server var connectReturnCode = ValidateConnection(connectPacket); if (connectReturnCode != MqttConnectReturnCode.ConnectionAccepted) { - await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttConnAckPacket + await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { new MqttConnAckPacket { ConnectReturnCode = connectReturnCode - }).ConfigureAwait(false); + }}).ConfigureAwait(false); return; } @@ -64,11 +64,11 @@ namespace MQTTnet.Server var result = await GetOrCreateClientSessionAsync(connectPacket).ConfigureAwait(false); clientSession = result.Session; - await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttConnAckPacket + await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { new MqttConnAckPacket { ConnectReturnCode = connectReturnCode, IsSessionPresent = result.IsExistingSession - }).ConfigureAwait(false); + }}).ConfigureAwait(false); ClientConnectedCallback?.Invoke(new ConnectedMqttClient { diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs index 97b9f047..e4ee9214 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSubscriptionsManager.cs @@ -14,7 +14,7 @@ namespace MQTTnet.Server private readonly Dictionary _subscriptions = new Dictionary(); private readonly IMqttServerOptions _options; private readonly string _clientId; - + public MqttClientSubscriptionsManager(IMqttServerOptions options, string clientId) { _options = options ?? throw new ArgumentNullException(nameof(options)); @@ -30,7 +30,11 @@ namespace MQTTnet.Server var result = new MqttClientSubscribeResult { - ResponsePacket = subscribePacket.CreateResponse(), + ResponsePacket = new MqttSubAckPacket + { + PacketIdentifier = subscribePacket.PacketIdentifier + }, + CloseConnection = false }; @@ -87,7 +91,10 @@ namespace MQTTnet.Server _semaphore.Release(); } - return unsubscribePacket.CreateResponse(); + return new MqttUnsubAckPacket + { + PacketIdentifier = unsubscribePacket.PacketIdentifier + }; } public async Task CheckSubscriptionsAsync(MqttApplicationMessage applicationMessage) From 3193381b693402d564ba9d23c13ab0addbbd0f4a Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 25 Mar 2018 14:42:12 +0200 Subject: [PATCH 135/149] Refactor web socket stream. Add mqtt as default sub protocol. --- .../Client/MqttClientWebSocketOptions.cs | 2 +- .../Implementations/WebSocketStream.cs | 36 +++++++++++-------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClientWebSocketOptions.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientWebSocketOptions.cs index 1819daab..114283d4 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClientWebSocketOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientWebSocketOptions.cs @@ -9,7 +9,7 @@ namespace MQTTnet.Client public IDictionary RequestHeaders { get; set; } - public ICollection SubProtocols { get; set; } + public ICollection SubProtocols { get; set; } = new List { "mqtt" }; public CookieContainer CookieContainer { get; set; } diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs b/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs index 1aa02a64..bad03935 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/WebSocketStream.cs @@ -11,9 +11,9 @@ namespace MQTTnet.Implementations { public class WebSocketStream : Stream { - private readonly WebSocket _webSocket; - private readonly byte[] _chunkBuffer = new byte[MqttWebSocketChannel.BufferSize]; + private readonly byte[] _chunckBuffer = new byte[MqttWebSocketChannel.BufferSize]; private readonly Queue _buffer = new Queue(MqttWebSocketChannel.BufferSize); + private readonly WebSocket _webSocket; public WebSocketStream(WebSocket webSocket) { @@ -55,25 +55,28 @@ namespace MQTTnet.Implementations // Use existing date from buffer. while (count > 0 && _buffer.Any()) { - buffer[offset++] = _buffer.Dequeue(); + buffer[offset] = _buffer.Dequeue(); count--; bytesRead++; + offset++; } if (count == 0) { return bytesRead; } - + + // Fetch new data if the buffer is not full. while (_webSocket.State == WebSocketState.Open) { - await FetchChunkAsync(cancellationToken); + await FetchChunkAsync(cancellationToken).ConfigureAwait(false); while (count > 0 && _buffer.Any()) { - buffer[offset++] = _buffer.Dequeue(); + buffer[offset] = _buffer.Dequeue(); count--; bytesRead++; + offset++; } if (count == 0) @@ -111,19 +114,24 @@ namespace MQTTnet.Implementations } private async Task FetchChunkAsync(CancellationToken cancellationToken) - { - var response = await _webSocket.ReceiveAsync(new ArraySegment(_chunkBuffer, 0, _chunkBuffer.Length), cancellationToken).ConfigureAwait(false); - - for (var i = 0; i < response.Count; i++) - { - var @byte = _chunkBuffer[i]; - _buffer.Enqueue(@byte); - } + { + var response = await _webSocket.ReceiveAsync(new ArraySegment(_chunckBuffer, 0, _chunckBuffer.Length), cancellationToken).ConfigureAwait(false); if (response.MessageType == WebSocketMessageType.Close) { await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken).ConfigureAwait(false); } + else if (response.MessageType == WebSocketMessageType.Binary) + { + for (var i = 0; i < response.Count; i++) + { + _buffer.Enqueue(_chunckBuffer[i]); + } + } + else if (response.MessageType == WebSocketMessageType.Text) + { + throw new MqttProtocolViolationException("WebSocket channel received TEXT message."); + } } } } From 3587a8ebd1651f53fac8a7cf3b2edb11b2085c27 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 25 Mar 2018 14:42:34 +0200 Subject: [PATCH 136/149] Add new option which allows configuring the send interval for keep alive packets. --- .../Client/IMqttClientOptions.cs | 2 + .../MQTTnet.NetStandard/Client/MqttClient.cs | 51 +++++++++++++++---- .../Client/MqttClientOptions.cs | 4 +- .../Client/MqttPacketDispatcher.cs | 24 ++++++--- 4 files changed, 63 insertions(+), 18 deletions(-) diff --git a/Frameworks/MQTTnet.NetStandard/Client/IMqttClientOptions.cs b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientOptions.cs index 035dba11..2f5b5042 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/IMqttClientOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientOptions.cs @@ -13,6 +13,8 @@ namespace MQTTnet.Client TimeSpan CommunicationTimeout { get; } TimeSpan KeepAlivePeriod { get; } + TimeSpan? KeepAliveSendInterval { get; set; } + MqttProtocolVersion ProtocolVersion { get; } IMqttClientChannelOptions ChannelOptions { get; } diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs index ffdc7f26..d01a47c8 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -15,6 +16,7 @@ namespace MQTTnet.Client public class MqttClient : IMqttClient { private readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider(); + private readonly Stopwatch _sendTracker = new Stopwatch(); private readonly IMqttClientAdapterFactory _adapterFactory; private readonly MqttPacketDispatcher _packetDispatcher; private readonly IMqttNetLogger _logger; @@ -59,10 +61,12 @@ namespace MQTTnet.Client _logger.Trace("Connection with server established."); await StartReceivingPacketsAsync(_cancellationTokenSource.Token).ConfigureAwait(false); - var connectResponse = await AuthenticateAsync(options.WillMessage).ConfigureAwait(false); + var connectResponse = await AuthenticateAsync(options.WillMessage).ConfigureAwait(false); _logger.Trace("MQTT connection with server established."); + _sendTracker.Restart(); + if (_options.KeepAlivePeriod != TimeSpan.Zero) { StartSendingKeepAliveMessages(_cancellationTokenSource.Token); @@ -149,7 +153,7 @@ namespace MQTTnet.Client case MqttQualityOfServiceLevel.AtMostOnce: { // No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier] - await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, qosGroup).ConfigureAwait(false); + await SendAsync(qosGroup.ToArray()).ConfigureAwait(false); break; } case MqttQualityOfServiceLevel.AtLeastOnce: @@ -167,8 +171,14 @@ namespace MQTTnet.Client foreach (var publishPacket in qosGroup) { publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier(); + var pubRecPacket = await SendAndReceiveAsync(publishPacket).ConfigureAwait(false); - await SendAndReceiveAsync(pubRecPacket.CreateResponse()).ConfigureAwait(false); + var pubRelPacket = new MqttPubRelPacket + { + PacketIdentifier = pubRecPacket.PacketIdentifier + }; + + await SendAndReceiveAsync(pubRelPacket).ConfigureAwait(false); } break; @@ -325,24 +335,31 @@ namespace MQTTnet.Client private Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket) { - return SendAsync(pubRelPacket.CreateResponse()); + var response = new MqttPubCompPacket + { + PacketIdentifier = pubRelPacket.PacketIdentifier + }; + + return SendAsync(response); } - private Task SendAsync(MqttBasePacket packet) + private Task SendAsync(params MqttBasePacket[] packets) { - return _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, packet); + _sendTracker.Restart(); + return _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, packets); } private async Task SendAndReceiveAsync(MqttBasePacket requestPacket) where TResponsePacket : MqttBasePacket { - ushort identifier = 0; + ushort? identifier = null; if (requestPacket is IMqttPacketWithIdentifier requestPacketWithIdentifier) { identifier = requestPacketWithIdentifier.PacketIdentifier; } var packetAwaiter = _packetDispatcher.WaitForPacketAsync(typeof(TResponsePacket), identifier, _options.CommunicationTimeout); - await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, requestPacket).ConfigureAwait(false); + await SendAsync(requestPacket).ConfigureAwait(false); + return (TResponsePacket)await packetAwaiter.ConfigureAwait(false); } @@ -354,8 +371,22 @@ namespace MQTTnet.Client { while (!cancellationToken.IsCancellationRequested) { - await SendAndReceiveAsync(new MqttPingReqPacket()).ConfigureAwait(false); - await Task.Delay(_options.KeepAlivePeriod, cancellationToken).ConfigureAwait(false); + TimeSpan keepAliveSendInterval; + if (_options.KeepAliveSendInterval.HasValue) + { + keepAliveSendInterval = _options.KeepAliveSendInterval.Value; + } + else + { + keepAliveSendInterval = TimeSpan.FromSeconds(_options.KeepAlivePeriod.TotalSeconds * 0.75); + } + + if (_sendTracker.Elapsed > keepAliveSendInterval) + { + await SendAndReceiveAsync(new MqttPingReqPacket()).ConfigureAwait(false); + } + + await Task.Delay(keepAliveSendInterval, cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException) diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClientOptions.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientOptions.cs index 20e711f3..9640a474 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClientOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientOptions.cs @@ -13,7 +13,9 @@ namespace MQTTnet.Client public IMqttClientCredentials Credentials { get; set; } = new MqttClientCredentials(); - public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(5); + public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(15); + + public TimeSpan? KeepAliveSendInterval { get; set; } public TimeSpan CommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10); diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs index ca759311..8b09fbce 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttPacketDispatcher.cs @@ -18,7 +18,7 @@ namespace MQTTnet.Client _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } - public async Task WaitForPacketAsync(Type responseType, ushort identifier, TimeSpan timeout) + public async Task WaitForPacketAsync(Type responseType, ushort? identifier, TimeSpan timeout) { var packetAwaiter = AddPacketAwaiter(responseType, identifier); try @@ -44,13 +44,13 @@ namespace MQTTnet.Client if (_awaiters.TryGetValue(type, out var byId)) { - ushort identifier = 0; + ushort? identifier = 0; if (packet is IMqttPacketWithIdentifier packetWithIdentifier) { identifier = packetWithIdentifier.PacketIdentifier; } - if (byId.TryRemove(identifier, out var tcs)) + if (byId.TryRemove(identifier.Value, out var tcs)) { tcs.TrySetResult(packet); return; @@ -65,12 +65,17 @@ namespace MQTTnet.Client _awaiters.Clear(); } - private TaskCompletionSource AddPacketAwaiter(Type responseType, ushort identifier) + private TaskCompletionSource AddPacketAwaiter(Type responseType, ushort? identifier) { var tcs = new TaskCompletionSource(); + if (!identifier.HasValue) + { + identifier = 0; + } + var byId = _awaiters.GetOrAdd(responseType, key => new ConcurrentDictionary>()); - if (!byId.TryAdd(identifier, tcs)) + if (!byId.TryAdd(identifier.Value, tcs)) { throw new InvalidOperationException($"The packet dispatcher already has an awaiter for packet of type '{responseType}' with identifier {identifier}."); } @@ -78,10 +83,15 @@ namespace MQTTnet.Client return tcs; } - private void RemovePacketAwaiter(Type responseType, ushort identifier) + private void RemovePacketAwaiter(Type responseType, ushort? identifier) { + if (!identifier.HasValue) + { + identifier = 0; + } + var byId = _awaiters.GetOrAdd(responseType, key => new ConcurrentDictionary>()); - byId.TryRemove(identifier, out var _); + byId.TryRemove(identifier.Value, out var _); } } } \ No newline at end of file From e58cb3c9cd8472c4b2c2a3473f6a12c8f51d138b Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 25 Mar 2018 14:42:43 +0200 Subject: [PATCH 137/149] Update docs. --- Build/MQTTnet.nuspec | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 87140eb5..d3f11d56 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -2,7 +2,7 @@ MQTTnet - 2.7.1 + 2.7.2 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,15 +10,11 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * [Core] Fixed wrong parsing of ConnAck packet for protocol version 3.1.0. -* [Core] Log messages are now overriding ToString() and providing a ready to use text representation. -* [Client] Optimized package dispatcher and added several new exceptions. -* [Client] The _ManagedClient_ now has an event which is fired after a queued application message was processed (including exception). -* [Client] The _ManagedClient_ now supports unsubscribing (thanks to @lerppana) -* [Server] Fixed some minor async issues. -* [Server] Fixed wrong comparison of the topic and QoS for retained messages. -* [Server] Added a property which provides access to the used options (read only). -* [Server] Fixed a null ref expection when using an interceptor and publishing via the server directly. + * [Client] Added the subprotocol "mqtt" as default for web socket based connections. +* [Client] Added a new client setting called "KeepAliveSendInterval". It allows configuring the effective interval for sending ping requests. +* [Client] The client will no longer send ping requests if other packets are sent within the configured interval. +* [Server] The server now generates a valid packet identifier when disaptching publish packets to clients. +* [Core] Add several new extension methods. Copyright Christian Kratky 2016-2018 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 cea984cc2f305ac29139bd12c8f2ae8808fe8725 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 29 Mar 2018 22:12:23 +0200 Subject: [PATCH 138/149] Fix stream and socket handling. --- Build/MQTTnet.AspNetCore.nuspec | 6 +- Build/MQTTnet.nuspec | 13 +-- .../Client/MqttClientTcpOptions.cs | 2 + .../Implementations/MqttTcpChannel.Uwp.cs | 57 ++++++++++- .../Implementations/MqttTcpChannel.cs | 97 ++++++++++++++++--- .../Implementations/MqttWebSocketChannel.cs | 13 ++- .../ManagedClient/IManagedMqttClient.cs | 1 + .../ManagedClient/ManagedMqttClient.cs | 1 + .../ManagedMqttClientExtensions.cs | 8 ++ .../ManagedMqttClientOptionsBuilder.cs | 2 +- 10 files changed, 171 insertions(+), 29 deletions(-) diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index 3f5cd0be..0c48e8e5 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -2,7 +2,7 @@ MQTTnet.AspNetCore - 2.7.1 + 2.7.3 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,13 +10,13 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false This is a support library to integrate MQTTnet into AspNetCore. - * Updated to MQTTnet 2.7.1. + * Updated to MQTTnet 2.7.3. Copyright Christian Kratky 2016-2018 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/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index d3f11d56..59cb06ad 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -2,7 +2,7 @@ MQTTnet - 2.7.2 + 2.7.3 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,11 +10,12 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * [Client] Added the subprotocol "mqtt" as default for web socket based connections. -* [Client] Added a new client setting called "KeepAliveSendInterval". It allows configuring the effective interval for sending ping requests. -* [Client] The client will no longer send ping requests if other packets are sent within the configured interval. -* [Server] The server now generates a valid packet identifier when disaptching publish packets to clients. -* [Core] Add several new extension methods. + * [Core] Add several new extension methods. +* [Client] Fixed an issue in _ManagedMqttClientOptionsBuilder_ when using _WithClientOptions_ and an options builder. +* [Client] Added the "IsStarted" property for the managed client. +* [Client] Optimized stream buffer for UWP apps. +* [Client] Added the _BufferSize_ to the TCP options. +* [Core] Fixed some issues in stream and socket handling. Copyright Christian Kratky 2016-2018 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/Frameworks/MQTTnet.NetStandard/Client/MqttClientTcpOptions.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClientTcpOptions.cs index f44d424a..ac96ce63 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClientTcpOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClientTcpOptions.cs @@ -6,6 +6,8 @@ public int? Port { get; set; } + public int BufferSize { get; set; } = 20 * 4096; + public MqttClientTlsOptions TlsOptions { get; set; } = new MqttClientTlsOptions(); } } diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs index c65f789f..fce1629c 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs @@ -15,12 +15,19 @@ namespace MQTTnet.Implementations { public sealed class MqttTcpChannel : IMqttChannel, IDisposable { + // ReSharper disable once MemberCanBePrivate.Global + // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global + public static int BufferSize { get; set; } = 4096 * 20; // Can be changed for fine tuning by library user. + + private readonly int _bufferSize = BufferSize; private readonly MqttClientTcpOptions _options; + private StreamSocket _socket; public MqttTcpChannel(MqttClientTcpOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); + _bufferSize = _options.BufferSize; } public MqttTcpChannel(StreamSocket socket) @@ -69,14 +76,56 @@ namespace MQTTnet.Implementations public void Dispose() { - _socket?.Dispose(); - _socket = null; + try + { + SendStream?.Dispose(); + } + catch (ObjectDisposedException) + { + } + catch (NullReferenceException) + { + } + finally + { + SendStream = null; + } + + try + { + ReceiveStream?.Dispose(); + } + catch (ObjectDisposedException) + { + } + catch (NullReferenceException) + { + } + finally + { + ReceiveStream = null; + } + + try + { + _socket?.Dispose(); + } + catch (ObjectDisposedException) + { + } + catch (NullReferenceException) + { + } + finally + { + _socket = null; + } } private void CreateStreams() { - SendStream = _socket.OutputStream.AsStreamForWrite(); - ReceiveStream = _socket.InputStream.AsStreamForRead(); + SendStream = _socket.OutputStream.AsStreamForWrite(_bufferSize); + ReceiveStream = _socket.InputStream.AsStreamForRead(_bufferSize); } private static Certificate LoadCertificate(MqttClientTcpOptions options) diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs index e908265c..e39b551a 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs @@ -14,15 +14,19 @@ namespace MQTTnet.Implementations { public sealed class MqttTcpChannel : IMqttChannel, IDisposable { - private readonly MqttClientTcpOptions _options; - //todo: this can be used with min dependency NetStandard1.6 #if NET452 || NET461 // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global public static int BufferSize { get; set; } = 4096 * 20; // Can be changed for fine tuning by library user. + + private readonly int _bufferSize = BufferSize; +#else + private readonly int _bufferSize = 0; #endif + private readonly MqttClientTcpOptions _options; + private Socket _socket; private SslStream _sslStream; @@ -32,6 +36,7 @@ namespace MQTTnet.Implementations public MqttTcpChannel(MqttClientTcpOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); + _bufferSize = options.BufferSize; } /// @@ -43,7 +48,7 @@ namespace MQTTnet.Implementations _socket = socket ?? throw new ArgumentNullException(nameof(socket)); _sslStream = sslStream; - CreateStreams(socket, sslStream); + CreateStreams(); } public Stream SendStream { get; private set; } @@ -71,7 +76,7 @@ namespace MQTTnet.Implementations await _sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(_options), SslProtocols.Tls12, _options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false); } - CreateStreams(_socket, _sslStream); + CreateStreams(); } public Task DisconnectAsync() @@ -82,11 +87,70 @@ namespace MQTTnet.Implementations public void Dispose() { - _socket?.Dispose(); - _socket = null; + var oneStreamIsUsed = SendStream != null && ReceiveStream != null && ReferenceEquals(SendStream, ReceiveStream); - _sslStream?.Dispose(); - _sslStream = null; + try + { + SendStream?.Dispose(); + } + catch (ObjectDisposedException) + { + } + catch (NullReferenceException) + { + } + finally + { + SendStream = null; + } + + try + { + if (!oneStreamIsUsed) + { + ReceiveStream?.Dispose(); + } + } + catch (ObjectDisposedException) + { + } + catch (NullReferenceException) + { + } + finally + { + ReceiveStream = null; + } + + try + { + _sslStream?.Dispose(); + } + catch (ObjectDisposedException) + { + } + catch (NullReferenceException) + { + } + finally + { + _sslStream = null; + } + + try + { + _socket?.Dispose(); + } + catch (ObjectDisposedException) + { + } + catch (NullReferenceException) + { + } + finally + { + _socket = null; + } } private bool InternalUserCertificateValidationCallback(object sender, X509Certificate x509Certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) @@ -136,20 +200,27 @@ namespace MQTTnet.Implementations return certificates; } - private void CreateStreams(Socket socket, Stream sslStream) + private void CreateStreams() { - var stream = sslStream ?? new NetworkStream(socket); + Stream stream; + if (_sslStream != null) + { + stream = _sslStream; + } + else + { + stream = new NetworkStream(_socket, true); + } //todo: if branch can be used with min dependency NetStandard1.6 #if NET452 || NET461 - SendStream = new BufferedStream(stream, BufferSize); - ReceiveStream = new BufferedStream(stream, BufferSize); + SendStream = new BufferedStream(stream, _bufferSize); + ReceiveStream = new BufferedStream(stream, _bufferSize); #else SendStream = stream; ReceiveStream = stream; #endif } - } } #endif diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs index 77d99a85..0e85c6ab 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs @@ -96,8 +96,17 @@ namespace MQTTnet.Implementations public void Dispose() { - _webSocket?.Dispose(); - _webSocket = null; + try + { + _webSocket?.Dispose(); + } + catch (ObjectDisposedException) + { + } + finally + { + _webSocket = null; + } } } } \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs index 6f435d5f..97cdeca9 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/IManagedMqttClient.cs @@ -7,6 +7,7 @@ namespace MQTTnet.ManagedClient { public interface IManagedMqttClient : IApplicationMessageReceiver, IApplicationMessagePublisher, IDisposable { + bool IsStarted { get; } bool IsConnected { get; } event EventHandler Connected; diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs index ffb86394..4570319c 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs @@ -40,6 +40,7 @@ namespace MQTTnet.ManagedClient } public bool IsConnected => _mqttClient.IsConnected; + public bool IsStarted => _connectionCancellationToken != null; public event EventHandler Connected; public event EventHandler Disconnected; diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientExtensions.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientExtensions.cs index d75117a5..84b37858 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientExtensions.cs @@ -21,6 +21,14 @@ namespace MQTTnet.ManagedClient return managedClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).WithQualityOfServiceLevel(qualityOfServiceLevel).Build()); } + public static Task SubscribeAsync(this IManagedMqttClient managedClient, string topic) + { + if (managedClient == null) throw new ArgumentNullException(nameof(managedClient)); + if (topic == null) throw new ArgumentNullException(nameof(topic)); + + return managedClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).Build()); + } + public static Task UnsubscribeAsync(this IManagedMqttClient managedClient, params string[] topicFilters) { if (managedClient == null) throw new ArgumentNullException(nameof(managedClient)); diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptionsBuilder.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptionsBuilder.cs index 38aadcfe..4d65bdbb 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptionsBuilder.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClientOptionsBuilder.cs @@ -47,7 +47,7 @@ namespace MQTTnet.ManagedClient { if (options == null) throw new ArgumentNullException(nameof(options)); - if (_clientOptionsBuilder != null) + if (_clientOptionsBuilder == null) { _clientOptionsBuilder = new MqttClientOptionsBuilder(); } From 8f96acaec4350de49d0141cb4faac74683070d50 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 31 Mar 2018 23:10:14 +0200 Subject: [PATCH 139/149] Fixed a race condition in client and server. --- Build/MQTTnet.nuspec | 2 + .../Adapter/IMqttChannelAdapter.cs | 2 +- .../Adapter/MqttChannelAdapter.cs | 39 +++- .../Channel/IMqttChannel.cs | 5 +- .../MQTTnet.NetStandard/Client/MqttClient.cs | 188 +++++++++--------- .../Implementations/MqttTcpChannel.Uwp.cs | 2 +- .../Implementations/MqttTcpChannel.cs | 13 +- .../Serializer/MqttPacketReader.cs | 5 + .../Server/MqttClientKeepAliveMonitor.cs | 12 +- .../Server/MqttClientPendingMessagesQueue.cs | 27 ++- .../Server/MqttClientSession.cs | 10 +- .../Server/MqttClientSessionsManager.cs | 40 ++-- .../TestMqttCommunicationAdapter.cs | 4 + Tests/MQTTnet.TestApp.NetCore/ServerTest.cs | 2 +- 14 files changed, 224 insertions(+), 127 deletions(-) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 59cb06ad..2f0b809d 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -15,6 +15,8 @@ * [Client] Added the "IsStarted" property for the managed client. * [Client] Optimized stream buffer for UWP apps. * [Client] Added the _BufferSize_ to the TCP options. +* [Client] Fixed a race condition which leads to exceptions when reconnecting rapidly. +* [Server] Fixed a race condition which leads to exceptions when clients are reconnecting rapidly. * [Core] Fixed some issues in stream and socket handling. Copyright Christian Kratky 2016-2018 diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/IMqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/IMqttChannelAdapter.cs index 5f58d0c5..7a5c02a2 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/IMqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/IMqttChannelAdapter.cs @@ -7,7 +7,7 @@ using MQTTnet.Serializer; namespace MQTTnet.Adapter { - public interface IMqttChannelAdapter + public interface IMqttChannelAdapter : IDisposable { IMqttPacketSerializer PacketSerializer { get; } diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index 0ad382a1..34ec1e08 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -14,11 +14,12 @@ using MQTTnet.Serializer; namespace MQTTnet.Adapter { - public class MqttChannelAdapter : IMqttChannelAdapter + public sealed class MqttChannelAdapter : IMqttChannelAdapter { private const uint ErrorOperationAborted = 0x800703E3; private const int ReadBufferSize = 4096; // TODO: Move buffer size to config + private bool _isDisposed; private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly IMqttNetLogger _logger; private readonly IMqttChannel _channel; @@ -34,6 +35,7 @@ namespace MQTTnet.Adapter public Task ConnectAsync(TimeSpan timeout) { + ThrowIfDisposed(); _logger.Trace("Connecting [Timeout={0}]", timeout); return ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout)); @@ -41,6 +43,7 @@ namespace MQTTnet.Adapter public Task DisconnectAsync(TimeSpan timeout) { + ThrowIfDisposed(); _logger.Trace("Disconnecting [Timeout={0}]", timeout); return ExecuteAndWrapExceptionAsync(() => _channel.DisconnectAsync().TimeoutAfter(timeout)); @@ -48,6 +51,8 @@ namespace MQTTnet.Adapter public Task SendPacketsAsync(TimeSpan timeout, CancellationToken cancellationToken, IEnumerable packets) { + ThrowIfDisposed(); + return ExecuteAndWrapExceptionAsync(async () => { await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); @@ -55,6 +60,11 @@ namespace MQTTnet.Adapter { foreach (var packet in packets) { + if (cancellationToken.IsCancellationRequested) + { + return; + } + if (packet == null) { continue; @@ -65,10 +75,20 @@ namespace MQTTnet.Adapter var chunks = PacketSerializer.Serialize(packet); foreach (var chunk in chunks) { + if (cancellationToken.IsCancellationRequested) + { + return; + } + await _channel.SendStream.WriteAsync(chunk.Array, chunk.Offset, chunk.Count, cancellationToken).ConfigureAwait(false); } } + if (cancellationToken.IsCancellationRequested) + { + return; + } + if (timeout > TimeSpan.Zero) { await _channel.SendStream.FlushAsync(cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false); @@ -87,6 +107,8 @@ namespace MQTTnet.Adapter public async Task ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken) { + ThrowIfDisposed(); + MqttBasePacket packet = null; await ExecuteAndWrapExceptionAsync(async () => { @@ -214,5 +236,20 @@ namespace MQTTnet.Adapter throw new MqttCommunicationException(exception); } } + + public void Dispose() + { + _isDisposed = true; + _semaphore?.Dispose(); + _channel?.Dispose(); + } + + private void ThrowIfDisposed() + { + if (_isDisposed) + { + throw new ObjectDisposedException(nameof(MqttChannelAdapter)); + } + } } } diff --git a/Frameworks/MQTTnet.NetStandard/Channel/IMqttChannel.cs b/Frameworks/MQTTnet.NetStandard/Channel/IMqttChannel.cs index 809b0b06..b332884d 100644 --- a/Frameworks/MQTTnet.NetStandard/Channel/IMqttChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Channel/IMqttChannel.cs @@ -1,9 +1,10 @@ -using System.IO; +using System; +using System.IO; using System.Threading.Tasks; namespace MQTTnet.Channel { - public interface IMqttChannel + public interface IMqttChannel : IDisposable { Stream SendStream { get; } Stream ReceiveStream { get; } diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs index d01a47c8..f1125665 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs @@ -17,6 +17,7 @@ namespace MQTTnet.Client { private readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider(); private readonly Stopwatch _sendTracker = new Stopwatch(); + private readonly SemaphoreSlim _disconnectLock = new SemaphoreSlim(1, 1); private readonly IMqttClientAdapterFactory _adapterFactory; private readonly MqttPacketDispatcher _packetDispatcher; private readonly IMqttNetLogger _logger; @@ -24,13 +25,15 @@ namespace MQTTnet.Client private IMqttClientOptions _options; private bool _isReceivingPackets; private CancellationTokenSource _cancellationTokenSource; + private Task _packetReceiverTask; + private Task _keepAliveMessageSenderTask; private IMqttChannelAdapter _adapter; public MqttClient(IMqttClientAdapterFactory channelFactory, IMqttNetLogger logger) { _adapterFactory = channelFactory ?? throw new ArgumentNullException(nameof(channelFactory)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - + _packetDispatcher = new MqttPacketDispatcher(logger); } @@ -55,12 +58,12 @@ namespace MQTTnet.Client _packetDispatcher.Reset(); _adapter = _adapterFactory.CreateClientAdapter(options.ChannelOptions, _logger); - + _logger.Trace("Trying to connect with server."); await _adapter.ConnectAsync(_options.CommunicationTimeout).ConfigureAwait(false); _logger.Trace("Connection with server established."); - await StartReceivingPacketsAsync(_cancellationTokenSource.Token).ConfigureAwait(false); + await StartReceivingPacketsAsync().ConfigureAwait(false); var connectResponse = await AuthenticateAsync(options.WillMessage).ConfigureAwait(false); _logger.Trace("MQTT connection with server established."); @@ -69,7 +72,7 @@ namespace MQTTnet.Client if (_options.KeepAlivePeriod != TimeSpan.Zero) { - StartSendingKeepAliveMessages(_cancellationTokenSource.Token); + StartSendingKeepAliveMessages(); } IsConnected = true; @@ -94,7 +97,10 @@ namespace MQTTnet.Client try { - await SendAsync(new MqttDisconnectPacket()).ConfigureAwait(false); + if (!_cancellationTokenSource.IsCancellationRequested) + { + await SendAsync(new MqttDisconnectPacket()).ConfigureAwait(false); + } } finally { @@ -144,7 +150,7 @@ namespace MQTTnet.Client ThrowIfNotConnected(); var publishPackets = applicationMessages.Select(m => m.ToPublishPacket()); - var packetGroups = publishPackets.GroupBy(p => p.QualityOfServiceLevel).OrderBy(g => g.Key); + var packetGroups = publishPackets.GroupBy(p => p.QualityOfServiceLevel).OrderBy(g => g.Key); foreach (var qosGroup in packetGroups) { @@ -153,7 +159,7 @@ namespace MQTTnet.Client case MqttQualityOfServiceLevel.AtMostOnce: { // No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier] - await SendAsync(qosGroup.ToArray()).ConfigureAwait(false); + await SendAsync((MqttPublishPacket[])qosGroup.ToArray()).ConfigureAwait(false); break; } case MqttQualityOfServiceLevel.AtLeastOnce: @@ -194,6 +200,9 @@ namespace MQTTnet.Client public void Dispose() { _cancellationTokenSource?.Dispose(); + _cancellationTokenSource = null; + + _adapter?.Dispose(); } private async Task AuthenticateAsync(MqttApplicationMessage willApplicationMessage) @@ -229,23 +238,31 @@ namespace MQTTnet.Client private async Task DisconnectInternalAsync(Exception exception) { + await _disconnectLock.WaitAsync(); var clientWasConnected = IsConnected; - IsConnected = false; - - var cts = _cancellationTokenSource; - if (cts == null || cts.IsCancellationRequested) - { - return; - } - - cts.Cancel(false); - cts.Dispose(); - _cancellationTokenSource = null; - try { + IsConnected = false; + + if (_cancellationTokenSource == null || _cancellationTokenSource.IsCancellationRequested) + { + return; + } + + _cancellationTokenSource.Cancel(false); + + if (_packetReceiverTask != null) + { + Task.WaitAll(_packetReceiverTask); + } + + if (_keepAliveMessageSenderTask != null) + { + Task.WaitAll(_keepAliveMessageSenderTask); + } + await _adapter.DisconnectAsync(_options.CommunicationTimeout).ConfigureAwait(false); - _logger.Info("Disconnected from adapter."); + _logger.Trace("Disconnected from adapter."); } catch (Exception adapterException) { @@ -253,6 +270,14 @@ namespace MQTTnet.Client } finally { + _adapter?.Dispose(); + _adapter = null; + + _cancellationTokenSource?.Dispose(); + _cancellationTokenSource = null; + + _disconnectLock.Release(); + _logger.Info("Disconnected."); Disconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(clientWasConnected, exception)); } @@ -263,7 +288,7 @@ namespace MQTTnet.Client try { _logger.Info("Received <<< {0}", packet); - + if (packet is MqttPublishPacket publishPacket) { await ProcessReceivedPublishPacketAsync(publishPacket).ConfigureAwait(false); @@ -311,6 +336,11 @@ namespace MQTTnet.Client private Task ProcessReceivedPublishPacketAsync(MqttPublishPacket publishPacket) { + if (_cancellationTokenSource.IsCancellationRequested) + { + return Task.FromResult(0); + } + if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce) { FireApplicationMessageReceivedEvent(publishPacket); @@ -363,54 +393,48 @@ namespace MQTTnet.Client return (TResponsePacket)await packetAwaiter.ConfigureAwait(false); } - private async Task SendKeepAliveMessagesAsync(CancellationToken cancellationToken) + private async Task SendKeepAliveMessagesAsync() { _logger.Info("Start sending keep alive packets."); try { - while (!cancellationToken.IsCancellationRequested) + while (!_cancellationTokenSource.Token.IsCancellationRequested) { - TimeSpan keepAliveSendInterval; + var keepAliveSendInterval = TimeSpan.FromSeconds(_options.KeepAlivePeriod.TotalSeconds * 0.75); if (_options.KeepAliveSendInterval.HasValue) { keepAliveSendInterval = _options.KeepAliveSendInterval.Value; } - else - { - keepAliveSendInterval = TimeSpan.FromSeconds(_options.KeepAlivePeriod.TotalSeconds * 0.75); - } if (_sendTracker.Elapsed > keepAliveSendInterval) { await SendAndReceiveAsync(new MqttPingReqPacket()).ConfigureAwait(false); } - - await Task.Delay(keepAliveSendInterval, cancellationToken).ConfigureAwait(false); + + await Task.Delay(keepAliveSendInterval, _cancellationTokenSource.Token).ConfigureAwait(false); } } catch (OperationCanceledException) { - if (cancellationToken.IsCancellationRequested) - { - return; - } - - await DisconnectInternalAsync(null).ConfigureAwait(false); - } - catch (MqttCommunicationException exception) - { - if (cancellationToken.IsCancellationRequested) - { - return; - } - - _logger.Warning(exception, "MQTT communication exception while sending/receiving keep alive packets."); - await DisconnectInternalAsync(exception).ConfigureAwait(false); } catch (Exception exception) { - _logger.Warning(exception, "Unhandled exception while sending/receiving keep alive packets."); + if (_cancellationTokenSource.Token.IsCancellationRequested) + { + return; + } + + if (exception is MqttCommunicationException) + { + _logger.Warning(exception, "MQTT communication exception while sending/receiving keep alive packets."); + } + else + { + _logger.Warning(exception, "Unhandled exception while sending/receiving keep alive packets."); + + } + await DisconnectInternalAsync(exception).ConfigureAwait(false); } finally @@ -419,48 +443,46 @@ namespace MQTTnet.Client } } - private async Task ReceivePacketsAsync(CancellationToken cancellationToken) + private async Task ReceivePacketsAsync() { _logger.Info("Start receiving packets."); try { - while (!cancellationToken.IsCancellationRequested) + while (!_cancellationTokenSource.Token.IsCancellationRequested) { _isReceivingPackets = true; - var packet = await _adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(false); + var packet = await _adapter.ReceivePacketAsync(TimeSpan.Zero, _cancellationTokenSource.Token).ConfigureAwait(false); - if (cancellationToken.IsCancellationRequested) + if (_cancellationTokenSource.Token.IsCancellationRequested) { return; } - StartProcessReceivedPacket(packet, cancellationToken); + StartProcessReceivedPacket(packet); } } catch (OperationCanceledException) { - if (cancellationToken.IsCancellationRequested) - { - return; - } - - await DisconnectInternalAsync(null).ConfigureAwait(false); - } - catch (MqttCommunicationException exception) - { - if (cancellationToken.IsCancellationRequested) - { - return; - } - - _logger.Warning(exception, "MQTT communication exception while receiving packets."); - await DisconnectInternalAsync(exception).ConfigureAwait(false); } catch (Exception exception) { - _logger.Error(exception, "Unhandled exception while receiving packets."); + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + + if (exception is MqttCommunicationException) + { + _logger.Warning(exception, "MQTT communication exception while receiving packets."); + } + else + { + _logger.Error(exception, "Unhandled exception while receiving packets."); + + } + await DisconnectInternalAsync(exception).ConfigureAwait(false); } finally @@ -469,38 +491,26 @@ namespace MQTTnet.Client } } - private void StartProcessReceivedPacket(MqttBasePacket packet, CancellationToken cancellationToken) + private void StartProcessReceivedPacket(MqttBasePacket packet) { -#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - Task.Run( - async () => await ProcessReceivedPacketAsync(packet).ConfigureAwait(false), - cancellationToken).ConfigureAwait(false); -#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + Task.Run(() => ProcessReceivedPacketAsync(packet), _cancellationTokenSource.Token); } - private async Task StartReceivingPacketsAsync(CancellationToken cancellationToken) + private async Task StartReceivingPacketsAsync() { _isReceivingPackets = false; -#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - Task.Run( - async () => await ReceivePacketsAsync(cancellationToken).ConfigureAwait(false), - cancellationToken).ConfigureAwait(false); -#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + _packetReceiverTask = Task.Run(ReceivePacketsAsync, _cancellationTokenSource.Token); - while (!_isReceivingPackets && !cancellationToken.IsCancellationRequested) + while (!_isReceivingPackets && !_cancellationTokenSource.Token.IsCancellationRequested) { - await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken).ConfigureAwait(false); + await Task.Delay(TimeSpan.FromMilliseconds(100), _cancellationTokenSource.Token).ConfigureAwait(false); } } - private void StartSendingKeepAliveMessages(CancellationToken cancellationToken) + private void StartSendingKeepAliveMessages() { -#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - Task.Run( - async () => await SendKeepAliveMessagesAsync(cancellationToken).ConfigureAwait(false), - cancellationToken).ConfigureAwait(false); -#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + _keepAliveMessageSenderTask = Task.Run(SendKeepAliveMessagesAsync, _cancellationTokenSource.Token); } } } \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs index fce1629c..a9cd18e7 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.Uwp.cs @@ -13,7 +13,7 @@ using MQTTnet.Client; namespace MQTTnet.Implementations { - public sealed class MqttTcpChannel : IMqttChannel, IDisposable + public sealed class MqttTcpChannel : IMqttChannel { // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs index e39b551a..8d43d878 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpChannel.cs @@ -12,9 +12,8 @@ using MQTTnet.Client; namespace MQTTnet.Implementations { - public sealed class MqttTcpChannel : IMqttChannel, IDisposable + public sealed class MqttTcpChannel : IMqttChannel { - //todo: this can be used with min dependency NetStandard1.6 #if NET452 || NET461 // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global @@ -63,7 +62,6 @@ namespace MQTTnet.Implementations _socket = new Socket(SocketType.Stream, ProtocolType.Tcp); } - //todo: else brach can be used with min dependency NET46 #if NET452 || NET461 await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, _options.Server, _options.GetPort(), null).ConfigureAwait(false); #else @@ -73,7 +71,7 @@ namespace MQTTnet.Implementations if (_options.TlsOptions.UseTls) { _sslStream = new SslStream(new NetworkStream(_socket, true), false, InternalUserCertificateValidationCallback); - await _sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(_options), SslProtocols.Tls12, _options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false); + await _sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), SslProtocols.Tls12, _options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false); } CreateStreams(); @@ -184,15 +182,15 @@ namespace MQTTnet.Implementations return _options.TlsOptions.AllowUntrustedCertificates; } - private static X509CertificateCollection LoadCertificates(MqttClientTcpOptions options) + private X509CertificateCollection LoadCertificates() { var certificates = new X509CertificateCollection(); - if (options.TlsOptions.Certificates == null) + if (_options.TlsOptions.Certificates == null) { return certificates; } - foreach (var certificate in options.TlsOptions.Certificates) + foreach (var certificate in _options.TlsOptions.Certificates) { certificates.Add(new X509Certificate2(certificate)); } @@ -212,7 +210,6 @@ namespace MQTTnet.Implementations stream = new NetworkStream(_socket, true); } - //todo: if branch can be used with min dependency NetStandard1.6 #if NET452 || NET461 SendStream = new BufferedStream(stream, _bufferSize); ReceiveStream = new BufferedStream(stream, _bufferSize); diff --git a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs index 9b793ccf..bd43f7d3 100644 --- a/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs +++ b/Frameworks/MQTTnet.NetStandard/Serializer/MqttPacketReader.cs @@ -24,6 +24,11 @@ namespace MQTTnet.Serializer public static async Task ReadHeaderAsync(Stream stream, CancellationToken cancellationToken) { + if (cancellationToken.IsCancellationRequested) + { + return null; + } + // Wait for the next package which starts with the header. At this point there will probably // some large delay and thus the thread should be put back to the pool (await). So ReadByte() // is not an option here. diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientKeepAliveMonitor.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientKeepAliveMonitor.cs index fb67c8d1..6be02f30 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientKeepAliveMonitor.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientKeepAliveMonitor.cs @@ -16,6 +16,8 @@ namespace MQTTnet.Server private readonly Func _timeoutCallback; private readonly IMqttNetLogger _logger; + private Task _workerTask; + public MqttClientKeepAliveMonitor(string clientId, Func timeoutCallback, IMqttNetLogger logger) { _clientId = clientId; @@ -34,7 +36,15 @@ namespace MQTTnet.Server return; } - Task.Run(async () => await RunAsync(keepAlivePeriod, cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false); + _workerTask = Task.Run(() => RunAsync(keepAlivePeriod, cancellationToken).ConfigureAwait(false), cancellationToken); + } + + public void WaitForCompletion() + { + if (_workerTask != null) + { + Task.WaitAll(_workerTask); + } } private async Task RunAsync(int keepAlivePeriod, CancellationToken cancellationToken) diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs index 2469eded..aba14466 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Concurrent; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using MQTTnet.Adapter; @@ -18,6 +19,8 @@ namespace MQTTnet.Server private readonly MqttClientSession _clientSession; private readonly IMqttNetLogger _logger; + private Task _workerTask; + public MqttClientPendingMessagesQueue(IMqttServerOptions options, MqttClientSession clientSession, IMqttNetLogger logger) { _options = options ?? throw new ArgumentNullException(nameof(options)); @@ -36,7 +39,15 @@ namespace MQTTnet.Server return; } - Task.Run(async () => await SendQueuedPacketsAsync(adapter, cancellationToken), cancellationToken).ConfigureAwait(false); + _workerTask = Task.Run(() => SendQueuedPacketsAsync(adapter, cancellationToken), cancellationToken); + } + + public void WaitForCompletion() + { + if (_workerTask != null) + { + Task.WaitAll(_workerTask); + } } public void Enqueue(MqttBasePacket packet) @@ -55,7 +66,7 @@ namespace MQTTnet.Server { while (!cancellationToken.IsCancellationRequested) { - await SendQueuedPacketAsync(adapter, cancellationToken); + await SendNextQueuedPacketAsync(adapter, cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException) @@ -67,7 +78,7 @@ namespace MQTTnet.Server } } - private async Task SendQueuedPacketAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken) + private async Task SendNextQueuedPacketAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken) { MqttBasePacket packet = null; try @@ -78,6 +89,11 @@ namespace MQTTnet.Server throw new InvalidOperationException(); // should not happen } + if (cancellationToken.IsCancellationRequested) + { + return; + } + await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { packet }).ConfigureAwait(false); _logger.Trace("Enqueued packet sent (ClientId: {0}).", _clientSession.ClientId); @@ -110,7 +126,10 @@ namespace MQTTnet.Server } } - await _clientSession.StopAsync(); + if (!cancellationToken.IsCancellationRequested) + { + await _clientSession.StopAsync().ConfigureAwait(false); + } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index 62bb39fc..c44467fa 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -96,14 +96,14 @@ namespace MQTTnet.Server } _cancellationTokenSource?.Cancel(false); + + PendingMessagesQueue.WaitForCompletion(); + KeepAliveMonitor.WaitForCompletion(); + _cancellationTokenSource?.Dispose(); _cancellationTokenSource = null; - if (_adapter != null) - { - await _adapter.DisconnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false); - _adapter = null; - } + _adapter = null; _logger.Info("Client '{0}': Session stopped.", ClientId); } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index f1580891..56dd2d21 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -33,16 +33,18 @@ namespace MQTTnet.Server public Action ClientSubscribedTopicCallback { get; set; } public Action ClientUnsubscribedTopicCallback { get; set; } public Action ApplicationMessageReceivedCallback { get; set; } - + public async Task RunSessionAsync(IMqttChannelAdapter clientAdapter, CancellationToken cancellationToken) { var clientId = string.Empty; MqttClientSession clientSession = null; try { - if (!(await clientAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout, cancellationToken).ConfigureAwait(false) is MqttConnectPacket connectPacket)) + if (!(await clientAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout, cancellationToken) + .ConfigureAwait(false) is MqttConnectPacket connectPacket)) { - throw new MqttProtocolViolationException("The first packet from a client must be a 'CONNECT' packet [MQTT-3.1.0-1]."); + throw new MqttProtocolViolationException( + "The first packet from a client must be a 'CONNECT' packet [MQTT-3.1.0-1]."); } clientId = connectPacket.ClientId; @@ -53,10 +55,13 @@ namespace MQTTnet.Server var connectReturnCode = ValidateConnection(connectPacket); if (connectReturnCode != MqttConnectReturnCode.ConnectionAccepted) { - await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { new MqttConnAckPacket + await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { - ConnectReturnCode = connectReturnCode - }}).ConfigureAwait(false); + new MqttConnAckPacket + { + ConnectReturnCode = connectReturnCode + } + }).ConfigureAwait(false); return; } @@ -64,11 +69,14 @@ namespace MQTTnet.Server var result = await GetOrCreateClientSessionAsync(connectPacket).ConfigureAwait(false); clientSession = result.Session; - await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { new MqttConnAckPacket + await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { - ConnectReturnCode = connectReturnCode, - IsSessionPresent = result.IsExistingSession - }}).ConfigureAwait(false); + new MqttConnAckPacket + { + ConnectReturnCode = connectReturnCode, + IsSessionPresent = result.IsExistingSession + } + }).ConfigureAwait(false); ClientConnectedCallback?.Invoke(new ConnectedMqttClient { @@ -78,6 +86,9 @@ namespace MQTTnet.Server await clientSession.RunAsync(connectPacket, clientAdapter).ConfigureAwait(false); } + catch (OperationCanceledException) + { + } catch (Exception exception) { _logger.Error(exception, exception.Message); @@ -87,12 +98,13 @@ namespace MQTTnet.Server try { await clientAdapter.DisconnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false); + clientAdapter.Dispose(); } - catch (Exception) + catch (Exception exception) { - // ignored + _logger.Error(exception, exception.Message); } - + ClientDisconnectedCallback?.Invoke(new ConnectedMqttClient { ClientId = clientId, @@ -308,7 +320,7 @@ namespace MQTTnet.Server ClientSubscribedTopicCallback = null; ClientUnsubscribedTopicCallback = null; ApplicationMessageReceivedCallback = null; - + _semaphore?.Dispose(); } } diff --git a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs index 2bac46b6..9624a905 100644 --- a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs +++ b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs @@ -17,6 +17,10 @@ namespace MQTTnet.Core.Tests public IMqttPacketSerializer PacketSerializer { get; } = new MqttPacketSerializer(); + public void Dispose() + { + } + public Task ConnectAsync(TimeSpan timeout) { return Task.FromResult(0); diff --git a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs index bd8b4efc..0c661693 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs @@ -89,7 +89,7 @@ namespace MQTTnet.TestApp.NetCore c.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(content.ToString()); } } - catch (Exception e) + catch (Exception) { } }; From 54a0265ef9ca6ce82efdb4d6d3d061d3fad70b5f Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 1 Apr 2018 20:53:32 +0200 Subject: [PATCH 140/149] Fix UnitTests --- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 2 +- .../TestMqttCommunicationAdapter.cs | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index 7cf8bf32..752601f8 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -156,7 +156,7 @@ namespace MQTTnet.Core.Tests var message = new MqttApplicationMessageBuilder().WithTopic("a").WithAtLeastOnceQoS().Build(); await c1.SubscribeAsync(new TopicFilter("a", MqttQualityOfServiceLevel.AtLeastOnce)); - s.PublishAsync(message).Wait(); + await s.PublishAsync(message); await Task.Delay(500); } finally diff --git a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs index 9624a905..a898f765 100644 --- a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs +++ b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapter.cs @@ -47,7 +47,17 @@ namespace MQTTnet.Core.Tests { ThrowIfPartnerIsNull(); - return Task.Run(() => _incomingPackets.Take(), cancellationToken); + return Task.Run(() => + { + try + { + return _incomingPackets.Take(cancellationToken); + } + catch + { + return null; + } + }, cancellationToken); } private void EnqueuePacketInternal(MqttBasePacket packet) From 7de3d79d092e9714b8a307d2e0773007c439e6e4 Mon Sep 17 00:00:00 2001 From: JanEggers Date: Thu, 5 Apr 2018 14:58:13 +0200 Subject: [PATCH 141/149] added tcp adapter --- Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs b/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs index d4bdf394..df87af70 100644 --- a/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs +++ b/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Hosting; using MQTTnet.Adapter; using MQTTnet.Diagnostics; using MQTTnet.Server; +using MQTTnet.Implementations; namespace MQTTnet.AspNetCore { @@ -20,7 +21,9 @@ namespace MQTTnet.AspNetCore services.AddSingleton(s => s.GetService()); services.AddSingleton(); - services.AddSingleton(s => s.GetService()); + services.AddSingleton(); + services.AddSingleton(s => s.GetService()); + services.AddSingleton(s => s.GetService()); return services; } From 7154a7b3dcb544e61185d4003f53ebbdc9d872dc Mon Sep 17 00:00:00 2001 From: JanEggers Date: Thu, 5 Apr 2018 15:55:08 +0200 Subject: [PATCH 142/149] fixed tests --- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 19 ++++------ .../TestServerExtensions.cs | 38 +++++++++++++++++++ 2 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 Tests/MQTTnet.Core.Tests/TestServerExtensions.cs diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index 752601f8..f0c74eaf 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -209,12 +209,9 @@ namespace MQTTnet.Core.Tests await s.StartAsync(new MqttServerOptions()); var c1 = await serverAdapter.ConnectTestClient(s, "c1"); - await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build()); + await c1.PublishAndWaitForAsync(s, new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build()); await c1.DisconnectAsync(); - await Task.Delay(TimeSpan.FromSeconds(2)); - // TODO: Find another way to wait for the retained components. - var c2 = await serverAdapter.ConnectTestClient(s, "c2"); c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++; await c2.SubscribeAsync(new TopicFilterBuilder().WithTopic("retained").Build()); @@ -244,7 +241,7 @@ namespace MQTTnet.Core.Tests await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build()); await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[0]).WithRetainFlag().Build()); await c1.DisconnectAsync(); - + var c2 = await serverAdapter.ConnectTestClient(s, "c2"); c2.ApplicationMessageReceived += (_, __) => receivedMessagesCount++; await c2.SubscribeAsync(new TopicFilter("retained", MqttQualityOfServiceLevel.AtMostOnce)); @@ -274,7 +271,8 @@ namespace MQTTnet.Core.Tests await s.StartAsync(options); var c1 = await serverAdapter.ConnectTestClient(s, "c1"); - await c1.PublishAsync(new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build()); + + await c1.PublishAndWaitForAsync(s, new MqttApplicationMessageBuilder().WithTopic("retained").WithPayload(new byte[3]).WithRetainFlag().Build()); await c1.DisconnectAsync(); } finally @@ -282,8 +280,7 @@ namespace MQTTnet.Core.Tests await s.StopAsync(); } - await Task.Delay(TimeSpan.FromSeconds(2)); - // TODO: Find another way to wait for the retained components. + Assert.AreEqual(1, storage.Messages.Count); s = new MqttFactory().CreateMqttServer(new[] { serverAdapter }, new MqttNetLogger()); @@ -385,17 +382,17 @@ namespace MQTTnet.Core.Tests private class TestStorage : IMqttServerStorage { - private IList _messages = new List(); + public IList Messages = new List(); public Task SaveRetainedMessagesAsync(IList messages) { - _messages = messages; + Messages = messages; return Task.CompletedTask; } public Task> LoadRetainedMessagesAsync() { - return Task.FromResult(_messages); + return Task.FromResult(Messages); } } diff --git a/Tests/MQTTnet.Core.Tests/TestServerExtensions.cs b/Tests/MQTTnet.Core.Tests/TestServerExtensions.cs new file mode 100644 index 00000000..2826f8a4 --- /dev/null +++ b/Tests/MQTTnet.Core.Tests/TestServerExtensions.cs @@ -0,0 +1,38 @@ +using MQTTnet.Client; +using MQTTnet.Server; +using System; +using System.Threading.Tasks; + +namespace MQTTnet.Core.Tests +{ + public static class TestServerExtensions + { + /// + /// publishes a message with a client and waits in the server until a message with the same topic is received + /// + /// + public static async Task PublishAndWaitForAsync(this IMqttClient client, IMqttServer server, MqttApplicationMessage message) + { + var tcs = new TaskCompletionSource(); + + EventHandler handler = (sender, args) => + { + if (args.ApplicationMessage.Topic == message.Topic) + { + tcs.SetResult(true); + } + }; + server.ApplicationMessageReceived += handler; + + try + { + await client.PublishAsync(message); + await tcs.Task; + } + finally + { + server.ApplicationMessageReceived -= handler; + } + } + } +} From 677beddf070a78c72a05d46873f6780f7e4f6a50 Mon Sep 17 00:00:00 2001 From: JanEggers Date: Thu, 5 Apr 2018 16:03:28 +0200 Subject: [PATCH 143/149] fixed code quality compliance --- Tests/MQTTnet.Core.Tests/TestServerExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/MQTTnet.Core.Tests/TestServerExtensions.cs b/Tests/MQTTnet.Core.Tests/TestServerExtensions.cs index 2826f8a4..cbb278ca 100644 --- a/Tests/MQTTnet.Core.Tests/TestServerExtensions.cs +++ b/Tests/MQTTnet.Core.Tests/TestServerExtensions.cs @@ -26,8 +26,8 @@ namespace MQTTnet.Core.Tests try { - await client.PublishAsync(message); - await tcs.Task; + await client.PublishAsync(message).ConfigureAwait(false); + await tcs.Task.ConfigureAwait(false); } finally { From 06a299d212470d05ee8df33007676213c3be16bc Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 5 Apr 2018 23:40:05 +0200 Subject: [PATCH 144/149] Update README.md Remove windows app --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b2e40ed3..6a3111d8 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ If you want to contribute to this project just create a pull request. But only p This library is used in the following projects: * MQTT Client Rx (Wrapper for Reactive Extensions, ) -* MQTT Tester (MQTT client test app for [Android](https://play.google.com/store/apps/details?id=com.liveowl.mqtttester), [iOS](https://itunes.apple.com/us/app/mqtt-tester/id1278621826?mt=8), and [Windows 10](https://www.microsoft.com/en-us/store/p/mqtt-tester/9wzdncrd272c)) +* MQTT Tester (MQTT client test app for [Android](https://play.google.com/store/apps/details?id=com.liveowl.mqtttester) and [iOS](https://itunes.apple.com/us/app/mqtt-tester/id1278621826?mt=8)) * Wirehome (Open Source Home Automation system for .NET, ) From c06d84e834646c7b7a5dc4d89413489e6ac46057 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 6 Apr 2018 22:49:41 +0200 Subject: [PATCH 145/149] Renamed MqttServerAdapter to MqttTcpServerAdapter --- Build/MQTTnet.nuspec | 21 +++++++++++-------- .../ServiceCollectionExtensions.cs | 4 ++-- ...ter.Uwp.cs => MqttTcpServerAdapter.Uwp.cs} | 6 +++--- ...rverAdapter.cs => MqttTcpServerAdapter.cs} | 8 +++---- Frameworks/MQTTnet.NetStandard/MqttFactory.cs | 9 +++++++- 5 files changed, 29 insertions(+), 19 deletions(-) rename Frameworks/MQTTnet.NetStandard/Implementations/{MqttServerAdapter.Uwp.cs => MqttTcpServerAdapter.Uwp.cs} (90%) rename Frameworks/MQTTnet.NetStandard/Implementations/{MqttServerAdapter.cs => MqttTcpServerAdapter.cs} (94%) diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 2f0b809d..1a7661fd 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -2,7 +2,7 @@ MQTTnet - 2.7.3 + 2.7.4 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,14 +10,9 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - * [Core] Add several new extension methods. -* [Client] Fixed an issue in _ManagedMqttClientOptionsBuilder_ when using _WithClientOptions_ and an options builder. -* [Client] Added the "IsStarted" property for the managed client. -* [Client] Optimized stream buffer for UWP apps. -* [Client] Added the _BufferSize_ to the TCP options. -* [Client] Fixed a race condition which leads to exceptions when reconnecting rapidly. -* [Server] Fixed a race condition which leads to exceptions when clients are reconnecting rapidly. -* [Core] Fixed some issues in stream and socket handling. + +* [Server] The _MqttTcpServerAdapter_ is now added to the ASP.NET services. +* [Server] _MqttServerAdapter_ is renamed to _MqttTcpServerAdapter_ (BREAKING CHANGE!). Copyright Christian Kratky 2016-2018 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 @@ -46,6 +41,12 @@ + + + + + + @@ -64,6 +65,8 @@ + + \ No newline at end of file diff --git a/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs b/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs index df87af70..61354cd9 100644 --- a/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs +++ b/Frameworks/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs @@ -21,9 +21,9 @@ namespace MQTTnet.AspNetCore services.AddSingleton(s => s.GetService()); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(s => s.GetService()); - services.AddSingleton(s => s.GetService()); + services.AddSingleton(s => s.GetService()); return services; } diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpServerAdapter.Uwp.cs similarity index 90% rename from Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs rename to Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpServerAdapter.Uwp.cs index 96fbae4a..e71d6fff 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.Uwp.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpServerAdapter.Uwp.cs @@ -9,12 +9,12 @@ using MQTTnet.Server; namespace MQTTnet.Implementations { - public class MqttServerAdapter : IMqttServerAdapter, IDisposable + public class MqttTcpServerAdapter : IMqttServerAdapter, IDisposable { private readonly IMqttNetLogger _logger; private StreamSocketListener _defaultEndpointSocket; - public MqttServerAdapter(IMqttNetLogger logger) + public MqttTcpServerAdapter(IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } @@ -67,7 +67,7 @@ namespace MQTTnet.Implementations } catch (Exception exception) { - _logger.Error(exception, "Error while accepting connection at default endpoint."); + _logger.Error(exception, "Error while accepting connection at default endpoint."); } } } diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpServerAdapter.cs similarity index 94% rename from Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs rename to Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpServerAdapter.cs index 0d0429d3..dc33a3f2 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttServerAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttTcpServerAdapter.cs @@ -14,7 +14,7 @@ using MQTTnet.Server; namespace MQTTnet.Implementations { - public class MqttServerAdapter : IMqttServerAdapter, IDisposable + public class MqttTcpServerAdapter : IMqttServerAdapter, IDisposable { private readonly IMqttNetLogger _logger; @@ -23,7 +23,7 @@ namespace MQTTnet.Implementations private Socket _tlsEndpointSocket; private X509Certificate2 _tlsCertificate; - public MqttServerAdapter(IMqttNetLogger logger) + public MqttTcpServerAdapter(IMqttNetLogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } @@ -117,7 +117,7 @@ namespace MQTTnet.Implementations return; } - _logger.Error(exception, "Error while accepting connection at default endpoint."); + _logger.Error(exception, "Error while accepting connection at default endpoint."); await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); } } @@ -152,7 +152,7 @@ namespace MQTTnet.Implementations return; } - _logger.Error(exception, "Error while accepting connection at TLS endpoint."); + _logger.Error(exception, "Error while accepting connection at TLS endpoint."); await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false); } } diff --git a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs index 5b0174b1..e3b3549a 100644 --- a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs @@ -38,7 +38,14 @@ namespace MQTTnet public IMqttServer CreateMqttServer() { var logger = new MqttNetLogger(); - return CreateMqttServer(new List { new MqttServerAdapter(logger) }, logger); + return CreateMqttServer(logger); + } + + public IMqttServer CreateMqttServer(IMqttNetLogger logger) + { + if (logger == null) throw new ArgumentNullException(nameof(logger)); + + return CreateMqttServer(new List { new MqttTcpServerAdapter(logger) }, logger); } public IMqttServer CreateMqttServer(IEnumerable adapters, IMqttNetLogger logger) From 580a431fbf4b543f26c494ec320d9934f26061ee Mon Sep 17 00:00:00 2001 From: BP Date: Mon, 9 Apr 2018 10:59:34 +0200 Subject: [PATCH 146/149] Update Startup.cs --- Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs b/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs index 9e5f90ae..591cc87d 100644 --- a/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs +++ b/Tests/MQTTnet.TestApp.AspNetCore2/Startup.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; +using MQTTnet; using MQTTnet.AspNetCore; using MQTTnet.Server; From ec41efd8606c0a89e5db997b5aeed21f5bc7b220 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 11 Apr 2018 21:22:08 +0200 Subject: [PATCH 147/149] Fix client dead lock and protocol version issues. --- Build/MQTTnet.AspNetCore.nuspec | 6 +- Build/MQTTnet.nuspec | 14 +-- .../Adapter/MqttChannelAdapter.cs | 8 +- .../Client/IMqttClientAdapterFactory.cs | 2 +- .../Client/IMqttClientOptions.cs | 2 +- .../MQTTnet.NetStandard/Client/MqttClient.cs | 92 +++++++++---------- .../Diagnostics/IMqttNetLogger.cs | 2 +- .../Diagnostics/MqttNetLogger.cs | 2 +- .../MqttClientAdapterFactory.cs | 20 +++- .../Implementations/MqttWebSocketChannel.cs | 2 +- .../ManagedClient/ManagedMqttClient.cs | 2 +- ...qttApplicationMessageInterceptorContext.cs | 4 + .../Server/MqttClientDisconnectedEventArgs.cs | 5 +- .../Server/MqttClientKeepAliveMonitor.cs | 2 +- .../Server/MqttClientPendingMessagesQueue.cs | 4 +- .../Server/MqttClientSession.cs | 23 +++-- .../Server/MqttClientSessionsManager.cs | 40 ++++---- .../Server/MqttRetainedMessagesManager.cs | 2 +- .../MQTTnet.NetStandard/Server/MqttServer.cs | 8 +- .../TestMqttCommunicationAdapterFactory.cs | 2 +- Tests/MQTTnet.TestApp.NetCore/ServerTest.cs | 47 +++++----- .../MainPage.xaml.cs | 27 ++++++ 22 files changed, 190 insertions(+), 126 deletions(-) diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index 0c48e8e5..664b09cd 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -2,7 +2,7 @@ MQTTnet.AspNetCore - 2.7.3 + 2.7.4 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,13 +10,13 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false This is a support library to integrate MQTTnet into AspNetCore. - * Updated to MQTTnet 2.7.3. + * Updated to MQTTnet 2.7.4. Copyright Christian Kratky 2016-2018 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/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 1a7661fd..2b7bf1e6 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -10,9 +10,13 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). - + * [Client] Fixed a deadlock while the client disconnects. +* [Client] Fixed broken support for protocol version 3.1.0. * [Server] The _MqttTcpServerAdapter_ is now added to the ASP.NET services. * [Server] _MqttServerAdapter_ is renamed to _MqttTcpServerAdapter_ (BREAKING CHANGE!). +* [Server] The server no longer sends the will message of a client if the disconnect was clean (via _Disconnect_ packet). +* [Server] The application message interceptor now allows closing the connection. +* [Server] Added a new flag for the _ClientDisconnected_ event which contains a value indicating whether the disconnect was clean (via _Disconnect_ packet). Copyright Christian Kratky 2016-2018 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 @@ -42,12 +46,6 @@ - - - - - - @@ -65,8 +63,6 @@ - - \ No newline at end of file diff --git a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs index 34ec1e08..c2f9ba43 100644 --- a/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs +++ b/Frameworks/MQTTnet.NetStandard/Adapter/MqttChannelAdapter.cs @@ -36,7 +36,7 @@ namespace MQTTnet.Adapter public Task ConnectAsync(TimeSpan timeout) { ThrowIfDisposed(); - _logger.Trace("Connecting [Timeout={0}]", timeout); + _logger.Verbose("Connecting [Timeout={0}]", timeout); return ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout)); } @@ -44,7 +44,7 @@ namespace MQTTnet.Adapter public Task DisconnectAsync(TimeSpan timeout) { ThrowIfDisposed(); - _logger.Trace("Disconnecting [Timeout={0}]", timeout); + _logger.Verbose("Disconnecting [Timeout={0}]", timeout); return ExecuteAndWrapExceptionAsync(() => _channel.DisconnectAsync().TimeoutAfter(timeout)); } @@ -70,7 +70,7 @@ namespace MQTTnet.Adapter continue; } - _logger.Trace("TX >>> {0} [Timeout={1}]", packet, timeout); + _logger.Verbose("TX >>> {0} [Timeout={1}]", packet, timeout); var chunks = PacketSerializer.Serialize(packet); foreach (var chunk in chunks) @@ -135,7 +135,7 @@ namespace MQTTnet.Adapter throw new MqttProtocolViolationException("Received malformed packet."); } - _logger.Trace("RX <<< {0}", packet); + _logger.Verbose("RX <<< {0}", packet); } finally { diff --git a/Frameworks/MQTTnet.NetStandard/Client/IMqttClientAdapterFactory.cs b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientAdapterFactory.cs index 8b144818..c2a7e74b 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/IMqttClientAdapterFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientAdapterFactory.cs @@ -5,6 +5,6 @@ namespace MQTTnet.Client { public interface IMqttClientAdapterFactory { - IMqttChannelAdapter CreateClientAdapter(IMqttClientChannelOptions options, IMqttNetLogger logger); + IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger); } } diff --git a/Frameworks/MQTTnet.NetStandard/Client/IMqttClientOptions.cs b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientOptions.cs index 2f5b5042..647f688b 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/IMqttClientOptions.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/IMqttClientOptions.cs @@ -13,7 +13,7 @@ namespace MQTTnet.Client TimeSpan CommunicationTimeout { get; } TimeSpan KeepAlivePeriod { get; } - TimeSpan? KeepAliveSendInterval { get; set; } + TimeSpan? KeepAliveSendInterval { get; } MqttProtocolVersion ProtocolVersion { get; } diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs index f1125665..90790d5a 100644 --- a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs @@ -57,16 +57,16 @@ namespace MQTTnet.Client _packetIdentifierProvider.Reset(); _packetDispatcher.Reset(); - _adapter = _adapterFactory.CreateClientAdapter(options.ChannelOptions, _logger); + _adapter = _adapterFactory.CreateClientAdapter(options, _logger); - _logger.Trace("Trying to connect with server."); + _logger.Verbose("Trying to connect with server."); await _adapter.ConnectAsync(_options.CommunicationTimeout).ConfigureAwait(false); - _logger.Trace("Connection with server established."); + _logger.Verbose("Connection with server established."); await StartReceivingPacketsAsync().ConfigureAwait(false); var connectResponse = await AuthenticateAsync(options.WillMessage).ConfigureAwait(false); - _logger.Trace("MQTT connection with server established."); + _logger.Verbose("MQTT connection with server established."); _sendTracker.Restart(); @@ -77,12 +77,14 @@ namespace MQTTnet.Client IsConnected = true; Connected?.Invoke(this, new MqttClientConnectedEventArgs(connectResponse.IsSessionPresent)); + + _logger.Info("Connected."); return new MqttClientConnectResult(connectResponse.IsSessionPresent); } catch (Exception exception) { _logger.Error(exception, "Error while connecting with server."); - await DisconnectInternalAsync(exception).ConfigureAwait(false); + await DisconnectInternalAsync(null, exception).ConfigureAwait(false); throw; } @@ -104,7 +106,7 @@ namespace MQTTnet.Client } finally { - await DisconnectInternalAsync(null).ConfigureAwait(false); + await DisconnectInternalAsync(null, null).ConfigureAwait(false); } } @@ -159,7 +161,7 @@ namespace MQTTnet.Client case MqttQualityOfServiceLevel.AtMostOnce: { // No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier] - await SendAsync((MqttPublishPacket[])qosGroup.ToArray()).ConfigureAwait(false); + await SendAsync(qosGroup.Cast().ToArray()).ConfigureAwait(false); break; } case MqttQualityOfServiceLevel.AtLeastOnce: @@ -236,33 +238,48 @@ namespace MQTTnet.Client if (IsConnected) throw new MqttProtocolViolationException(message); } - private async Task DisconnectInternalAsync(Exception exception) + private async Task DisconnectInternalAsync(Task sender, Exception exception) { await _disconnectLock.WaitAsync(); - var clientWasConnected = IsConnected; try { - IsConnected = false; - if (_cancellationTokenSource == null || _cancellationTokenSource.IsCancellationRequested) { return; } _cancellationTokenSource.Cancel(false); + } + catch (Exception adapterException) + { + _logger.Warning(adapterException, "Error while disconnecting from adapter."); + } + finally + { + _disconnectLock.Release(); + } - if (_packetReceiverTask != null) + var clientWasConnected = IsConnected; + IsConnected = false; + + try + { + if (_packetReceiverTask != null && _packetReceiverTask != sender) { - Task.WaitAll(_packetReceiverTask); + _packetReceiverTask.Wait(); } - if (_keepAliveMessageSenderTask != null) + if (_keepAliveMessageSenderTask != null && _keepAliveMessageSenderTask != sender) { - Task.WaitAll(_keepAliveMessageSenderTask); + _keepAliveMessageSenderTask.Wait(); } - await _adapter.DisconnectAsync(_options.CommunicationTimeout).ConfigureAwait(false); - _logger.Trace("Disconnected from adapter."); + if (_adapter != null) + { + await _adapter.DisconnectAsync(_options.CommunicationTimeout).ConfigureAwait(false); + } + + _logger.Verbose("Disconnected from adapter."); } catch (Exception adapterException) { @@ -272,12 +289,9 @@ namespace MQTTnet.Client { _adapter?.Dispose(); _adapter = null; - _cancellationTokenSource?.Dispose(); _cancellationTokenSource = null; - _disconnectLock.Release(); - _logger.Info("Disconnected."); Disconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(clientWasConnected, exception)); } @@ -287,8 +301,6 @@ namespace MQTTnet.Client { try { - _logger.Info("Received <<< {0}", packet); - if (packet is MqttPublishPacket publishPacket) { await ProcessReceivedPublishPacketAsync(publishPacket).ConfigureAwait(false); @@ -395,7 +407,7 @@ namespace MQTTnet.Client private async Task SendKeepAliveMessagesAsync() { - _logger.Info("Start sending keep alive packets."); + _logger.Verbose("Start sending keep alive packets."); try { @@ -415,37 +427,31 @@ namespace MQTTnet.Client await Task.Delay(keepAliveSendInterval, _cancellationTokenSource.Token).ConfigureAwait(false); } } - catch (OperationCanceledException) - { - } catch (Exception exception) { - if (_cancellationTokenSource.Token.IsCancellationRequested) + if (exception is OperationCanceledException) { - return; } - - if (exception is MqttCommunicationException) + else if (exception is MqttCommunicationException) { _logger.Warning(exception, "MQTT communication exception while sending/receiving keep alive packets."); } else { - _logger.Warning(exception, "Unhandled exception while sending/receiving keep alive packets."); - + _logger.Error(exception, "Unhandled exception while sending/receiving keep alive packets."); } - - await DisconnectInternalAsync(exception).ConfigureAwait(false); + + await DisconnectInternalAsync(_keepAliveMessageSenderTask, exception).ConfigureAwait(false); } finally { - _logger.Info("Stopped sending keep alive packets."); + _logger.Verbose("Stopped sending keep alive packets."); } } private async Task ReceivePacketsAsync() { - _logger.Info("Start receiving packets."); + _logger.Verbose("Start receiving packets."); try { @@ -463,31 +469,25 @@ namespace MQTTnet.Client StartProcessReceivedPacket(packet); } } - catch (OperationCanceledException) - { - } catch (Exception exception) { - if (_cancellationTokenSource.IsCancellationRequested) + if (exception is OperationCanceledException) { - return; } - - if (exception is MqttCommunicationException) + else if (exception is MqttCommunicationException) { _logger.Warning(exception, "MQTT communication exception while receiving packets."); } else { _logger.Error(exception, "Unhandled exception while receiving packets."); - } - await DisconnectInternalAsync(exception).ConfigureAwait(false); + await DisconnectInternalAsync(_packetReceiverTask, exception).ConfigureAwait(false); } finally { - _logger.Info("Stopped receiving packets."); + _logger.Verbose("Stopped receiving packets."); } } diff --git a/Frameworks/MQTTnet.NetStandard/Diagnostics/IMqttNetLogger.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/IMqttNetLogger.cs index a65207bf..6ed16de2 100644 --- a/Frameworks/MQTTnet.NetStandard/Diagnostics/IMqttNetLogger.cs +++ b/Frameworks/MQTTnet.NetStandard/Diagnostics/IMqttNetLogger.cs @@ -6,7 +6,7 @@ namespace MQTTnet.Diagnostics { event EventHandler LogMessagePublished; - void Trace(string message, params object[] parameters); + void Verbose(string message, params object[] parameters); void Info(string message, params object[] parameters); diff --git a/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogger.cs b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogger.cs index 8ad1d4c4..53598b2b 100644 --- a/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogger.cs +++ b/Frameworks/MQTTnet.NetStandard/Diagnostics/MqttNetLogger.cs @@ -13,7 +13,7 @@ namespace MQTTnet.Diagnostics public event EventHandler LogMessagePublished; - public void Trace(string message, params object[] parameters) + public void Verbose(string message, params object[] parameters) { Publish(MqttNetLogLevel.Verbose, null, message, parameters); } diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttClientAdapterFactory.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttClientAdapterFactory.cs index f8f0e996..4692d7ee 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttClientAdapterFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttClientAdapterFactory.cs @@ -8,18 +8,28 @@ namespace MQTTnet.Implementations { public class MqttClientAdapterFactory : IMqttClientAdapterFactory { - public IMqttChannelAdapter CreateClientAdapter(IMqttClientChannelOptions options, IMqttNetLogger logger) + public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger) { if (options == null) throw new ArgumentNullException(nameof(options)); - switch (options) + var serializer = new MqttPacketSerializer { ProtocolVersion = options.ProtocolVersion }; + + switch (options.ChannelOptions) { case MqttClientTcpOptions tcpOptions: - return new MqttChannelAdapter(new MqttTcpChannel(tcpOptions), new MqttPacketSerializer(), logger); + { + return new MqttChannelAdapter(new MqttTcpChannel(tcpOptions), serializer, logger); + } + case MqttClientWebSocketOptions webSocketOptions: - return new MqttChannelAdapter(new MqttWebSocketChannel(webSocketOptions), new MqttPacketSerializer(), logger); + { + return new MqttChannelAdapter(new MqttWebSocketChannel(webSocketOptions), serializer, logger); + } + default: - throw new NotSupportedException(); + { + throw new NotSupportedException(); + } } } } diff --git a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs index 0e85c6ab..057a07e5 100644 --- a/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs +++ b/Frameworks/MQTTnet.NetStandard/Implementations/MqttWebSocketChannel.cs @@ -9,7 +9,7 @@ using MQTTnet.Client; namespace MQTTnet.Implementations { - public sealed class MqttWebSocketChannel : IMqttChannel, IDisposable + public sealed class MqttWebSocketChannel : IMqttChannel { // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global diff --git a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs index 4570319c..f1ce45d9 100644 --- a/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs +++ b/Frameworks/MQTTnet.NetStandard/ManagedClient/ManagedMqttClient.cs @@ -244,7 +244,7 @@ namespace MQTTnet.ManagedClient } finally { - _logger.Trace("Stopped publishing messages."); + _logger.Verbose("Stopped publishing messages."); } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttApplicationMessageInterceptorContext.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttApplicationMessageInterceptorContext.cs index 8074d527..56126015 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttApplicationMessageInterceptorContext.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttApplicationMessageInterceptorContext.cs @@ -11,5 +11,9 @@ public string ClientId { get; } public MqttApplicationMessage ApplicationMessage { get; set; } + + public bool AcceptPublish { get; set; } = true; + + public bool CloseConnection { get; set; } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientDisconnectedEventArgs.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientDisconnectedEventArgs.cs index 78372bc9..6dd505e5 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientDisconnectedEventArgs.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientDisconnectedEventArgs.cs @@ -4,11 +4,14 @@ namespace MQTTnet.Server { public class MqttClientDisconnectedEventArgs : EventArgs { - public MqttClientDisconnectedEventArgs(ConnectedMqttClient client) + public MqttClientDisconnectedEventArgs(ConnectedMqttClient client, bool wasCleanDisconnect) { Client = client ?? throw new ArgumentNullException(nameof(client)); + WasCleanDisconnect = wasCleanDisconnect; } public ConnectedMqttClient Client { get; } + + public bool WasCleanDisconnect { get; } } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientKeepAliveMonitor.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientKeepAliveMonitor.cs index 6be02f30..3f215369 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientKeepAliveMonitor.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientKeepAliveMonitor.cs @@ -81,7 +81,7 @@ namespace MQTTnet.Server } finally { - _logger.Trace("Client {0}: Stopped checking keep alive timeout.", _clientId); + _logger.Verbose("Client {0}: Stopped checking keep alive timeout.", _clientId); } } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs index aba14466..99493874 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientPendingMessagesQueue.cs @@ -57,7 +57,7 @@ namespace MQTTnet.Server _queue.Enqueue(packet); _queueWaitSemaphore.Release(); - _logger.Trace("Enqueued packet (ClientId: {0}).", _clientSession.ClientId); + _logger.Verbose("Enqueued packet (ClientId: {0}).", _clientSession.ClientId); } private async Task SendQueuedPacketsAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken) @@ -96,7 +96,7 @@ namespace MQTTnet.Server await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { packet }).ConfigureAwait(false); - _logger.Trace("Enqueued packet sent (ClientId: {0}).", _clientSession.ClientId); + _logger.Verbose("Enqueued packet sent (ClientId: {0}).", _clientSession.ClientId); } catch (Exception exception) { diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs index c44467fa..8514da99 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSession.cs @@ -23,6 +23,7 @@ namespace MQTTnet.Server private IMqttChannelAdapter _adapter; private CancellationTokenSource _cancellationTokenSource; private MqttApplicationMessage _willMessage; + private bool _wasCleanDisconnect; public MqttClientSession( string clientId, @@ -55,7 +56,7 @@ namespace MQTTnet.Server public bool IsConnected => _adapter != null; - public async Task RunAsync(MqttConnectPacket connectPacket, IMqttChannelAdapter adapter) + public async Task RunAsync(MqttConnectPacket connectPacket, IMqttChannelAdapter adapter) { if (connectPacket == null) throw new ArgumentNullException(nameof(connectPacket)); if (adapter == null) throw new ArgumentNullException(nameof(adapter)); @@ -64,6 +65,7 @@ namespace MQTTnet.Server { var cancellationTokenSource = new CancellationTokenSource(); + _wasCleanDisconnect = false; _willMessage = connectPacket.WillMessage; _adapter = adapter; _cancellationTokenSource = cancellationTokenSource; @@ -84,9 +86,11 @@ namespace MQTTnet.Server { _logger.Error(exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId); } + + return _wasCleanDisconnect; } - public async Task StopAsync() + public async Task StopAsync(bool wasCleanDisconnect = false) { try { @@ -95,6 +99,8 @@ namespace MQTTnet.Server return; } + _wasCleanDisconnect = wasCleanDisconnect; + _cancellationTokenSource?.Cancel(false); PendingMessagesQueue.WaitForCompletion(); @@ -110,9 +116,10 @@ namespace MQTTnet.Server finally { var willMessage = _willMessage; - if (willMessage != null) + _willMessage = null; // clear willmessage so it is send just once + + if (willMessage != null && !wasCleanDisconnect) { - _willMessage = null; // clear willmessage so it is send just once await ApplicationMessageReceivedCallback(this, willMessage).ConfigureAwait(false); } } @@ -246,7 +253,12 @@ namespace MQTTnet.Server return HandleIncomingUnsubscribePacketAsync(adapter, unsubscribePacket, cancellationToken); } - if (packet is MqttDisconnectPacket || packet is MqttConnectPacket) + if (packet is MqttDisconnectPacket) + { + return StopAsync(true); + } + + if (packet is MqttConnectPacket) { return StopAsync(); } @@ -262,7 +274,6 @@ namespace MQTTnet.Server if (subscribeResult.CloseConnection) { - await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new[] { new MqttDisconnectPacket() }).ConfigureAwait(false); await StopAsync().ConfigureAwait(false); } diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs index 56dd2d21..8dd9d062 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttClientSessionsManager.cs @@ -29,7 +29,7 @@ namespace MQTTnet.Server } public Action ClientConnectedCallback { get; set; } - public Action ClientDisconnectedCallback { get; set; } + public Action ClientDisconnectedCallback { get; set; } public Action ClientSubscribedTopicCallback { get; set; } public Action ClientUnsubscribedTopicCallback { get; set; } public Action ApplicationMessageReceivedCallback { get; set; } @@ -37,7 +37,9 @@ namespace MQTTnet.Server public async Task RunSessionAsync(IMqttChannelAdapter clientAdapter, CancellationToken cancellationToken) { var clientId = string.Empty; + var wasCleanDisconnect = false; MqttClientSession clientSession = null; + try { if (!(await clientAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout, cancellationToken) @@ -84,7 +86,7 @@ namespace MQTTnet.Server ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion }); - await clientSession.RunAsync(connectPacket, clientAdapter).ConfigureAwait(false); + wasCleanDisconnect = await clientSession.RunAsync(connectPacket, clientAdapter).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -110,7 +112,8 @@ namespace MQTTnet.Server ClientId = clientId, ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion, PendingApplicationMessages = clientSession?.PendingMessagesQueue.Count ?? 0 - }); + }, + wasCleanDisconnect); } } @@ -156,8 +159,13 @@ namespace MQTTnet.Server { try { - applicationMessage = InterceptApplicationMessage(senderClientSession, applicationMessage); - if (applicationMessage == null) + var interceptorContext = InterceptApplicationMessage(senderClientSession, applicationMessage); + if (interceptorContext.CloseConnection) + { + await senderClientSession.StopAsync().ConfigureAwait(false); + } + + if (interceptorContext.ApplicationMessage == null || !interceptorContext.AcceptPublish) { return; } @@ -230,20 +238,20 @@ namespace MQTTnet.Server } } - private MqttApplicationMessage InterceptApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage) + private MqttApplicationMessageInterceptorContext InterceptApplicationMessage(MqttClientSession senderClientSession, MqttApplicationMessage applicationMessage) { - var interceptor = _options.ApplicationMessageInterceptor; - if (interceptor == null) - { - return applicationMessage; - } - var interceptorContext = new MqttApplicationMessageInterceptorContext( senderClientSession?.ClientId, applicationMessage); + var interceptor = _options.ApplicationMessageInterceptor; + if (interceptor == null) + { + return interceptorContext; + } + interceptor(interceptorContext); - return interceptorContext.ApplicationMessage; + return interceptorContext; } private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket) @@ -279,11 +287,11 @@ namespace MQTTnet.Server clientSession.Dispose(); clientSession = null; - _logger.Trace("Stopped existing session of client '{0}'.", connectPacket.ClientId); + _logger.Verbose("Stopped existing session of client '{0}'.", connectPacket.ClientId); } else { - _logger.Trace("Reusing existing session of client '{0}'.", connectPacket.ClientId); + _logger.Verbose("Reusing existing session of client '{0}'.", connectPacket.ClientId); } } @@ -302,7 +310,7 @@ namespace MQTTnet.Server _sessions[connectPacket.ClientId] = clientSession; - _logger.Trace("Created a new session for client '{0}'.", connectPacket.ClientId); + _logger.Verbose("Created a new session for client '{0}'.", connectPacket.ClientId); } return new GetOrCreateClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession }; diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs index 11cac24f..f998557e 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttRetainedMessagesManager.cs @@ -132,7 +132,7 @@ namespace MQTTnet.Server if (!saveIsRequired) { - _logger.Trace("Skipped saving retained messages because no changes were detected."); + _logger.Verbose("Skipped saving retained messages because no changes were detected."); } if (saveIsRequired && _options.Storage != null) diff --git a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs index de33800a..63294420 100644 --- a/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs +++ b/Frameworks/MQTTnet.NetStandard/Server/MqttServer.cs @@ -138,10 +138,10 @@ namespace MQTTnet.Server ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(client)); } - private void OnClientDisconnected(ConnectedMqttClient client) + private void OnClientDisconnected(ConnectedMqttClient client, bool wasCleanDisconnect) { - _logger.Info("Client '{0}': Disconnected.", client.ClientId); - ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(client)); + _logger.Info("Client '{0}': Disconnected (clean={1}).", client.ClientId, wasCleanDisconnect); + ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(client, wasCleanDisconnect)); } private void OnClientSubscribedTopic(string clientId, TopicFilter topicFilter) @@ -162,7 +162,7 @@ namespace MQTTnet.Server private void OnClientAccepted(object sender, MqttServerAdapterClientAcceptedEventArgs eventArgs) { eventArgs.SessionTask = Task.Run( - async () => await _clientSessionsManager.RunSessionAsync(eventArgs.Client, _cancellationTokenSource.Token).ConfigureAwait(false), + () => _clientSessionsManager.RunSessionAsync(eventArgs.Client, _cancellationTokenSource.Token), _cancellationTokenSource.Token); } } diff --git a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs index eb291f9f..4fe35373 100644 --- a/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs +++ b/Tests/MQTTnet.Core.Tests/TestMqttCommunicationAdapterFactory.cs @@ -13,7 +13,7 @@ namespace MQTTnet.Core.Tests _adapter = adapter; } - public IMqttChannelAdapter CreateClientAdapter(IMqttClientChannelOptions options, IMqttNetLogger logger) + public IMqttChannelAdapter CreateClientAdapter(IMqttClientOptions options, IMqttNetLogger logger) { return _adapter; } diff --git a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs index 0c661693..80a8e5a4 100644 --- a/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs +++ b/Tests/MQTTnet.TestApp.NetCore/ServerTest.cs @@ -3,7 +3,6 @@ using System.Text; using System.Threading.Tasks; using MQTTnet.Protocol; using MQTTnet.Server; -using Newtonsoft.Json.Linq; namespace MQTTnet.TestApp.NetCore { @@ -38,6 +37,12 @@ namespace MQTTnet.TestApp.NetCore // based payload with the timestamp is a suitable use case. context.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O")); } + + if (context.ApplicationMessage.Topic == "not_allowed_topic") + { + context.AcceptPublish = false; + context.CloseConnection = true; + } }, SubscriptionInterceptor = context => { @@ -72,27 +77,27 @@ namespace MQTTnet.TestApp.NetCore ConsoleColor.Magenta); }; - options.ApplicationMessageInterceptor = c => - { - if (c.ApplicationMessage.Payload == null || c.ApplicationMessage.Payload.Length == 0) - { - return; - } + //options.ApplicationMessageInterceptor = c => + //{ + // if (c.ApplicationMessage.Payload == null || c.ApplicationMessage.Payload.Length == 0) + // { + // return; + // } - try - { - var content = JObject.Parse(Encoding.UTF8.GetString(c.ApplicationMessage.Payload)); - var timestampProperty = content.Property("timestamp"); - if (timestampProperty != null && timestampProperty.Value.Type == JTokenType.Null) - { - timestampProperty.Value = DateTime.Now.ToString("O"); - c.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(content.ToString()); - } - } - catch (Exception) - { - } - }; + // try + // { + // var content = JObject.Parse(Encoding.UTF8.GetString(c.ApplicationMessage.Payload)); + // var timestampProperty = content.Property("timestamp"); + // if (timestampProperty != null && timestampProperty.Value.Type == JTokenType.Null) + // { + // timestampProperty.Value = DateTime.Now.ToString("O"); + // c.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(content.ToString()); + // } + // } + // catch (Exception) + // { + // } + //}; mqttServer.ClientDisconnected += (s, e) => { diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index 3ed12bf4..da0c2f31 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -13,6 +13,8 @@ using MQTTnet.Implementations; using MQTTnet.ManagedClient; using MQTTnet.Protocol; using MQTTnet.Server; +using MqttClientConnectedEventArgs = MQTTnet.Client.MqttClientConnectedEventArgs; +using MqttClientDisconnectedEventArgs = MQTTnet.Client.MqttClientDisconnectedEventArgs; namespace MQTTnet.TestApp.UniversalWindows { @@ -33,6 +35,11 @@ namespace MQTTnet.TestApp.UniversalWindows private async void OnTraceMessagePublished(object sender, MqttNetLogMessagePublishedEventArgs e) { _traceMessages.Enqueue(e.TraceMessage); + await UpdateLogAsync(); + } + + private async Task UpdateLogAsync() + { while (_traceMessages.Count > 100) { _traceMessages.TryDequeue(out _); @@ -113,11 +120,15 @@ namespace MQTTnet.TestApp.UniversalWindows { await _mqttClient.DisconnectAsync(); _mqttClient.ApplicationMessageReceived -= OnApplicationMessageReceived; + _mqttClient.Connected -= OnConnected; + _mqttClient.Disconnected -= OnDisconnected; } var factory = new MqttFactory(); _mqttClient = factory.CreateMqttClient(); _mqttClient.ApplicationMessageReceived += OnApplicationMessageReceived; + _mqttClient.Connected += OnConnected; + _mqttClient.Disconnected += OnDisconnected; await _mqttClient.ConnectAsync(options); } @@ -127,6 +138,22 @@ namespace MQTTnet.TestApp.UniversalWindows } } + private void OnDisconnected(object sender, MqttClientDisconnectedEventArgs e) + { + _traceMessages.Enqueue(new MqttNetLogMessage("", DateTime.Now, -1, + "", MqttNetLogLevel.Info, "! DISCONNECTED EVENT FIRED", null)); + + Task.Run(UpdateLogAsync); + } + + private void OnConnected(object sender, MqttClientConnectedEventArgs e) + { + _traceMessages.Enqueue(new MqttNetLogMessage("", DateTime.Now, -1, + "", MqttNetLogLevel.Info, "! CONNECTED EVENT FIRED", null)); + + Task.Run(UpdateLogAsync); + } + private async void OnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs eventArgs) { var item = $"Timestamp: {DateTime.Now:O} | Topic: {eventArgs.ApplicationMessage.Topic} | Payload: {Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload)} | QoS: {eventArgs.ApplicationMessage.QualityOfServiceLevel}"; From b23d25217b94179620bd1de914d1dc0190897cf2 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 11 Apr 2018 23:12:27 +0200 Subject: [PATCH 148/149] Fix unit tests. --- Tests/MQTTnet.Core.Tests/MqttServerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs index f0c74eaf..dc2f5251 100644 --- a/Tests/MQTTnet.Core.Tests/MqttServerTests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttServerTests.cs @@ -75,7 +75,7 @@ namespace MQTTnet.Core.Tests await s.StopAsync(); } - Assert.AreEqual(1, receivedMessagesCount); + Assert.AreEqual(0, receivedMessagesCount); } [TestMethod] From 9f4f37bb51c1e41e527ed84c0a9e9439cdacfb4a Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 28 Apr 2018 20:24:07 +0200 Subject: [PATCH 149/149] Update nugets --- Build/MQTTnet.AspNetCore.nuspec | 6 +++--- Build/MQTTnet.Extensions.Rpc.nuspec | 16 ++++++++-------- Build/MQTTnet.nuspec | 2 +- MQTTnet.sln | 1 + 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index 664b09cd..4245077b 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -2,7 +2,7 @@ MQTTnet.AspNetCore - 2.7.4 + 2.7.5 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,13 +10,13 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false This is a support library to integrate MQTTnet into AspNetCore. - * Updated to MQTTnet 2.7.4. + * Updated to MQTTnet 2.7.5. Copyright Christian Kratky 2016-2018 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/Build/MQTTnet.Extensions.Rpc.nuspec b/Build/MQTTnet.Extensions.Rpc.nuspec index ec09c1de..cb31c21b 100644 --- a/Build/MQTTnet.Extensions.Rpc.nuspec +++ b/Build/MQTTnet.Extensions.Rpc.nuspec @@ -2,7 +2,7 @@ MQTTnet.Extensions.Rpc - 2.6.0 + 2.7.5 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE @@ -10,32 +10,32 @@ https://raw.githubusercontent.com/chkr1011/MQTTnet/master/Images/Logo_128x128.png false This is a extension library which allows executing synchronous device calls including a response using MQTTnet. - * Initial version. + * Updated to MQTTnet 2.7.5. Copyright Christian Kratky 2016-2017 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/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 2b7bf1e6..4146cd38 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -2,7 +2,7 @@ MQTTnet - 2.7.4 + 2.7.5 Christian Kratky Christian Kratky https://github.com/chkr1011/MQTTnet/blob/master/LICENSE diff --git a/MQTTnet.sln b/MQTTnet.sln index cece21c5..fab76088 100644 --- a/MQTTnet.sln +++ b/MQTTnet.sln @@ -18,6 +18,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{67C28AC1 appveyor.yml = appveyor.yml Build\build.ps1 = Build\build.ps1 Build\MQTTnet.AspNetCore.nuspec = Build\MQTTnet.AspNetCore.nuspec + Build\MQTTnet.Extensions.Rpc.nuspec = Build\MQTTnet.Extensions.Rpc.nuspec Build\MQTTnet.nuspec = Build\MQTTnet.nuspec EndProjectSection EndProject