rethrow MqttClientUnexpectedDisconnectReceivedException when Publish … (#1974)

* rethrow MqttClientUnexpectedDisconnectReceivedException when Publish errors out because server disconnects the client and QoS is 0

* use a local var to cache _unexpectedDisconnectPacket

* Add inner exception to new exception

* Update release notes

* set the default inner exception as null

---------

Co-authored-by: christian <6939810+chkr1011@users.noreply.github.com>
This commit is contained in:
fazho
2024-05-07 18:31:16 +02:00
committed by GitHub
co-authored by christian
parent 4f9e54ba1d
commit abbf14b1ec
3 changed files with 38 additions and 14 deletions
+1
View File
@@ -1,6 +1,7 @@
* [Core] Optimized packet serialization of PUBACK and PUBREC packets for protocol version 5.0.0 (#1939, thanks to @Y-Sindo).
* [Core] The package inspector is now fully async (#1941).
* [Client] Added a dedicated exception when the client is not connected (#1954, thanks to @marcpiulachs).
* [Client] The client will now throw a _MqttClientUnexpectedDisconnectReceivedException_ when publishing a QoS 0 message which leads to a server disconnect (BREAKING CHANGE!, #1974, thanks to @fazho).
* [Client] Exposed the certificate selection event handler in client options (#1984).
* [Server] The server will no longer send _NoMatchingSubscribers_ when the actual subscription was non success (#1965, BREAKING CHANGE!).
* [Server] Fixed broken support for _null_ in _AddServer_ method in ASP.NET integration (#1981).
@@ -2,6 +2,7 @@
// 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.Collections.Generic;
using MQTTnet.Exceptions;
using MQTTnet.Packets;
@@ -11,8 +12,9 @@ namespace MQTTnet.Client
{
public sealed class MqttClientUnexpectedDisconnectReceivedException : MqttCommunicationException
{
public MqttClientUnexpectedDisconnectReceivedException(MqttDisconnectPacket disconnectPacket)
: base($"Unexpected DISCONNECT (Reason code={disconnectPacket.ReasonCode}) received.")
public MqttClientUnexpectedDisconnectReceivedException(MqttDisconnectPacket disconnectPacket, Exception innerExcpetion = null) : base(
$"Unexpected DISCONNECT (Reason code={disconnectPacket.ReasonCode}) received.",
innerExcpetion)
{
ReasonCode = disconnectPacket.ReasonCode;
SessionExpiryInterval = disconnectPacket.SessionExpiryInterval;
@@ -23,12 +25,12 @@ namespace MQTTnet.Client
public MqttDisconnectReasonCode? ReasonCode { get; }
public uint? SessionExpiryInterval { get; }
public string ReasonString { get; }
public List<MqttUserProperty> UserProperties { get; }
public string ServerReference { get; }
public uint? SessionExpiryInterval { get; }
public List<MqttUserProperty> UserProperties { get; }
}
}
}
+28 -7
View File
@@ -48,6 +48,7 @@ namespace MQTTnet.Client
Task _packetReceiverTask;
AsyncQueue<MqttPublishPacket> _publishPacketReceiverQueue;
Task _publishPacketReceiverTask;
MqttDisconnectPacket _unexpectedDisconnectPacket;
public MqttClient(IMqttClientAdapterFactory channelFactory, IMqttNetLogger logger)
{
@@ -123,6 +124,8 @@ namespace MQTTnet.Client
var adapter = _adapterFactory.CreateClientAdapter(options, new MqttPacketInspector(_events.InspectPacketEvent, _rootLogger), _rootLogger);
_adapter = adapter ?? throw new InvalidOperationException("The adapter factory did not provide an adapter.");
_unexpectedDisconnectPacket = null;
if (cancellationToken.CanBeCanceled)
{
connectResult = await ConnectInternal(adapter, cancellationToken).ConfigureAwait(false);
@@ -239,7 +242,7 @@ namespace MQTTnet.Client
public async Task PingAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
ThrowIfNotConnected();
@@ -330,7 +333,7 @@ namespace MQTTnet.Client
ThrowIfDisposed();
ThrowIfNotConnected();
if (Options.ValidateFeatures)
{
MqttClientSubscribeOptionsValidator.ThrowIfNotSupported(options, _adapter.PacketFormatterAdapter.ProtocolVersion);
@@ -682,9 +685,10 @@ namespace MQTTnet.Client
_disconnectReason = (int)disconnectPacket.ReasonCode;
_disconnectReasonString = disconnectPacket.ReasonString;
_disconnectUserProperties = disconnectPacket.UserProperties;
_unexpectedDisconnectPacket = disconnectPacket;
// Also dispatch disconnect to waiting threads to generate a proper exception.
_packetDispatcher.Dispose(new MqttClientUnexpectedDisconnectReceivedException(disconnectPacket));
_packetDispatcher.Dispose(new MqttClientUnexpectedDisconnectReceivedException(disconnectPacket, null));
return DisconnectInternal(_packetReceiverTask, null, null);
}
@@ -751,10 +755,27 @@ namespace MQTTnet.Client
async Task<MqttClientPublishResult> PublishAtMostOnce(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
{
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
await Send(publishPacket, cancellationToken).ConfigureAwait(false);
try
{
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
await Send(publishPacket, cancellationToken).ConfigureAwait(false);
return MqttClientResultFactory.PublishResult.Create(null);
return MqttClientResultFactory.PublishResult.Create(null);
}
catch (Exception exception)
{
// We have to check if the server has sent a disconnect packet in response to the published message.
// Since we are in QoS 0 we do not get a direct response via an PUBACK packet and thus basically no
// feedback at all.
var localUnexpectedDisconnectPacket = _unexpectedDisconnectPacket;
if (localUnexpectedDisconnectPacket != null)
{
throw new MqttClientUnexpectedDisconnectReceivedException(localUnexpectedDisconnectPacket, exception);
}
throw;
}
}
async Task<MqttClientPublishResult> PublishExactlyOnce(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
@@ -1071,4 +1092,4 @@ namespace MQTTnet.Client
}
}
}
}
}