1595 object disposed exception in unit test handle parallel connection attempts (#1610)

This commit is contained in:
Christian
2022-12-05 19:22:18 +01:00
committed by GitHub
parent bb106f8c6e
commit c17a350796
34 changed files with 802 additions and 484 deletions
+11 -13
View File
@@ -19,7 +19,6 @@ namespace MQTTnet.Client
public sealed class MqttClient : Disposable, IMqttClient
{
readonly IMqttClientAdapterFactory _adapterFactory;
readonly MqttApplicationMessageFactory _applicationMessageFactory = new MqttApplicationMessageFactory();
readonly AsyncEvent<MqttApplicationMessageReceivedEventArgs> _applicationMessageReceivedEvent = new AsyncEvent<MqttApplicationMessageReceivedEventArgs>();
readonly MqttClientPublishResultFactory _clientPublishResultFactory = new MqttClientPublishResultFactory();
@@ -32,7 +31,6 @@ namespace MQTTnet.Client
readonly object _disconnectLock = new object();
readonly AsyncEvent<InspectMqttPacketEventArgs> _inspectPacketEvent = new AsyncEvent<InspectMqttPacketEventArgs>();
readonly MqttNetSourceLogger _logger;
readonly MqttPacketFactories _packetFactories = new MqttPacketFactories();
readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider();
readonly IMqttNetLogger _rootLogger;
@@ -207,7 +205,7 @@ namespace MQTTnet.Client
if (clientWasConnected)
{
var disconnectPacket = _packetFactories.Disconnect.Create(options);
var disconnectPacket = MqttPacketFactories.Disconnect.Create(options);
await SendAsync(disconnectPacket, cancellationToken).ConfigureAwait(false);
}
}
@@ -241,7 +239,7 @@ namespace MQTTnet.Client
ThrowIfDisposed();
ThrowIfNotConnected();
var publishPacket = _packetFactories.Publish.Create(applicationMessage);
var publishPacket = MqttPacketFactories.Publish.Create(applicationMessage);
switch (applicationMessage.QualityOfServiceLevel)
{
@@ -301,7 +299,7 @@ namespace MQTTnet.Client
ThrowIfDisposed();
ThrowIfNotConnected();
var subscribePacket = _packetFactories.Subscribe.Create(options);
var subscribePacket = MqttPacketFactories.Subscribe.Create(options);
subscribePacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
var subAckPacket = await SendAndReceiveAsync<MqttSubAckPacket>(subscribePacket, cancellationToken).ConfigureAwait(false);
@@ -319,7 +317,7 @@ namespace MQTTnet.Client
ThrowIfDisposed();
ThrowIfNotConnected();
var unsubscribePacket = _packetFactories.Unsubscribe.Create(options);
var unsubscribePacket = MqttPacketFactories.Unsubscribe.Create(options);
unsubscribePacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
var unsubAckPacket = await SendAndReceiveAsync<MqttUnsubAckPacket>(unsubscribePacket, cancellationToken).ConfigureAwait(false);
@@ -347,7 +345,7 @@ namespace MQTTnet.Client
{
if (!eventArgs.ProcessingFailed)
{
var pubAckPacket = _packetFactories.PubAck.Create(eventArgs);
var pubAckPacket = MqttPacketFactories.PubAck.Create(eventArgs);
return SendAsync(pubAckPacket, cancellationToken);
}
}
@@ -355,7 +353,7 @@ namespace MQTTnet.Client
{
if (!eventArgs.ProcessingFailed)
{
var pubRecPacket = _packetFactories.PubRec.Create(eventArgs);
var pubRecPacket = MqttPacketFactories.PubRec.Create(eventArgs);
return SendAsync(pubRecPacket, cancellationToken);
}
}
@@ -373,7 +371,7 @@ namespace MQTTnet.Client
try
{
var connectPacket = _packetFactories.Connect.Create(options);
var connectPacket = MqttPacketFactories.Connect.Create(options);
var connAckPacket = await SendAndReceiveAsync<MqttConnAckPacket>(connectPacket, cancellationToken).ConfigureAwait(false);
@@ -535,7 +533,7 @@ namespace MQTTnet.Client
async Task<MqttApplicationMessageReceivedEventArgs> HandleReceivedApplicationMessageAsync(MqttPublishPacket publishPacket)
{
var applicationMessage = _applicationMessageFactory.Create(publishPacket);
var applicationMessage = MqttApplicationMessageFactory.Create(publishPacket);
var eventArgs = new MqttApplicationMessageReceivedEventArgs(Options.ClientId, applicationMessage, publishPacket, AcknowledgeReceivedPublishPacket);
await _applicationMessageReceivedEvent.InvokeAsync(eventArgs).ConfigureAwait(false);
@@ -601,7 +599,7 @@ namespace MQTTnet.Client
{
// The packet is unknown. Probably due to a restart of the client.
// So wen send this to the server to trigger a full resend of the message.
var pubRelPacket = _packetFactories.PubRel.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.PacketIdentifierNotFound);
var pubRelPacket = MqttPacketFactories.PubRel.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.PacketIdentifierNotFound);
return SendAsync(pubRelPacket, cancellationToken);
}
@@ -610,7 +608,7 @@ namespace MQTTnet.Client
Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
{
var pubCompPacket = _packetFactories.PubComp.Create(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubCompPacket = MqttPacketFactories.PubComp.Create(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
return SendAsync(pubCompPacket, cancellationToken);
}
@@ -637,7 +635,7 @@ namespace MQTTnet.Client
var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket, cancellationToken).ConfigureAwait(false);
var pubRelPacket = _packetFactories.PubRel.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubRelPacket = MqttPacketFactories.PubRel.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubCompPacket = await SendAndReceiveAsync<MqttPubCompPacket>(pubRelPacket, cancellationToken).ConfigureAwait(false);
@@ -6,17 +6,100 @@ using System;
namespace MQTTnet.Diagnostics
{
/*
* The logger uses generic parameters in order to avoid boxing of parameter values like integers etc.
*/
public static class MqttNetSourceLoggerExtensions
{
/*
* The logger uses generic parameters in order to avoid boxing of parameter values like integers etc.
*/
public static MqttNetSourceLogger WithSource(this IMqttNetLogger logger, string source)
public static void Error<TParameter1>(this MqttNetSourceLogger logger, Exception exception, string message, TParameter1 parameter1)
{
if (logger == null) throw new ArgumentNullException(nameof(logger));
if (!logger.IsEnabled)
{
return;
}
return new MqttNetSourceLogger(logger, source);
logger.Publish(MqttNetLogLevel.Error, message, new object[] { parameter1 }, exception);
}
public static void Error<TParameter1, TParameter2>(this MqttNetSourceLogger logger, Exception exception, string message, TParameter1 parameter1, TParameter2 parameter2)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Error, message, new object[] { parameter1, parameter2 }, exception);
}
public static void Error(this MqttNetSourceLogger logger, Exception exception, string message)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Error, message, null, exception);
}
public static void Error(this MqttNetSourceLogger logger, string message)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Error, message, null, null);
}
public static void Info<TParameter1>(this MqttNetSourceLogger logger, string message, TParameter1 parameter1)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Info, message, new object[] { parameter1 }, null);
}
public static void Info<TParameter1, TParameter2>(this MqttNetSourceLogger logger, string message, TParameter1 parameter1, TParameter2 parameter2)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Info, message, new object[] { parameter1, parameter2 }, null);
}
public static void Info(this MqttNetSourceLogger logger, string message)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Info, message, null, null);
}
public static void Publish<TParameter1>(this MqttNetSourceLogger logger, MqttNetLogLevel logLevel, Exception exception, string message, TParameter1 parameter1)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(logLevel, message, new object[] { parameter1 }, exception);
}
public static void Publish<TParameter1, TParameter2>(this MqttNetSourceLogger logger, MqttNetLogLevel logLevel, Exception exception, string message, TParameter1 parameter1, TParameter2 parameter2)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(logLevel, message, new object[] { parameter1, parameter2 }, exception);
}
public static void Verbose<TParameter1>(this MqttNetSourceLogger logger, string message, TParameter1 parameter1)
@@ -26,7 +109,7 @@ namespace MQTTnet.Diagnostics
return;
}
logger.Publish(MqttNetLogLevel.Verbose, message, new object[] {parameter1}, null);
logger.Publish(MqttNetLogLevel.Verbose, message, new object[] { parameter1 }, null);
}
public static void Verbose<TParameter1, TParameter2>(this MqttNetSourceLogger logger, string message, TParameter1 parameter1, TParameter2 parameter2)
@@ -36,10 +119,14 @@ namespace MQTTnet.Diagnostics
return;
}
logger.Publish(MqttNetLogLevel.Verbose, message, new object[] {parameter1, parameter2}, null);
logger.Publish(MqttNetLogLevel.Verbose, message, new object[] { parameter1, parameter2 }, null);
}
public static void Verbose<TParameter1, TParameter2, TParameter3>(this MqttNetSourceLogger logger, string message, TParameter1 parameter1, TParameter2 parameter2,
public static void Verbose<TParameter1, TParameter2, TParameter3>(
this MqttNetSourceLogger logger,
string message,
TParameter1 parameter1,
TParameter2 parameter2,
TParameter3 parameter3)
{
if (!logger.IsEnabled)
@@ -47,7 +134,7 @@ namespace MQTTnet.Diagnostics
return;
}
logger.Publish(MqttNetLogLevel.Verbose, message, new object[] {parameter1, parameter2, parameter3}, null);
logger.Publish(MqttNetLogLevel.Verbose, message, new object[] { parameter1, parameter2, parameter3 }, null);
}
public static void Verbose(this MqttNetSourceLogger logger, string message)
@@ -60,134 +147,74 @@ namespace MQTTnet.Diagnostics
logger.Publish(MqttNetLogLevel.Verbose, message, null, null);
}
public static void Info<TParameter1>(this MqttNetSourceLogger logger, string message, TParameter1 parameter1)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Info, message, new object[] {parameter1}, null);
}
public static void Info<TParameter1, TParameter2>(this MqttNetSourceLogger logger, string message, TParameter1 parameter1, TParameter2 parameter2)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Info, message, new object[] {parameter1, parameter2}, null);
}
public static void Info(this MqttNetSourceLogger logger, string message)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Info, message, null, null);
}
public static void Warning<TParameter1>(this MqttNetSourceLogger logger, Exception exception, string message, TParameter1 parameter1)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Warning, message, new object[] {parameter1}, exception);
logger.Publish(MqttNetLogLevel.Warning, message, new object[] { parameter1 }, exception);
}
public static void Warning<TParameter1, TParameter2>(this MqttNetSourceLogger logger, Exception exception, string message, TParameter1 parameter1, TParameter2 parameter2)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Warning, message, new object[] {parameter1, parameter2}, exception);
logger.Publish(MqttNetLogLevel.Warning, message, new object[] { parameter1, parameter2 }, exception);
}
public static void Warning(this MqttNetSourceLogger logger, Exception exception, string message)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Warning, message, null, exception);
}
public static void Warning<TParameter1>(this MqttNetSourceLogger logger, string message, TParameter1 parameter1)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Warning, message, new object[] {parameter1}, null);
logger.Publish(MqttNetLogLevel.Warning, message, new object[] { parameter1 }, null);
}
public static void Warning<TParameter1, TParameter2>(this MqttNetSourceLogger logger, string message, TParameter1 parameter1, TParameter2 parameter2)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Warning, message, new object[] {parameter1, parameter2}, null);
logger.Publish(MqttNetLogLevel.Warning, message, new object[] { parameter1, parameter2 }, null);
}
public static void Warning(this MqttNetSourceLogger logger, string message)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Warning, message, null, null);
}
public static void Error<TParameter1>(this MqttNetSourceLogger logger, Exception exception, string message, TParameter1 parameter1)
public static MqttNetSourceLogger WithSource(this IMqttNetLogger logger, string source)
{
if (!logger.IsEnabled)
if (logger == null)
{
return;
throw new ArgumentNullException(nameof(logger));
}
logger.Publish(MqttNetLogLevel.Error, message, new object[] {parameter1}, exception);
}
public static void Error<TParameter1, TParameter2>(this MqttNetSourceLogger logger, Exception exception, string message, TParameter1 parameter1, TParameter2 parameter2)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Error, message, new object[] {parameter1, parameter2}, exception);
}
public static void Error(this MqttNetSourceLogger logger, Exception exception, string message)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Error, message, null, exception);
}
public static void Error(this MqttNetSourceLogger logger, string message)
{
if (!logger.IsEnabled)
{
return;
}
logger.Publish(MqttNetLogLevel.Error, message, null, null);
return new MqttNetSourceLogger(logger, source);
}
}
}
@@ -7,9 +7,9 @@ using MQTTnet.Packets;
namespace MQTTnet.Formatter
{
public sealed class MqttApplicationMessageFactory
public static class MqttApplicationMessageFactory
{
public MqttApplicationMessage Create(MqttPublishPacket publishPacket)
public static MqttApplicationMessage Create(MqttPublishPacket publishPacket)
{
if (publishPacket == null)
{
+13 -13
View File
@@ -4,30 +4,30 @@
namespace MQTTnet.Formatter
{
public sealed class MqttPacketFactories
public static class MqttPacketFactories
{
public MqttConnAckPacketFactory ConnAck { get; } = new MqttConnAckPacketFactory();
public static MqttConnAckPacketFactory ConnAck { get; } = new MqttConnAckPacketFactory();
public MqttConnectPacketFactory Connect { get; } = new MqttConnectPacketFactory();
public static MqttConnectPacketFactory Connect { get; } = new MqttConnectPacketFactory();
public MqttDisconnectPacketFactory Disconnect { get; } = new MqttDisconnectPacketFactory();
public static MqttDisconnectPacketFactory Disconnect { get; } = new MqttDisconnectPacketFactory();
public MqttPubAckPacketFactory PubAck { get; } = new MqttPubAckPacketFactory();
public static MqttPubAckPacketFactory PubAck { get; } = new MqttPubAckPacketFactory();
public MqttPubCompPacketFactory PubComp { get; } = new MqttPubCompPacketFactory();
public static MqttPubCompPacketFactory PubComp { get; } = new MqttPubCompPacketFactory();
public MqttPublishPacketFactory Publish { get; } = new MqttPublishPacketFactory();
public static MqttPublishPacketFactory Publish { get; } = new MqttPublishPacketFactory();
public MqttPubRecPacketFactory PubRec { get; } = new MqttPubRecPacketFactory();
public static MqttPubRecPacketFactory PubRec { get; } = new MqttPubRecPacketFactory();
public MqttPubRelPacketFactory PubRel { get; } = new MqttPubRelPacketFactory();
public static MqttPubRelPacketFactory PubRel { get; } = new MqttPubRelPacketFactory();
public MqttSubAckPacketFactory SubAck { get; } = new MqttSubAckPacketFactory();
public static MqttSubAckPacketFactory SubAck { get; } = new MqttSubAckPacketFactory();
public MqttSubscribePacketFactory Subscribe { get; } = new MqttSubscribePacketFactory();
public static MqttSubscribePacketFactory Subscribe { get; } = new MqttSubscribePacketFactory();
public MqttUnsubAckPacketFactory UnsubAck { get; } = new MqttUnsubAckPacketFactory();
public static MqttUnsubAckPacketFactory UnsubAck { get; } = new MqttUnsubAckPacketFactory();
public MqttUnsubscribePacketFactory Unsubscribe { get; } = new MqttUnsubscribePacketFactory();
public static MqttUnsubscribePacketFactory Unsubscribe { get; } = new MqttUnsubscribePacketFactory();
}
}
@@ -78,7 +78,7 @@ namespace MQTTnet.Formatter.V3
return DecodeSubscribePacket(receivedMqttPacket.Body);
case MqttControlPacketType.SubAck:
return DecodeSubAckPacket(receivedMqttPacket.Body);
case MqttControlPacketType.Unsubscibe:
case MqttControlPacketType.Unsubscribe:
return DecodeUnsubscribePacket(receivedMqttPacket.Body);
case MqttControlPacketType.UnsubAck:
return DecodeUnsubAckPacket(receivedMqttPacket.Body);
@@ -783,7 +783,7 @@ namespace MQTTnet.Formatter.V3
}
}
return MqttBufferWriter.BuildFixedHeader(MqttControlPacketType.Unsubscibe, 0x02);
return MqttBufferWriter.BuildFixedHeader(MqttControlPacketType.Unsubscribe, 0x02);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -54,7 +54,7 @@ namespace MQTTnet.Formatter.V5
return DecodeSubscribePacket(receivedMqttPacket.Body);
case MqttControlPacketType.SubAck:
return DecodeSubAckPacket(receivedMqttPacket.Body);
case MqttControlPacketType.Unsubscibe:
case MqttControlPacketType.Unsubscribe:
return DecodeUnsubscribePacket(receivedMqttPacket.Body);
case MqttControlPacketType.UnsubAck:
return DecodeUnsubAckPacket(receivedMqttPacket.Body);
@@ -524,7 +524,7 @@ namespace MQTTnet.Formatter.V5
_bufferWriter.WriteString(topicFilter);
}
return MqttBufferWriter.BuildFixedHeader(MqttControlPacketType.Unsubscibe, 0x02);
return MqttBufferWriter.BuildFixedHeader(MqttControlPacketType.Unsubscribe, 0x02);
}
static void ThrowIfPacketIdentifierIsInvalid(ushort packetIdentifier, MqttPacket packet)
@@ -0,0 +1,37 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading;
namespace MQTTnet.Internal
{
public static class CancellationTokenSourceExtensions
{
public static bool TryCancel(this CancellationTokenSource cancellationTokenSource, bool throwOnFirstException = false)
{
if (cancellationTokenSource == null)
{
return false;
}
try
{
// Checking the _IsCancellationRequested_ here will not throw an
// "ObjectDisposedException" as the getter of the property "Token" will do!
if (cancellationTokenSource.IsCancellationRequested)
{
return false;
}
cancellationTokenSource.Cancel(throwOnFirstException);
return true;
}
catch (ObjectDisposedException)
{
return false;
}
}
}
}
@@ -0,0 +1,102 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace MQTTnet.Packets
{
public static class MqttPacketExtensions
{
public static string GetRfcName(this MqttPacket packet)
{
if (packet == null)
{
throw new ArgumentNullException(nameof(packet));
}
switch (packet)
{
case MqttConnectPacket _:
{
return "CONNECT";
}
case MqttConnAckPacket _:
{
return "CONNACK";
}
case MqttAuthPacket _:
{
return "AUTH";
}
case MqttDisconnectPacket _:
{
return "DISCONNECT";
}
case MqttPingReqPacket _:
{
return "PINGREQ";
}
case MqttPingRespPacket _:
{
return "PINGRESP";
}
case MqttSubscribePacket _:
{
return "SUBSCRIBE";
}
case MqttSubAckPacket _:
{
return "SUBACK";
}
case MqttUnsubscribePacket _:
{
return "UNSUBSCRIBE";
}
case MqttUnsubAckPacket _:
{
return "UNSUBACK";
}
case MqttPublishPacket _:
{
return "PUBLISH";
}
case MqttPubAckPacket _:
{
return "PUBACK";
}
case MqttPubRelPacket _:
{
return "PUBREL";
}
case MqttPubRecPacket _:
{
return "PUBREC";
}
case MqttPubCompPacket _:
{
return "PUBCOMP";
}
default:
{
return packet.GetType().Name;
}
}
}
}
}
@@ -15,7 +15,7 @@ namespace MQTTnet.Protocol
PubComp = 7,
Subscribe = 8,
SubAck = 9,
Unsubscibe = 10,
Unsubscribe = 10,
UnsubAck = 11,
PingReq = 12,
PingResp = 13,
+86 -82
View File
@@ -12,27 +12,21 @@ using MQTTnet.Diagnostics;
using MQTTnet.Exceptions;
using MQTTnet.Formatter;
using MQTTnet.Internal;
using MQTTnet.PacketDispatcher;
using MQTTnet.Packets;
using MQTTnet.Protocol;
namespace MQTTnet.Server
{
public sealed class MqttClient
public sealed class MqttClient : IDisposable
{
readonly MqttApplicationMessageFactory _applicationMessageFactory = new MqttApplicationMessageFactory();
readonly MqttConnectPacket _connectPacket;
readonly MqttServerEventContainer _eventContainer;
readonly MqttNetSourceLogger _logger;
readonly MqttPacketDispatcher _packetDispatcher = new MqttPacketDispatcher();
readonly MqttPacketFactories _packetFactories = new MqttPacketFactories();
readonly MqttServerOptions _serverOptions;
readonly MqttClientSessionsManager _sessionsManager;
readonly Dictionary<ushort, string> _topicAlias = new Dictionary<ushort, string>();
CancellationTokenSource _cancellationToken;
CancellationTokenSource _cancellationToken = new CancellationTokenSource();
bool _disconnectPacketSent;
public MqttClient(
@@ -45,14 +39,13 @@ namespace MQTTnet.Server
IMqttNetLogger logger)
{
_serverOptions = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions));
_eventContainer = eventContainer;
_eventContainer = eventContainer ?? throw new ArgumentNullException(nameof(eventContainer));
_sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager));
_connectPacket = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket));
ChannelAdapter = channelAdapter ?? throw new ArgumentNullException(nameof(channelAdapter));
Endpoint = channelAdapter.Endpoint;
Session = session ?? throw new ArgumentNullException(nameof(session));
_connectPacket = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket));
if (logger == null)
{
@@ -80,6 +73,11 @@ namespace MQTTnet.Server
public MqttClientStatistics Statistics { get; } = new MqttClientStatistics();
public void Dispose()
{
_cancellationToken?.Dispose();
}
public void ResetStatistics()
{
ChannelAdapter.ResetStatistics();
@@ -88,46 +86,43 @@ namespace MQTTnet.Server
public async Task RunAsync()
{
_logger.Info("Client '{0}': Session started.", Id);
_logger.Info("Client '{0}': Session started", Id);
Session.LatestConnectPacket = _connectPacket;
Session.WillMessageSent = false;
using (_cancellationToken = new CancellationTokenSource())
try
{
var cancellationToken = _cancellationToken.Token;
try
{
_ = Task.Factory.StartNew(() => SendPacketsLoop(cancellationToken), cancellationToken, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false);
_ = Task.Factory.StartNew(() => SendPacketsLoop(cancellationToken), cancellationToken, TaskCreationOptions.PreferFairness, TaskScheduler.Default)
.ConfigureAwait(false);
IsRunning = true;
IsRunning = true;
await ReceivePackagesLoop(cancellationToken).ConfigureAwait(false);
}
finally
{
IsRunning = false;
_cancellationToken?.Cancel();
_cancellationToken = null;
}
await ReceivePackagesLoop(cancellationToken).ConfigureAwait(false);
}
finally
{
IsRunning = false;
_packetDispatcher.CancelAll();
_cancellationToken?.TryCancel();
_cancellationToken?.Dispose();
_cancellationToken = null;
}
if (!IsTakenOver && !IsCleanDisconnect && Session.LatestConnectPacket.WillFlag && !Session.WillMessageSent)
{
var willPublishPacket = _packetFactories.Publish.Create(Session.LatestConnectPacket);
var willApplicationMessage = _applicationMessageFactory.Create(willPublishPacket);
var willPublishPacket = MqttPacketFactories.Publish.Create(Session.LatestConnectPacket);
var willApplicationMessage = MqttApplicationMessageFactory.Create(willPublishPacket);
_ = _sessionsManager.DispatchApplicationMessage(Id, willApplicationMessage);
Session.WillMessageSent = true;
_logger.Info("Client '{0}': Published will message.", Id);
_logger.Info("Client '{0}': Published will message", Id);
}
_logger.Info("Client '{0}': Connection stopped.", Id);
_logger.Info("Client '{0}': Connection stopped", Id);
}
public async Task SendPacketAsync(MqttPacket packet, CancellationToken cancellationToken)
@@ -181,6 +176,12 @@ namespace MQTTnet.Server
return CompletedTask.Instance;
}
void HandleIncomingPingReqPacket()
{
// See: The Server MUST send a PINGRESP packet in response to a PINGREQ packet [MQTT-3.12.4-1].
Session.EnqueueHealthPacket(new MqttPacketBusItem(MqttPingRespPacket.Instance));
}
Task HandleIncomingPubAckPacket(MqttPubAckPacket pubAckPacket)
{
var acknowledgedPublishPacket = Session.AcknowledgePublishPacket(pubAckPacket.PacketIdentifier);
@@ -210,7 +211,7 @@ namespace MQTTnet.Server
HandleTopicAlias(publishPacket);
InterceptingPublishEventArgs interceptingPublishEventArgs = null;
var applicationMessage = _applicationMessageFactory.Create(publishPacket);
var applicationMessage = MqttApplicationMessageFactory.Create(publishPacket);
var closeConnection = false;
var processPublish = true;
@@ -253,19 +254,19 @@ namespace MQTTnet.Server
}
case MqttQualityOfServiceLevel.AtLeastOnce:
{
var pubAckPacket = _packetFactories.PubAck.Create(publishPacket, interceptingPublishEventArgs, dispatchResult);
var pubAckPacket = MqttPacketFactories.PubAck.Create(publishPacket, interceptingPublishEventArgs, dispatchResult);
Session.EnqueueControlPacket(new MqttPacketBusItem(pubAckPacket));
break;
}
case MqttQualityOfServiceLevel.ExactlyOnce:
{
var pubRecPacket = _packetFactories.PubRec.Create(publishPacket, interceptingPublishEventArgs, dispatchResult);
var pubRecPacket = MqttPacketFactories.PubRec.Create(publishPacket, interceptingPublishEventArgs, dispatchResult);
Session.EnqueueControlPacket(new MqttPacketBusItem(pubRecPacket));
break;
}
default:
{
throw new MqttCommunicationException("Received a not supported QoS level.");
throw new MqttCommunicationException("Received a not supported QoS level");
}
}
}
@@ -274,7 +275,7 @@ namespace MQTTnet.Server
{
// Do not fire the event _ClientAcknowledgedPublishPacket_ here because the QoS 2 process is only finished
// properly when the client has sent the PUBCOMP packet.
var pubRelPacket = _packetFactories.PubRel.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubRelPacket = MqttPacketFactories.PubRel.Create(pubRecPacket, MqttApplicationMessageReceivedReasonCode.Success);
Session.EnqueueControlPacket(new MqttPacketBusItem(pubRelPacket));
return CompletedTask.Instance;
@@ -282,7 +283,7 @@ namespace MQTTnet.Server
void HandleIncomingPubRelPacket(MqttPubRelPacket pubRelPacket)
{
var pubCompPacket = _packetFactories.PubComp.Create(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
var pubCompPacket = MqttPacketFactories.PubComp.Create(pubRelPacket, MqttApplicationMessageReceivedReasonCode.Success);
Session.EnqueueControlPacket(new MqttPacketBusItem(pubCompPacket));
}
@@ -290,7 +291,7 @@ namespace MQTTnet.Server
{
var subscribeResult = await Session.Subscribe(subscribePacket, cancellationToken).ConfigureAwait(false);
var subAckPacket = _packetFactories.SubAck.Create(subscribePacket, subscribeResult);
var subAckPacket = MqttPacketFactories.SubAck.Create(subscribePacket, subscribeResult);
Session.EnqueueControlPacket(new MqttPacketBusItem(subAckPacket));
@@ -304,7 +305,7 @@ namespace MQTTnet.Server
{
foreach (var retainedMessageMatch in subscribeResult.RetainedMessages)
{
var publishPacket = _packetFactories.Publish.Create(retainedMessageMatch);
var publishPacket = MqttPacketFactories.Publish.Create(retainedMessageMatch);
Session.EnqueueDataPacket(new MqttPacketBusItem(publishPacket));
}
}
@@ -314,7 +315,7 @@ namespace MQTTnet.Server
{
var unsubscribeResult = await Session.Unsubscribe(unsubscribePacket, cancellationToken).ConfigureAwait(false);
var unsubAckPacket = _packetFactories.UnsubAck.Create(unsubscribePacket, unsubscribeResult);
var unsubAckPacket = MqttPacketFactories.UnsubAck.Create(unsubscribePacket, unsubscribeResult);
Session.EnqueueControlPacket(new MqttPacketBusItem(unsubAckPacket));
@@ -345,7 +346,7 @@ namespace MQTTnet.Server
}
else
{
_logger.Warning("Client '{0}': Received invalid topic alias ({1}).", Id, publishPacket.TopicAlias);
_logger.Warning("Client '{0}': Received invalid topic alias ({1})", Id, publishPacket.TopicAlias);
}
}
}
@@ -371,6 +372,7 @@ namespace MQTTnet.Server
async Task ReceivePackagesLoop(CancellationToken cancellationToken)
{
MqttPacket currentPacket = null;
try
{
// We do not listen for the cancellation token here because the internal buffer might still
@@ -380,12 +382,12 @@ namespace MQTTnet.Server
{
await Task.Yield();
var packet = await ChannelAdapter.ReceivePacketAsync(cancellationToken).ConfigureAwait(false);
if (packet == null)
currentPacket = await ChannelAdapter.ReceivePacketAsync(cancellationToken).ConfigureAwait(false);
if (currentPacket == null)
{
return;
}
// Check for cancellation again because receive packet might block some time.
if (cancellationToken.IsCancellationRequested)
{
@@ -398,73 +400,69 @@ namespace MQTTnet.Server
{
return;
}
var processPacket = true;
if (_eventContainer.InterceptingInboundPacketEvent.HasHandlers)
{
var interceptingPacketEventArgs = new InterceptingPacketEventArgs(cancellationToken, Id, Endpoint, packet, Session.Items);
var interceptingPacketEventArgs = new InterceptingPacketEventArgs(cancellationToken, Id, Endpoint, currentPacket, Session.Items);
await _eventContainer.InterceptingInboundPacketEvent.InvokeAsync(interceptingPacketEventArgs).ConfigureAwait(false);
packet = interceptingPacketEventArgs.Packet;
currentPacket = interceptingPacketEventArgs.Packet;
processPacket = interceptingPacketEventArgs.ProcessPacket;
}
if (!processPacket || packet == null)
if (!processPacket || currentPacket == null)
{
// Restart the receiving process to get the next packet ignoring the current one..
continue;
}
Statistics.HandleReceivedPacket(packet);
Statistics.HandleReceivedPacket(currentPacket);
if (packet is MqttPublishPacket publishPacket)
if (currentPacket is MqttPublishPacket publishPacket)
{
await HandleIncomingPublishPacket(publishPacket, cancellationToken).ConfigureAwait(false);
}
else if (packet is MqttPubAckPacket pubAckPacket)
else if (currentPacket is MqttPubAckPacket pubAckPacket)
{
await HandleIncomingPubAckPacket(pubAckPacket).ConfigureAwait(false);
}
else if (packet is MqttPubCompPacket pubCompPacket)
else if (currentPacket is MqttPubCompPacket pubCompPacket)
{
await HandleIncomingPubCompPacket(pubCompPacket).ConfigureAwait(false);
}
else if (packet is MqttPubRecPacket pubRecPacket)
else if (currentPacket is MqttPubRecPacket pubRecPacket)
{
await HandleIncomingPubRecPacket(pubRecPacket).ConfigureAwait(false);
}
else if (packet is MqttPubRelPacket pubRelPacket)
else if (currentPacket is MqttPubRelPacket pubRelPacket)
{
HandleIncomingPubRelPacket(pubRelPacket);
}
else if (packet is MqttSubscribePacket subscribePacket)
else if (currentPacket is MqttSubscribePacket subscribePacket)
{
await HandleIncomingSubscribePacket(subscribePacket, cancellationToken).ConfigureAwait(false);
}
else if (packet is MqttUnsubscribePacket unsubscribePacket)
else if (currentPacket is MqttUnsubscribePacket unsubscribePacket)
{
await HandleIncomingUnsubscribePacket(unsubscribePacket, cancellationToken).ConfigureAwait(false);
}
else if (packet is MqttPingReqPacket)
else if (currentPacket is MqttPingReqPacket)
{
// See: The Server MUST send a PINGRESP packet in response to a PINGREQ packet [MQTT-3.12.4-1].
Session.EnqueueHealthPacket(new MqttPacketBusItem(MqttPingRespPacket.Instance));
HandleIncomingPingReqPacket();
}
else if (packet is MqttPingRespPacket)
else if (currentPacket is MqttPingRespPacket)
{
throw new MqttProtocolViolationException("A PINGRESP Packet is sent by the Server to the Client in response to a PINGREQ Packet only.");
}
else if (packet is MqttDisconnectPacket)
else if (currentPacket is MqttDisconnectPacket)
{
IsCleanDisconnect = true;
return;
}
else
{
if (!_packetDispatcher.TryDispatch(packet))
{
throw new MqttProtocolViolationException($"Received packet '{packet}' at an unexpected time.");
}
throw new MqttProtocolViolationException("Packet not allowed");
}
}
}
@@ -475,11 +473,25 @@ namespace MQTTnet.Server
{
if (exception is MqttCommunicationException)
{
_logger.Warning(exception, "Client '{0}': Communication exception while receiving client packets.", Id);
_logger.Warning(exception, "Client '{0}': Communication exception while receiving packets", Id);
return;
}
var logLevel = MqttNetLogLevel.Error;
if (!IsRunning)
{
// There was an exception but the connection is already closed. So there is no chance to send a response to the client etc.
logLevel = MqttNetLogLevel.Warning;
}
if (currentPacket == null)
{
_logger.Publish(logLevel, exception, "Client '{0}': Error while receiving packets", Id);
}
else
{
_logger.Error(exception, "Client '{0}': Error while receiving client packets.", Id);
_logger.Publish(logLevel, exception, "Client '{0}': Error while processing {1} packet", Id, currentPacket.GetRfcName());
}
}
}
@@ -531,15 +543,15 @@ namespace MQTTnet.Server
{
if (exception is MqttCommunicationTimedOutException)
{
_logger.Warning(exception, "Client '{0}': Sending publish packet failed: Timeout.", Id);
_logger.Warning(exception, "Client '{0}': Sending PUBLISH packet failed due to timeout", Id);
}
else if (exception is MqttCommunicationException)
{
_logger.Warning(exception, "Client '{0}': Sending publish packet failed: Communication exception.", Id);
_logger.Warning(exception, "Client '{0}': Sending PUBLISH packet failed due to communication exception", Id);
}
else
{
_logger.Error(exception, "Client '{0}': Sending publish packet failed.", Id);
_logger.Error(exception, "Client '{0}': Sending PUBLISH packet failed", Id);
}
if (packetBusItem?.Packet is MqttPublishPacket publishPacket)
@@ -557,15 +569,7 @@ namespace MQTTnet.Server
void StopInternal()
{
try
{
_cancellationToken?.Cancel();
}
catch (ObjectDisposedException)
{
// This can happen when connections are created and dropped very quickly.
// It is not an issue if the cancellation token cannot be canceled multiple times.
}
_cancellationToken?.TryCancel();
}
async Task TrySendDisconnectPacket(MqttDisconnectReasonCode reasonCode)
@@ -574,8 +578,8 @@ namespace MQTTnet.Server
{
// This also indicates that it was tried at least!
_disconnectPacketSent = true;
var disconnectPacket = _packetFactories.Disconnect.Create(reasonCode);
var disconnectPacket = MqttPacketFactories.Disconnect.Create(reasonCode);
using (var timeout = new CancellationTokenSource(_serverOptions.DefaultCommunicationTimeout))
{
@@ -584,7 +588,7 @@ namespace MQTTnet.Server
}
catch (Exception exception)
{
_logger.Warning(exception, "Client '{0}': Error while sending DISCONNECT packet (ReasonCode = {1}).", Id, reasonCode);
_logger.Warning(exception, "Client '{0}': Error while sending DISCONNECT packet (ReasonCode = {1})", Id, reasonCode);
}
}
}
@@ -28,7 +28,6 @@ namespace MQTTnet.Server
readonly MqttServerEventContainer _eventContainer;
readonly MqttNetSourceLogger _logger;
readonly MqttServerOptions _options;
readonly MqttPacketFactories _packetFactories = new MqttPacketFactories();
readonly MqttRetainedMessagesManager _retainedMessagesManager;
readonly IMqttNetLogger _rootLogger;
@@ -166,7 +165,7 @@ namespace MQTTnet.Server
continue;
}
var newPublishPacket = _packetFactories.Publish.Create(applicationMessage);
var newPublishPacket = MqttPacketFactories.Publish.Create(applicationMessage);
newPublishPacket.QualityOfServiceLevel = checkSubscriptionsResult.QualityOfServiceLevel;
newPublishPacket.SubscriptionIdentifiers = checkSubscriptionsResult.SubscriptionIdentifiers;
@@ -288,7 +287,7 @@ namespace MQTTnet.Server
}
var validatingConnectionEventArgs = await ValidateConnection(connectPacket, channelAdapter).ConfigureAwait(false);
var connAckPacket = _packetFactories.ConnAck.Create(validatingConnectionEventArgs);
var connAckPacket = MqttPacketFactories.ConnAck.Create(validatingConnectionEventArgs);
if (validatingConnectionEventArgs.ReasonCode != MqttConnectReasonCode.Success)
{
@@ -430,7 +429,7 @@ namespace MQTTnet.Server
{
foreach (var retainedMessageMatch in subscribeResult.RetainedMessages)
{
var publishPacket = _packetFactories.Publish.Create(retainedMessageMatch);
var publishPacket = MqttPacketFactories.Publish.Create(retainedMessageMatch);
clientSession.EnqueueDataPacket(new MqttPacketBusItem(publishPacket));
}
}