diff --git a/Build/MQTTnet.AspNetCore.nuspec b/Build/MQTTnet.AspNetCore.nuspec index a46cd815..d38efb1a 100644 --- a/Build/MQTTnet.AspNetCore.nuspec +++ b/Build/MQTTnet.AspNetCore.nuspec @@ -11,7 +11,7 @@ false This is a support library to integrate MQTTnet into AspNetCore. For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/). - Copyright Christian Kratky 2016-2019 + Copyright Christian Kratky 2016-2020 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.ManagedClient.nuspec b/Build/MQTTnet.Extensions.ManagedClient.nuspec index edec7696..8ae373fa 100644 --- a/Build/MQTTnet.Extensions.ManagedClient.nuspec +++ b/Build/MQTTnet.Extensions.ManagedClient.nuspec @@ -11,7 +11,7 @@ false This is an extension library which provides a managed MQTT client with additional features using MQTTnet. For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/). - Copyright Christian Kratky 2016-2019 + Copyright Christian Kratky 2016-2020 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 ce81cb6e..4089ae4c 100644 --- a/Build/MQTTnet.Extensions.Rpc.nuspec +++ b/Build/MQTTnet.Extensions.Rpc.nuspec @@ -11,7 +11,7 @@ false This is an extension library which allows executing synchronous device calls including a response using MQTTnet. For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/). - Copyright Christian Kratky 2016-2019 + Copyright Christian Kratky 2016-2020 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.WebSocket4Net.nuspec b/Build/MQTTnet.Extensions.WebSocket4Net.nuspec index 054933ed..0baacddd 100644 --- a/Build/MQTTnet.Extensions.WebSocket4Net.nuspec +++ b/Build/MQTTnet.Extensions.WebSocket4Net.nuspec @@ -11,7 +11,7 @@ false This is an extension library which allows using _WebSocket4Net_ as transport for MQTTnet clients. For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/). - Copyright Christian Kratky 2016-2019 + Copyright Christian Kratky 2016-2020 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.NETStandard.nuspec b/Build/MQTTnet.NETStandard.nuspec index c505dd18..ef1b3fac 100644 --- a/Build/MQTTnet.NETStandard.nuspec +++ b/Build/MQTTnet.NETStandard.nuspec @@ -11,7 +11,7 @@ false This package contains the .NET Standard version of MQTTnet only. For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/). - Copyright Christian Kratky 2016-2019 + Copyright Christian Kratky 2016-2020 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 318faddc..c5320540 100644 --- a/Build/MQTTnet.nuspec +++ b/Build/MQTTnet.nuspec @@ -11,6 +11,7 @@ false MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol. +* [All] Due to a merge issue not all changes are included in 3.0.8. All these changes are now included in this version. * [ManagedClient] Added builder class for MqttClientUnsubscribeOptions (thanks to @dominikviererbe). * [ManagedClient] Added support for persisted sessions (thansk to @PMExtra). * [Client] Improve connection stability (thanks to @jltjohanlindqvist). @@ -23,7 +24,7 @@ * [MQTTnet.AspNetCore] improved compatibility with AspNetCore 3.1 * [LowLevelMqttClient] Added low level MQTT client in order to provide more flexibility when using the MQTT protocol. This client requires detailed knowledge about the MQTT protocol. - Copyright Christian Kratky 2016-2019 + Copyright Christian Kratky 2016-2020 MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin diff --git a/Source/MQTTnet.AspnetCore/Extensions/ReaderExtensions.cs b/Source/MQTTnet.AspnetCore/Extensions/ReaderExtensions.cs index 2746c7db..d6ec5847 100644 --- a/Source/MQTTnet.AspnetCore/Extensions/ReaderExtensions.cs +++ b/Source/MQTTnet.AspnetCore/Extensions/ReaderExtensions.cs @@ -80,7 +80,7 @@ namespace MQTTnet.AspNetCore headerLength = 0; bodyLength = 0; - var temp = input.Slice(0, Math.Min(5, input.Length)).GetMemory(); + var temp = input.Slice(0, Math.Min(5, input.Length)).GetMemory().Span; do { @@ -88,7 +88,7 @@ namespace MQTTnet.AspNetCore { return false; } - encodedByte = temp.Span[index]; + encodedByte = temp[index]; index++; value += (byte)(encodedByte & 127) * multiplier; diff --git a/Source/MQTTnet.AspnetCore/Extensions/ServiceCollectionExtensions.cs b/Source/MQTTnet.AspnetCore/Extensions/ServiceCollectionExtensions.cs index 8606142f..84a10d49 100644 --- a/Source/MQTTnet.AspnetCore/Extensions/ServiceCollectionExtensions.cs +++ b/Source/MQTTnet.AspnetCore/Extensions/ServiceCollectionExtensions.cs @@ -1,10 +1,10 @@ -using System; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using MQTTnet.Adapter; using MQTTnet.Diagnostics; -using MQTTnet.Server; using MQTTnet.Implementations; -using Microsoft.Extensions.DependencyInjection; +using MQTTnet.Server; +using System; namespace MQTTnet.AspNetCore { @@ -13,7 +13,7 @@ namespace MQTTnet.AspNetCore public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, IMqttServerOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); - + services.AddSingleton(options); services.AddHostedMqttServer(); @@ -23,7 +23,8 @@ namespace MQTTnet.AspNetCore public static IServiceCollection AddHostedMqttServer(this IServiceCollection services, Action configure) { - services.AddSingleton(s => { + services.AddSingleton(s => + { var builder = new MqttServerOptionsBuilder(); configure(builder); return builder.Build(); @@ -36,7 +37,8 @@ namespace MQTTnet.AspNetCore public static IServiceCollection AddHostedMqttServerWithServices(this IServiceCollection services, Action configure) { - services.AddSingleton(s => { + services.AddSingleton(s => + { var builder = new AspNetMqttServerOptionsBuilder(s); configure(builder); return builder.Build(); @@ -60,14 +62,12 @@ namespace MQTTnet.AspNetCore private static IServiceCollection AddHostedMqttServer(this IServiceCollection services) { var logger = new MqttNetLogger(); - var childLogger = logger.CreateChildLogger(); services.AddSingleton(logger); - services.AddSingleton(childLogger); services.AddSingleton(); services.AddSingleton(s => s.GetService()); services.AddSingleton(s => s.GetService()); - + return services; } diff --git a/Source/MQTTnet.AspnetCore/MQTTnet.AspNetCore.csproj b/Source/MQTTnet.AspnetCore/MQTTnet.AspNetCore.csproj index c0768b4b..e6f0582a 100644 --- a/Source/MQTTnet.AspnetCore/MQTTnet.AspNetCore.csproj +++ b/Source/MQTTnet.AspnetCore/MQTTnet.AspNetCore.csproj @@ -14,11 +14,13 @@ RELEASE;NETSTANDARD2_0 - + + + - + diff --git a/Source/MQTTnet.Extensions.ManagedClient/MqttFactoryExtensions.cs b/Source/MQTTnet.Extensions.ManagedClient/MqttFactoryExtensions.cs index 37393ac2..b0fd8827 100644 --- a/Source/MQTTnet.Extensions.ManagedClient/MqttFactoryExtensions.cs +++ b/Source/MQTTnet.Extensions.ManagedClient/MqttFactoryExtensions.cs @@ -1,5 +1,5 @@ -using System; -using MQTTnet.Diagnostics; +using MQTTnet.Diagnostics; +using System; namespace MQTTnet.Extensions.ManagedClient { @@ -9,7 +9,7 @@ namespace MQTTnet.Extensions.ManagedClient { if (factory == null) throw new ArgumentNullException(nameof(factory)); - return new ManagedMqttClient(factory.CreateMqttClient(), factory.DefaultLogger.CreateChildLogger()); + return new ManagedMqttClient(factory.CreateMqttClient(), factory.DefaultLogger); } public static IManagedMqttClient CreateManagedMqttClient(this IMqttFactory factory, IMqttNetLogger logger) @@ -17,7 +17,7 @@ namespace MQTTnet.Extensions.ManagedClient if (factory == null) throw new ArgumentNullException(nameof(factory)); if (logger == null) throw new ArgumentNullException(nameof(logger)); - return new ManagedMqttClient(factory.CreateMqttClient(logger), logger.CreateChildLogger()); + return new ManagedMqttClient(factory.CreateMqttClient(logger), logger); } } } \ No newline at end of file diff --git a/Source/MQTTnet.Server/Logging/MqttNetLoggerWrapper.cs b/Source/MQTTnet.Server/Logging/MqttNetLoggerWrapper.cs index 668ae265..adaa3632 100644 --- a/Source/MQTTnet.Server/Logging/MqttNetLoggerWrapper.cs +++ b/Source/MQTTnet.Server/Logging/MqttNetLoggerWrapper.cs @@ -21,15 +21,24 @@ namespace MQTTnet.Server.Logging return new MqttNetLogger(source); } - public void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception) + public void Publish(MqttNetLogLevel level, string source, string message, object[] parameters, Exception exception) { - var convertedLogLevel = ConvertLogLevel(logLevel); + var convertedLogLevel = ConvertLogLevel(level); _logger.Log(convertedLogLevel, exception, message, parameters); var logMessagePublishedEvent = LogMessagePublished; if (logMessagePublishedEvent != null) { - var logMessage = new MqttNetLogMessage(null, DateTime.UtcNow, Thread.CurrentThread.ManagedThreadId, source, logLevel, message, exception); + var logMessage = new MqttNetLogMessage + { + Timestamp = DateTime.UtcNow, + ThreadId = Thread.CurrentThread.ManagedThreadId, + Source = source, + Level = level, + Message = message, + Exception = exception + }; + logMessagePublishedEvent.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage)); } } diff --git a/Source/MQTTnet.Server/Mqtt/MqttServerService.cs b/Source/MQTTnet.Server/Mqtt/MqttServerService.cs index 85c41768..9bcb42c5 100644 --- a/Source/MQTTnet.Server/Mqtt/MqttServerService.cs +++ b/Source/MQTTnet.Server/Mqtt/MqttServerService.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.WebSockets; -using System.Security.Authentication; -using System.Text; -using System.Threading.Tasks; -using IronPython.Runtime; +using IronPython.Runtime; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using MQTTnet.Adapter; @@ -16,6 +9,13 @@ using MQTTnet.Protocol; using MQTTnet.Server.Configuration; using MQTTnet.Server.Scripting; using MQTTnet.Server.Status; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.WebSockets; +using System.Security.Authentication; +using System.Text; +using System.Threading.Tasks; namespace MQTTnet.Server.Mqtt { @@ -65,11 +65,11 @@ namespace MQTTnet.Server.Mqtt _pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _webSocketServerAdapter = new MqttWebSocketServerAdapter(mqttFactory.Logger.CreateChildLogger()); + _webSocketServerAdapter = new MqttWebSocketServerAdapter(mqttFactory.Logger); var adapters = new List { - new MqttTcpServerAdapter(mqttFactory.Logger.CreateChildLogger()) + new MqttTcpServerAdapter(mqttFactory.Logger) { TreatSocketOpeningErrorAsWarning = true // Opening other ports than for HTTP is not allows in Azure App Services. }, @@ -215,7 +215,7 @@ namespace MQTTnet.Server.Mqtt options .WithEncryptedEndpoint() .WithEncryptionSslProtocol(SslProtocols.Tls12); - + if (!string.IsNullOrEmpty(_settings.EncryptedTcpEndPoint?.Certificate?.Path)) { IMqttServerCertificateCredentials certificateCredentials = null; @@ -230,7 +230,7 @@ namespace MQTTnet.Server.Mqtt options.WithEncryptionCertificate(_settings.EncryptedTcpEndPoint.Certificate.ReadCertificate(), certificateCredentials); } - + if (_settings.EncryptedTcpEndPoint.TryReadIPv4(out var address4)) { options.WithEncryptedEndpointBoundIPAddress(address4); diff --git a/Source/MQTTnet/Adapter/MqttChannelAdapter.cs b/Source/MQTTnet/Adapter/MqttChannelAdapter.cs index 5dd02815..e8bed007 100644 --- a/Source/MQTTnet/Adapter/MqttChannelAdapter.cs +++ b/Source/MQTTnet/Adapter/MqttChannelAdapter.cs @@ -19,14 +19,14 @@ namespace MQTTnet.Adapter const uint ErrorOperationAborted = 0x800703E3; const int ReadBufferSize = 4096; // TODO: Move buffer size to config - readonly SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1); - readonly IMqttNetLogger _logger; readonly IMqttChannel _channel; readonly MqttPacketReader _packetReader; readonly byte[] _fixedHeaderBuffer = new byte[2]; + SemaphoreSlim _writerSemaphore = new SemaphoreSlim(1, 1); + long _bytesReceived; long _bytesSent; @@ -143,7 +143,7 @@ namespace MQTTnet.Adapter } finally { - _writerSemaphore.Release(); + _writerSemaphore?.Release(); } } @@ -212,7 +212,9 @@ namespace MQTTnet.Adapter if (disposing) { _channel?.Dispose(); + _writerSemaphore?.Dispose(); + _writerSemaphore = null; } base.Dispose(disposing); diff --git a/Source/MQTTnet/Diagnostics/IMqttNetLogger.cs b/Source/MQTTnet/Diagnostics/IMqttNetLogger.cs index 40bb04b5..b952cf56 100644 --- a/Source/MQTTnet/Diagnostics/IMqttNetLogger.cs +++ b/Source/MQTTnet/Diagnostics/IMqttNetLogger.cs @@ -6,7 +6,7 @@ namespace MQTTnet.Diagnostics { event EventHandler LogMessagePublished; - IMqttNetLogger CreateChildLogger(string source = null); + IMqttNetLogger CreateChildLogger(string source); void Publish(MqttNetLogLevel logLevel, string message, object[] parameters, Exception exception); } diff --git a/Source/MQTTnet/Diagnostics/MqttNetLogMessage.cs b/Source/MQTTnet/Diagnostics/MqttNetLogMessage.cs index 107d8f34..1ab1b4c1 100644 --- a/Source/MQTTnet/Diagnostics/MqttNetLogMessage.cs +++ b/Source/MQTTnet/Diagnostics/MqttNetLogMessage.cs @@ -4,30 +4,19 @@ namespace MQTTnet.Diagnostics { public class MqttNetLogMessage { - public MqttNetLogMessage(string logId, DateTime timestamp, int threadId, string source, MqttNetLogLevel level, string message, Exception exception) - { - LogId = logId; - Timestamp = timestamp; - ThreadId = threadId; - Source = source; - Level = level; - Message = message; - Exception = exception; - } + public string LogId { get; set; } - public string LogId { get; } + public DateTime Timestamp { get; set; } - public DateTime Timestamp { get; } + public int ThreadId { get; set; } - public int ThreadId { get; } + public string Source { get; set; } - public string Source { get; } + public MqttNetLogLevel Level { get; set; } - public MqttNetLogLevel Level { get; } + public string Message { get; set; } - public string Message { get; } - - public Exception Exception { get; } + public Exception Exception { get; set; } public override string ToString() { diff --git a/Source/MQTTnet/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs b/Source/MQTTnet/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs index 1b3488e1..e64a40d0 100644 --- a/Source/MQTTnet/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs +++ b/Source/MQTTnet/Diagnostics/MqttNetLogMessagePublishedEventArgs.cs @@ -6,8 +6,9 @@ namespace MQTTnet.Diagnostics { public MqttNetLogMessagePublishedEventArgs(MqttNetLogMessage logMessage) { - TraceMessage = logMessage ?? throw new ArgumentNullException(nameof(logMessage)); LogMessage = logMessage ?? throw new ArgumentNullException(nameof(logMessage)); + + TraceMessage = logMessage ?? throw new ArgumentNullException(nameof(logMessage)); } [Obsolete("Use new proeprty LogMessage instead.")] diff --git a/Source/MQTTnet/Diagnostics/MqttNetLogger.cs b/Source/MQTTnet/Diagnostics/MqttNetLogger.cs index b14bf343..71610d41 100644 --- a/Source/MQTTnet/Diagnostics/MqttNetLogger.cs +++ b/Source/MQTTnet/Diagnostics/MqttNetLogger.cs @@ -7,6 +7,8 @@ namespace MQTTnet.Diagnostics readonly string _logId; readonly string _source; + readonly MqttNetLogger _parentLogger; + public MqttNetLogger(string source, string logId = null) { _source = source; @@ -17,19 +19,31 @@ namespace MQTTnet.Diagnostics { } - public event EventHandler LogMessagePublished; - - public IMqttNetLogger CreateChildLogger(string source = null) + MqttNetLogger(MqttNetLogger parentLogger, string logId, string source) { - return new MqttNetLogger(source, _logId); + _parentLogger = parentLogger ?? throw new ArgumentNullException(nameof(parentLogger)); + _source = source ?? throw new ArgumentNullException(nameof(source)); + + _logId = logId; } - public void Publish(MqttNetLogLevel logLevel, string message, object[] parameters, Exception exception) + public event EventHandler LogMessagePublished; + + // TODO: Consider creating a LoggerFactory which will allow creating loggers. The logger factory will + // be the only place which has the published event. + public IMqttNetLogger CreateChildLogger(string source) + { + if (source is null) throw new ArgumentNullException(nameof(source)); + + return new MqttNetLogger(this, _logId, source); + } + + public void Publish(MqttNetLogLevel level, string message, object[] parameters, Exception exception) { var hasLocalListeners = LogMessagePublished != null; var hasGlobalListeners = MqttNetGlobalLogger.HasListeners; - if (!hasLocalListeners && !hasGlobalListeners) + if (!hasLocalListeners && !hasGlobalListeners && _parentLogger == null) { return; } @@ -46,17 +60,35 @@ namespace MQTTnet.Diagnostics } } - var traceMessage = new MqttNetLogMessage(_logId, DateTime.UtcNow, Environment.CurrentManagedThreadId, _source, logLevel, message, exception); + var logMessage = new MqttNetLogMessage + { + LogId = _logId, + Timestamp = DateTime.UtcNow, + Source = _source, + ThreadId = Environment.CurrentManagedThreadId, + Level = level, + Message = message, + Exception = exception + }; if (hasGlobalListeners) { - MqttNetGlobalLogger.Publish(traceMessage); + MqttNetGlobalLogger.Publish(logMessage); } if (hasLocalListeners) { - LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(traceMessage)); + LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage)); } + + _parentLogger?.Publish(logMessage); + } + + void Publish(MqttNetLogMessage logMessage) + { + LogMessagePublished?.Invoke(this, new MqttNetLogMessagePublishedEventArgs(logMessage)); + + _parentLogger?.Publish(logMessage); } } } \ No newline at end of file diff --git a/Source/MQTTnet/Implementations/MqttTcpChannel.cs b/Source/MQTTnet/Implementations/MqttTcpChannel.cs index 9b2ba56e..71050e1e 100644 --- a/Source/MQTTnet/Implementations/MqttTcpChannel.cs +++ b/Source/MQTTnet/Implementations/MqttTcpChannel.cs @@ -1,25 +1,24 @@ #if !WINDOWS_UWP -using System; -using System.Net.Security; -using System.Net.Sockets; -using System.Security.Cryptography.X509Certificates; -using System.Threading.Tasks; -using System.IO; -using System.Linq; -using System.Runtime.ExceptionServices; -using System.Threading; using MQTTnet.Channel; using MQTTnet.Client.Options; -using MQTTnet.Internal; +using System; +using System.IO; +using System.Linq; +using System.Net.Security; +using System.Net.Sockets; +using System.Runtime.ExceptionServices; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; namespace MQTTnet.Implementations { - public class MqttTcpChannel : Disposable, IMqttChannel + public sealed class MqttTcpChannel : IDisposable, IMqttChannel { - private readonly IMqttClientOptions _clientOptions; - private readonly MqttClientTcpOptions _options; + readonly IMqttClientOptions _clientOptions; + readonly MqttClientTcpOptions _options; - private Stream _stream; + Stream _stream; public MqttTcpChannel(IMqttClientOptions clientOptions) { @@ -69,7 +68,7 @@ namespace MQTTnet.Implementations // of the actual value. socket.DualMode = _options.DualMode.Value; } - + // Workaround for: workaround for https://github.com/dotnet/corefx/issues/24430 using (cancellationToken.Register(() => socket.Dispose())) { @@ -83,7 +82,7 @@ namespace MQTTnet.Implementations var sslStream = new SslStream(networkStream, false, InternalUserCertificateValidationCallback); _stream = sslStream; - await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), _options.TlsOptions.SslProtocol, !_options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false); + await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), _options.TlsOptions.SslProtocol, !_options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false); } else { @@ -95,12 +94,14 @@ namespace MQTTnet.Implementations public Task DisconnectAsync(CancellationToken cancellationToken) { - Cleanup(); + Dispose(); return Task.FromResult(0); } public async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { + if (buffer is null) throw new ArgumentNullException(nameof(buffer)); + try { // Workaround for: https://github.com/dotnet/corefx/issues/24430 @@ -131,6 +132,8 @@ namespace MQTTnet.Implementations public async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { + if (buffer is null) throw new ArgumentNullException(nameof(buffer)); + try { // Workaround for: https://github.com/dotnet/corefx/issues/24430 @@ -159,7 +162,7 @@ namespace MQTTnet.Implementations } } - private void Cleanup() + public void Dispose() { // When the stream is disposed it will also close the socket and this will also dispose it. // So there is no need to dispose the socket again. @@ -178,16 +181,7 @@ namespace MQTTnet.Implementations _stream = null; } - protected override void Dispose(bool disposing) - { - if (disposing) - { - Cleanup(); - } - base.Dispose(disposing); - } - - private bool InternalUserCertificateValidationCallback(object sender, X509Certificate x509Certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + bool InternalUserCertificateValidationCallback(object sender, X509Certificate x509Certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (_options.TlsOptions.CertificateValidationCallback != null) { @@ -218,7 +212,7 @@ namespace MQTTnet.Implementations return _options.TlsOptions.AllowUntrustedCertificates; } - private X509CertificateCollection LoadCertificates() + X509CertificateCollection LoadCertificates() { var certificates = new X509CertificateCollection(); if (_options.TlsOptions.Certificates == null) diff --git a/Source/MQTTnet/Implementations/PlatformAbstractionLayer.cs b/Source/MQTTnet/Implementations/PlatformAbstractionLayer.cs index ee9057a4..80c08903 100644 --- a/Source/MQTTnet/Implementations/PlatformAbstractionLayer.cs +++ b/Source/MQTTnet/Implementations/PlatformAbstractionLayer.cs @@ -7,6 +7,7 @@ namespace MQTTnet.Implementations { public static class PlatformAbstractionLayer { + // TODO: Consider creating primitives like "MqttNetSocket" which will wrap all required methods and do the platform stuff. public static async Task AcceptAsync(Socket socket) { #if NET452 || NET461 @@ -90,7 +91,7 @@ namespace MQTTnet.Implementations public static Task CompletedTask { - get + get { #if NET452 return Task.FromResult(0); diff --git a/Source/MQTTnet/Internal/Disposable.cs b/Source/MQTTnet/Internal/Disposable.cs index 2ce34237..e9b05eae 100644 --- a/Source/MQTTnet/Internal/Disposable.cs +++ b/Source/MQTTnet/Internal/Disposable.cs @@ -2,32 +2,20 @@ namespace MQTTnet.Internal { - public class Disposable : IDisposable + public abstract class Disposable : IDisposable { - protected bool IsDisposed => _isDisposed; + protected bool IsDisposed { get; private set; } = false; protected void ThrowIfDisposed() { - if (_isDisposed) + if (IsDisposed) { throw new ObjectDisposedException(GetType().Name); } } - - #region IDisposable Support - - private bool _isDisposed = false; // To detect redundant calls - protected virtual void Dispose(bool disposing) { - if (disposing) - { - // TODO: dispose managed state (managed objects). - } - - // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. - // TODO: set large fields to null. } // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. @@ -40,18 +28,17 @@ namespace MQTTnet.Internal // This code added to correctly implement the disposable pattern. public void Dispose() { - if (_isDisposed) + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + + if (IsDisposed) { return; } - _isDisposed = true; + IsDisposed = true; - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. Dispose(true); - // TODO: uncomment the following line if the finalizer is overridden above. - // GC.SuppressFinalize(this); + GC.SuppressFinalize(this); } - #endregion } } diff --git a/Source/MQTTnet/MqttFactory.cs b/Source/MQTTnet/MqttFactory.cs index da85cba7..ed70fd51 100644 --- a/Source/MQTTnet/MqttFactory.cs +++ b/Source/MQTTnet/MqttFactory.cs @@ -93,7 +93,7 @@ namespace MQTTnet { if (logger == null) throw new ArgumentNullException(nameof(logger)); - return CreateMqttServer(new List { new MqttTcpServerAdapter(logger.CreateChildLogger()) }, logger); + return CreateMqttServer(new List { new MqttTcpServerAdapter(logger) }, logger); } public IMqttServer CreateMqttServer(IEnumerable serverAdapters, IMqttNetLogger logger) @@ -101,14 +101,14 @@ namespace MQTTnet if (serverAdapters == null) throw new ArgumentNullException(nameof(serverAdapters)); if (logger == null) throw new ArgumentNullException(nameof(logger)); - return new MqttServer(serverAdapters, logger.CreateChildLogger()); + return new MqttServer(serverAdapters, logger); } public IMqttServer CreateMqttServer(IEnumerable serverAdapters) { if (serverAdapters == null) throw new ArgumentNullException(nameof(serverAdapters)); - return new MqttServer(serverAdapters, DefaultLogger.CreateChildLogger()); + return new MqttServer(serverAdapters, DefaultLogger); } } } \ No newline at end of file diff --git a/Source/MQTTnet/PacketDispatcher/MqttPacketAwaiter.cs b/Source/MQTTnet/PacketDispatcher/MqttPacketAwaiter.cs index b1722900..d8f0a043 100644 --- a/Source/MQTTnet/PacketDispatcher/MqttPacketAwaiter.cs +++ b/Source/MQTTnet/PacketDispatcher/MqttPacketAwaiter.cs @@ -1,9 +1,9 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using MQTTnet.Exceptions; +using MQTTnet.Exceptions; using MQTTnet.Internal; using MQTTnet.Packets; +using System; +using System.Threading; +using System.Threading.Tasks; namespace MQTTnet.PacketDispatcher { @@ -12,7 +12,7 @@ namespace MQTTnet.PacketDispatcher private readonly TaskCompletionSource _taskCompletionSource; private readonly ushort? _packetIdentifier; private readonly MqttPacketDispatcher _owningPacketDispatcher; - + public MqttPacketAwaiter(ushort? packetIdentifier, MqttPacketDispatcher owningPacketDispatcher) { _packetIdentifier = packetIdentifier; @@ -87,6 +87,7 @@ namespace MQTTnet.PacketDispatcher { _owningPacketDispatcher.RemovePacketAwaiter(_packetIdentifier); } + base.Dispose(disposing); } } diff --git a/Source/MQTTnet/Server/MqttClientConnection.cs b/Source/MQTTnet/Server/MqttClientConnection.cs index a21873bd..54475d08 100644 --- a/Source/MQTTnet/Server/MqttClientConnection.cs +++ b/Source/MQTTnet/Server/MqttClientConnection.cs @@ -437,9 +437,8 @@ namespace MQTTnet.Server { _logger.Warning(exception, "Sending publish packet failed: Communication exception (ClientId: {0}).", ClientId); } - else if (exception is OperationCanceledException && _cancellationToken.Token.IsCancellationRequested) + else if (exception is OperationCanceledException) { - // The cancellation was triggered externally. } else { diff --git a/Source/MQTTnet/Server/MqttClientSessionsManager.cs b/Source/MQTTnet/Server/MqttClientSessionsManager.cs index dcbf5a4f..285f63e9 100644 --- a/Source/MQTTnet/Server/MqttClientSessionsManager.cs +++ b/Source/MQTTnet/Server/MqttClientSessionsManager.cs @@ -1,5 +1,6 @@ using MQTTnet.Adapter; using MQTTnet.Diagnostics; +using MQTTnet.Exceptions; using MQTTnet.Formatter; using MQTTnet.Internal; using MQTTnet.Packets; @@ -236,12 +237,23 @@ namespace MQTTnet.Server string clientId = null; var clientWasConnected = true; + MqttConnectPacket connectPacket = null; + try { - var firstPacket = await channelAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout, cancellationToken).ConfigureAwait(false); - if (!(firstPacket is MqttConnectPacket connectPacket)) + try { - _logger.Warning(null, "The first packet from client '{0}' was no 'CONNECT' packet [MQTT-3.1.0-1].", channelAdapter.Endpoint); + var firstPacket = await channelAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout, cancellationToken).ConfigureAwait(false); + connectPacket = firstPacket as MqttConnectPacket; + if (connectPacket == null) + { + _logger.Warning(null, "The first packet from client '{0}' was no 'CONNECT' packet [MQTT-3.1.0-1].", channelAdapter.Endpoint); + return; + } + } + catch (MqttCommunicationTimedOutException) + { + _logger.Warning(null, "Client '{0}' connected but did not sent a CONNECT packet.", channelAdapter.Endpoint); return; } diff --git a/Tests/MQTTnet.Benchmarks/MqttTcpChannelBenchmark.cs b/Tests/MQTTnet.Benchmarks/MqttTcpChannelBenchmark.cs index 04761e79..ecfa76e7 100644 --- a/Tests/MQTTnet.Benchmarks/MqttTcpChannelBenchmark.cs +++ b/Tests/MQTTnet.Benchmarks/MqttTcpChannelBenchmark.cs @@ -1,11 +1,11 @@ using BenchmarkDotNet.Attributes; using MQTTnet.Channel; +using MQTTnet.Client.Options; using MQTTnet.Diagnostics; using MQTTnet.Implementations; using MQTTnet.Server; using System.Threading; using System.Threading.Tasks; -using MQTTnet.Client.Options; namespace MQTTnet.Benchmarks { @@ -20,7 +20,7 @@ namespace MQTTnet.Benchmarks public void Setup() { var factory = new MqttFactory(); - var tcpServer = new MqttTcpServerAdapter(new MqttNetLogger().CreateChildLogger()); + var tcpServer = new MqttTcpServerAdapter(new MqttNetLogger()); tcpServer.ClientHandler += args => { _serverChannel = @@ -30,7 +30,7 @@ namespace MQTTnet.Benchmarks return Task.CompletedTask; }; - + _mqttServer = factory.CreateMqttServer(new[] { tcpServer }, new MqttNetLogger()); var serverOptions = new MqttServerOptionsBuilder().Build(); diff --git a/Tests/MQTTnet.Core.Tests/ManagedMqttClient_Tests.cs b/Tests/MQTTnet.Core.Tests/ManagedMqttClient_Tests.cs index edfe0584..f8052fb5 100644 --- a/Tests/MQTTnet.Core.Tests/ManagedMqttClient_Tests.cs +++ b/Tests/MQTTnet.Core.Tests/ManagedMqttClient_Tests.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using MQTTnet.Client; using MQTTnet.Client.Connecting; using MQTTnet.Client.Options; @@ -12,6 +7,11 @@ using MQTTnet.Diagnostics; using MQTTnet.Extensions.ManagedClient; using MQTTnet.Server; using MQTTnet.Tests.Mockups; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; namespace MQTTnet.Tests { @@ -69,7 +69,7 @@ namespace MQTTnet.Tests .WithTcpServer("localhost", testEnvironment.ServerPort) .WithWillMessage(willMessage); var dyingClient = testEnvironment.CreateClient(); - var dyingManagedClient = new ManagedMqttClient(dyingClient, testEnvironment.ClientLogger.CreateChildLogger()); + var dyingManagedClient = new ManagedMqttClient(dyingClient, testEnvironment.ClientLogger); await dyingManagedClient.StartAsync(new ManagedMqttClientOptionsBuilder() .WithClientOptions(clientOptions) .Build()); @@ -96,7 +96,7 @@ namespace MQTTnet.Tests var server = await testEnvironment.StartServerAsync(); - var managedClient = new ManagedMqttClient(testEnvironment.CreateClient(), new MqttNetLogger().CreateChildLogger()); + var managedClient = new ManagedMqttClient(testEnvironment.CreateClient(), new MqttNetLogger()); var clientOptions = new MqttClientOptionsBuilder() .WithTcpServer("localhost", testEnvironment.ServerPort); @@ -110,6 +110,8 @@ namespace MQTTnet.Tests await managedClient.StopAsync(); + await Task.Delay(500); + Assert.AreEqual(0, (await server.GetClientStatusAsync()).Count); } } @@ -126,7 +128,7 @@ namespace MQTTnet.Tests var server = await testEnvironment.StartServerAsync(); - var managedClient = new ManagedMqttClient(testEnvironment.CreateClient(), new MqttNetLogger().CreateChildLogger()); + var managedClient = new ManagedMqttClient(testEnvironment.CreateClient(), new MqttNetLogger()); var clientOptions = new MqttClientOptionsBuilder() .WithTcpServer("localhost", testEnvironment.ServerPort); var storage = new ManagedMqttClientTestStorage(); @@ -349,7 +351,7 @@ namespace MQTTnet.Tests managedOptions.ConnectionCheckInterval = connectionCheckInterval ?? TimeSpan.FromSeconds(0.1); var managedClient = - new ManagedMqttClient(underlyingClient ?? testEnvironment.CreateClient(), new MqttNetLogger().CreateChildLogger()); + new ManagedMqttClient(underlyingClient ?? testEnvironment.CreateClient(), new MqttNetLogger()); var connected = GetConnectedTask(managedClient); diff --git a/Tests/MQTTnet.Core.Tests/Mockups/TestClientWrapper.cs b/Tests/MQTTnet.Core.Tests/Mockups/TestClientWrapper.cs index 103142ee..e52133c3 100644 --- a/Tests/MQTTnet.Core.Tests/Mockups/TestClientWrapper.cs +++ b/Tests/MQTTnet.Core.Tests/Mockups/TestClientWrapper.cs @@ -29,37 +29,34 @@ namespace MQTTnet.Tests.Mockups public IMqttClientOptions Options => Implementation.Options; - public IMqttClientConnectedHandler ConnectedHandler { get => Implementation.ConnectedHandler; set => Implementation.ConnectedHandler = value; } - public IMqttClientDisconnectedHandler DisconnectedHandler { get => Implementation.DisconnectedHandler; set => Implementation.DisconnectedHandler = value; } - public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler { get => Implementation.ApplicationMessageReceivedHandler; set => Implementation.ApplicationMessageReceivedHandler = value; } + public IMqttClientConnectedHandler ConnectedHandler + { + get => Implementation.ConnectedHandler; + set => Implementation.ConnectedHandler = value; + } + + public IMqttClientDisconnectedHandler DisconnectedHandler + { + get => Implementation.DisconnectedHandler; + set => Implementation.DisconnectedHandler = value; + } + + public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler + { + get => Implementation.ApplicationMessageReceivedHandler; + set => Implementation.ApplicationMessageReceivedHandler = value; + } public Task ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken) { if (TestContext != null) { - switch (options) + var clientOptions = (MqttClientOptions)options; + + var existingClientId = clientOptions.ClientId; + if (existingClientId != null && !existingClientId.StartsWith(TestContext.TestName)) { - case MqttClientOptionsBuilder builder: - { - var existingClientId = builder.Build().ClientId; - if (existingClientId != null && !existingClientId.StartsWith(TestContext.TestName)) - { - builder.WithClientId(TestContext.TestName + existingClientId); - } - - break; - } - - case MqttClientOptions op: - { - var existingClientId = op.ClientId; - if (existingClientId != null && !existingClientId.StartsWith(TestContext.TestName)) - { - op.ClientId = TestContext.TestName + existingClientId; - } - - break; - } + clientOptions.ClientId = TestContext.TestName + existingClientId; } } diff --git a/Tests/MQTTnet.Core.Tests/Mockups/TestLogger.cs b/Tests/MQTTnet.Core.Tests/Mockups/TestLogger.cs index 46471f83..e1878ed7 100644 --- a/Tests/MQTTnet.Core.Tests/Mockups/TestLogger.cs +++ b/Tests/MQTTnet.Core.Tests/Mockups/TestLogger.cs @@ -7,7 +7,7 @@ namespace MQTTnet.Tests.Mockups { public event EventHandler LogMessagePublished; - public IMqttNetLogger CreateChildLogger(string source = null) + public IMqttNetLogger CreateChildLogger(string source) { return new TestLogger(); } diff --git a/Tests/MQTTnet.Core.Tests/Mockups/TestServerWrapper.cs b/Tests/MQTTnet.Core.Tests/Mockups/TestServerWrapper.cs index 79c97393..86030e8d 100644 --- a/Tests/MQTTnet.Core.Tests/Mockups/TestServerWrapper.cs +++ b/Tests/MQTTnet.Core.Tests/Mockups/TestServerWrapper.cs @@ -22,16 +22,50 @@ namespace MQTTnet.Tests.Mockups public IMqttServer Implementation { get; } public TestContext TestContext { get; } public TestEnvironment TestEnvironment { get; } - public IMqttServerStartedHandler StartedHandler { get => Implementation.StartedHandler; set => Implementation.StartedHandler = value; } - public IMqttServerStoppedHandler StoppedHandler { get => Implementation.StoppedHandler; set => Implementation.StoppedHandler = value; } - public IMqttServerClientConnectedHandler ClientConnectedHandler { get => Implementation.ClientConnectedHandler; set => Implementation.ClientConnectedHandler = value; } - public IMqttServerClientDisconnectedHandler ClientDisconnectedHandler { get => Implementation.ClientDisconnectedHandler; set => Implementation.ClientDisconnectedHandler = value; } - public IMqttServerClientSubscribedTopicHandler ClientSubscribedTopicHandler { get => Implementation.ClientSubscribedTopicHandler; set => Implementation.ClientSubscribedTopicHandler = value; } - public IMqttServerClientUnsubscribedTopicHandler ClientUnsubscribedTopicHandler { get => Implementation.ClientUnsubscribedTopicHandler; set => Implementation.ClientUnsubscribedTopicHandler = value; } + + public IMqttServerStartedHandler StartedHandler + { + get => Implementation.StartedHandler; + set => Implementation.StartedHandler = value; + } + + public IMqttServerStoppedHandler StoppedHandler + { + get => Implementation.StoppedHandler; + set => Implementation.StoppedHandler = value; + } + + public IMqttServerClientConnectedHandler ClientConnectedHandler + { + get => Implementation.ClientConnectedHandler; + set => Implementation.ClientConnectedHandler = value; + } + + public IMqttServerClientDisconnectedHandler ClientDisconnectedHandler + { + get => Implementation.ClientDisconnectedHandler; + set => Implementation.ClientDisconnectedHandler = value; + } + + public IMqttServerClientSubscribedTopicHandler ClientSubscribedTopicHandler + { + get => Implementation.ClientSubscribedTopicHandler; + set => Implementation.ClientSubscribedTopicHandler = value; + } + + public IMqttServerClientUnsubscribedTopicHandler ClientUnsubscribedTopicHandler + { + get => Implementation.ClientUnsubscribedTopicHandler; + set => Implementation.ClientUnsubscribedTopicHandler = value; + } public IMqttServerOptions Options => Implementation.Options; - public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler { get => Implementation.ApplicationMessageReceivedHandler; set => Implementation.ApplicationMessageReceivedHandler = value; } + public IMqttApplicationMessageReceivedHandler ApplicationMessageReceivedHandler + { + get => Implementation.ApplicationMessageReceivedHandler; + set => Implementation.ApplicationMessageReceivedHandler = value; + } public Task ClearRetainedApplicationMessagesAsync() { @@ -62,26 +96,11 @@ namespace MQTTnet.Tests.Mockups { if (TestContext != null) { - switch (options) + var serverOptions = (MqttServerOptions)options; + + if (serverOptions.ConnectionValidator == null) { - case MqttServerOptionsBuilder builder: - { - if (builder.Build().ConnectionValidator == null) - { - builder.WithConnectionValidator(ConnectionValidator); - } - - break; - } - case MqttServerOptions op: - { - if (op.ConnectionValidator == null) - { - op.ConnectionValidator = new MqttServerConnectionValidatorDelegate(ConnectionValidator); - } - - break; - } + serverOptions.ConnectionValidator = new MqttServerConnectionValidatorDelegate(ConnectionValidator); } } @@ -92,7 +111,7 @@ namespace MQTTnet.Tests.Mockups { if (!ctx.ClientId.StartsWith(TestContext.TestName)) { - TestEnvironment.TrackException(new InvalidOperationException($"invalid client connected '{ctx.ClientId}'")); + TestEnvironment.TrackException(new InvalidOperationException($"Invalid client ID used ({ctx.ClientId}). It must start with UnitTest name.")); ctx.ReasonCode = Protocol.MqttConnectReasonCode.ClientIdentifierNotValid; } } diff --git a/Tests/MQTTnet.Core.Tests/MqttClient_Tests.cs b/Tests/MQTTnet.Core.Tests/MqttClient_Tests.cs index b8f4fbcb..2b86955f 100644 --- a/Tests/MQTTnet.Core.Tests/MqttClient_Tests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttClient_Tests.cs @@ -1,9 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using MQTTnet.Client; using MQTTnet.Client.Connecting; @@ -14,6 +8,12 @@ using MQTTnet.Exceptions; using MQTTnet.Protocol; using MQTTnet.Server; using MQTTnet.Tests.Mockups; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; namespace MQTTnet.Tests { @@ -29,9 +29,9 @@ namespace MQTTnet.Tests { await testEnvironment.StartServerAsync(); var client = await testEnvironment.ConnectClientAsync(); - + await client.SubscribeAsync("#"); - + var replyReceived = false; client.UseApplicationMessageReceivedHandler(c => @@ -78,7 +78,7 @@ namespace MQTTnet.Tests } }); - client2.UseApplicationMessageReceivedHandler(async c =>{ await client2.PublishAsync("reply", null, MqttQualityOfServiceLevel.AtLeastOnce); }); + client2.UseApplicationMessageReceivedHandler(async c => { await client2.PublishAsync("reply", null, MqttQualityOfServiceLevel.AtLeastOnce); }); await client1.PublishAsync("request", null, MqttQualityOfServiceLevel.AtLeastOnce); @@ -181,7 +181,7 @@ namespace MQTTnet.Tests catch { } - + SpinWait.SpinUntil(() => tries >= maxTries, 10000); Assert.AreEqual(maxTries, tries); @@ -215,7 +215,7 @@ namespace MQTTnet.Tests Assert.AreEqual((ushort)4, result.PacketIdentifier); } } - + [TestMethod] public async Task Invalid_Connect_Throws_Exception() { @@ -558,6 +558,8 @@ namespace MQTTnet.Tests clients.Add(await testEnvironment.ConnectClientAsync(new MqttClientOptionsBuilder().WithClientId("a"))); } + await Task.Delay(500); + var clientStatus = await testEnvironment.Server.GetClientStatusAsync(); var sessionStatus = await testEnvironment.Server.GetSessionStatusAsync(); @@ -565,7 +567,7 @@ namespace MQTTnet.Tests { Assert.IsFalse(clients[i].IsConnected); } - + Assert.IsTrue(clients[99].IsConnected); Assert.AreEqual(1, clientStatus.Count); @@ -583,7 +585,7 @@ namespace MQTTnet.Tests var sendClient = await testEnvironment.ConnectClientAsync(); await sendClient.PublishAsync("x", "1"); - await Task.Delay(100); + await Task.Delay(250); Assert.AreEqual("1", receivedPayload); } diff --git a/Tests/MQTTnet.Core.Tests/MqttFactory_Tests.cs b/Tests/MQTTnet.Core.Tests/MqttFactory_Tests.cs index 28f25118..d586d601 100644 --- a/Tests/MQTTnet.Core.Tests/MqttFactory_Tests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttFactory_Tests.cs @@ -15,35 +15,36 @@ namespace MQTTnet.Tests { var factory = new MqttFactory(); - //This test compares - //1. correct logID + // This test compares + // 1. correct logID var logId = "logId"; - string invalidLogId = null; + var hasInvalidLogId = false; - //2. if the total log calls are the same for global and local - var globalLogCount = 0; + // 2. if the total log calls are the same for global and local + //var globalLogCount = 0; var localLogCount = 0; var logger = new MqttNetLogger(logId); - //we have a theoretical bug here if a concurrent test is also logging - var globalLog = new EventHandler((s, e) => - { - if (logId != e.LogMessage.LogId) - { - invalidLogId = e.LogMessage.LogId; - } + // TODO: This is commented out because it is affected by other tests. + //// we have a theoretical bug here if a concurrent test is also logging + //var globalLog = new EventHandler((s, e) => + //{ + // if (e.TraceMessage.LogId != logId) + // { + // invalidLogId = e.TraceMessage.LogId; + // } - Interlocked.Increment(ref globalLogCount); - }); + // Interlocked.Increment(ref globalLogCount); + //}); - MqttNetGlobalLogger.LogMessagePublished += globalLog; + //MqttNetGlobalLogger.LogMessagePublished += globalLog; logger.LogMessagePublished += (s, e) => { - if (logId != e.LogMessage.LogId) + if (e.LogMessage.LogId != logId) { - invalidLogId = e.LogMessage.LogId; + hasInvalidLogId = true; } Interlocked.Increment(ref localLogCount); @@ -56,10 +57,10 @@ namespace MQTTnet.Tests clientOptions.WithClientOptions(o => o.WithTcpServer("this_is_an_invalid_host").WithCommunicationTimeout(TimeSpan.FromSeconds(1))); - //try connect to get some log entries + // try connect to get some log entries await managedClient.StartAsync(clientOptions.Build()); - //wait at least connect timeout or we have some log messages + // wait at least connect timeout or we have some log messages var tcs = new TaskCompletionSource(); managedClient.ConnectingFailedHandler = new ConnectingFailedHandlerDelegate(e => tcs.TrySetResult(null)); await Task.WhenAny(Task.Delay(managedClient.Options.ClientOptions.CommunicationTimeout), tcs.Task); @@ -68,12 +69,13 @@ namespace MQTTnet.Tests { await managedClient.StopAsync(); - MqttNetGlobalLogger.LogMessagePublished -= globalLog; + //MqttNetGlobalLogger.LogMessagePublished -= globalLog; } - Assert.IsNull(invalidLogId); - Assert.AreNotEqual(0, globalLogCount); - Assert.AreEqual(globalLogCount, localLogCount); + await Task.Delay(500); + + Assert.IsFalse(hasInvalidLogId); + Assert.AreNotEqual(0, localLogCount); } } } \ No newline at end of file diff --git a/Tests/MQTTnet.Core.Tests/MqttKeepAliveMonitor_Tests.cs b/Tests/MQTTnet.Core.Tests/MqttKeepAliveMonitor_Tests.cs index fe1a0c5b..73ed8466 100644 --- a/Tests/MQTTnet.Core.Tests/MqttKeepAliveMonitor_Tests.cs +++ b/Tests/MQTTnet.Core.Tests/MqttKeepAliveMonitor_Tests.cs @@ -1,12 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using MQTTnet.Adapter; using MQTTnet.Diagnostics; using MQTTnet.Server; using MQTTnet.Server.Status; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; namespace MQTTnet.Tests { @@ -23,7 +23,7 @@ namespace MQTTnet.Tests counter++; return Task.CompletedTask; }, - new MqttNetLogger().CreateChildLogger()); + new MqttNetLogger()); Assert.AreEqual(0, counter); @@ -46,7 +46,7 @@ namespace MQTTnet.Tests counter++; return Task.CompletedTask; }, - new MqttNetLogger().CreateChildLogger()); + new MqttNetLogger()); Assert.AreEqual(0, counter); diff --git a/Tests/MQTTnet.Core.Tests/MqttNetLogger_Tests.cs b/Tests/MQTTnet.Core.Tests/MqttNetLogger_Tests.cs new file mode 100644 index 00000000..760d70fa --- /dev/null +++ b/Tests/MQTTnet.Core.Tests/MqttNetLogger_Tests.cs @@ -0,0 +1,50 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MQTTnet.Diagnostics; + +namespace MQTTnet.Tests +{ + [TestClass] + public class MqttNetLogger_Tests + { + [TestMethod] + public void Root_Log_Messages() + { + var logger = new MqttNetLogger(); + + var logMessagesCount = 0; + + logger.LogMessagePublished += (s, e) => + { + logMessagesCount++; + }; + + logger.Verbose("Verbose"); + logger.Info("Info"); + logger.Warning(null, "Warning"); + logger.Error(null, "Error"); + + Assert.AreEqual(4, logMessagesCount); + } + + [TestMethod] + public void Bubbling_Log_Messages() + { + var logger = new MqttNetLogger(); + var childLogger = logger.CreateChildLogger("Source1"); + + var logMessagesCount = 0; + + logger.LogMessagePublished += (s, e) => + { + logMessagesCount++; + }; + + childLogger.Verbose("Verbose"); + childLogger.Info("Info"); + childLogger.Warning(null, "Warning"); + childLogger.Error(null, "Error"); + + Assert.AreEqual(4, logMessagesCount); + } + } +} diff --git a/Tests/MQTTnet.Core.Tests/Server_Tests.cs b/Tests/MQTTnet.Core.Tests/Server_Tests.cs index 7d81eca8..8121f410 100644 --- a/Tests/MQTTnet.Core.Tests/Server_Tests.cs +++ b/Tests/MQTTnet.Core.Tests/Server_Tests.cs @@ -1050,6 +1050,7 @@ namespace MQTTnet.Tests Assert.AreEqual("c", flow); // dc + // Connect client with same client ID. Should disconnect existing client. var c2 = await testEnvironment.ConnectClientAsync(clientOptionsBuilder); c2.UseApplicationMessageReceivedHandler(_ => @@ -1075,7 +1076,6 @@ namespace MQTTnet.Tests flow = string.Join(string.Empty, events); Assert.AreEqual("cdcr", flow); - // nothing Assert.AreEqual(false, c1.IsConnected); diff --git a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs index 94abc418..beb07ffd 100644 --- a/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs +++ b/Tests/MQTTnet.TestApp.UniversalWindows/MainPage.xaml.cs @@ -1,12 +1,4 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.ObjectModel; -using System.Text; -using System.Threading.Tasks; -using Windows.Security.Cryptography.Certificates; -using Windows.UI.Core; -using Windows.UI.Xaml; -using MQTTnet.Client; +using MQTTnet.Client; using MQTTnet.Client.Connecting; using MQTTnet.Client.Disconnecting; using MQTTnet.Client.Options; @@ -14,14 +6,22 @@ using MQTTnet.Diagnostics; using MQTTnet.Exceptions; using MQTTnet.Extensions.ManagedClient; using MQTTnet.Extensions.Rpc; +using MQTTnet.Extensions.WebSocket4Net; using MQTTnet.Formatter; using MQTTnet.Implementations; using MQTTnet.Protocol; using MQTTnet.Server; using MQTTnet.Server.Status; +using System; +using System.Collections.Concurrent; +using System.Collections.ObjectModel; +using System.Text; +using System.Threading.Tasks; +using Windows.Security.Cryptography.Certificates; +using Windows.UI.Core; +using Windows.UI.Xaml; using MqttClientConnectedEventArgs = MQTTnet.Client.Connecting.MqttClientConnectedEventArgs; using MqttClientDisconnectedEventArgs = MQTTnet.Client.Disconnecting.MqttClientDisconnectedEventArgs; -using MQTTnet.Extensions.WebSocket4Net; namespace MQTTnet.TestApp.UniversalWindows { @@ -141,7 +141,7 @@ namespace MQTTnet.TestApp.UniversalWindows Password = Encoding.UTF8.GetBytes(Password.Text) }; } - + options.CleanSession = CleanSession.IsChecked == true; options.KeepAlivePeriod = TimeSpan.FromSeconds(double.Parse(KeepAliveInterval.Text)); @@ -198,16 +198,26 @@ namespace MQTTnet.TestApp.UniversalWindows private void OnDisconnected(MqttClientDisconnectedEventArgs e) { - _traceMessages.Enqueue(new MqttNetLogMessage("", DateTime.Now, -1, - "", MqttNetLogLevel.Info, "! DISCONNECTED EVENT FIRED", null)); + _traceMessages.Enqueue(new MqttNetLogMessage + { + Timestamp = DateTime.UtcNow, + ThreadId = -1, + Level = MqttNetLogLevel.Info, + Message = "! DISCONNECTED EVENT FIRED", + }); Task.Run(UpdateLogAsync); } private void OnConnected(MqttClientConnectedEventArgs e) { - _traceMessages.Enqueue(new MqttNetLogMessage("", DateTime.Now, -1, - "", MqttNetLogLevel.Info, "! CONNECTED EVENT FIRED", null)); + _traceMessages.Enqueue(new MqttNetLogMessage + { + Timestamp = DateTime.UtcNow, + ThreadId = -1, + Level = MqttNetLogLevel.Info, + Message = "! CONNECTED EVENT FIRED", + }); Task.Run(UpdateLogAsync); } @@ -538,7 +548,7 @@ namespace MQTTnet.TestApp.UniversalWindows { //... } - + client.UseApplicationMessageReceivedHandler(e => Handler(e)); // Subscribe after connect @@ -614,7 +624,7 @@ namespace MQTTnet.TestApp.UniversalWindows }; } } - + // ---------------------------------- { var options = new MqttServerOptions();