1883 in a weak network environment the mqtt broker is unable to detect disconnections (#1891)

* Add new setting

* Align keep alive handling with RFC

Only completely sent packets are treated as keep alive

* Update ReleaseNotes.md
This commit is contained in:
Christian
2023-12-07 17:49:03 +01:00
committed by GitHub
parent f3499013f4
commit 4df06980a1
7 changed files with 61 additions and 61 deletions
+1
View File
@@ -1 +1,2 @@
* [Server] Added new events for delivered and dropped messages (#1866, thanks to @kallayj). * [Server] Added new events for delivered and dropped messages (#1866, thanks to @kallayj).
* [Server] The server will no longer treat a client which is receiving a large payload as alive. The packet must be received completely within the keep alive boundaries (BREAKING CHANGE!, #1883).
@@ -83,8 +83,6 @@ namespace MQTTnet.AspNetCore
} }
} }
public bool IsReadingPacket { get; private set; }
public bool IsSecureConnection public bool IsSecureConnection
{ {
get get
@@ -164,11 +162,6 @@ namespace MQTTnet.AspNetCore
BytesReceived += received; BytesReceived += received;
return packet; return packet;
} }
else
{
// we did receive something but the message is not yet complete
IsReadingPacket = true;
}
} }
else if (readResult.IsCompleted) else if (readResult.IsCompleted)
{ {
@@ -189,12 +182,9 @@ namespace MQTTnet.AspNetCore
// completing the channel makes sure that there is no more data read after a protocol error // completing the channel makes sure that there is no more data read after a protocol error
_input?.Complete(exception); _input?.Complete(exception);
_output?.Complete(exception); _output?.Complete(exception);
throw; throw;
} }
finally
{
IsReadingPacket = false;
}
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
return null; return null;
@@ -25,8 +25,6 @@ namespace MQTTnet.Adapter
long BytesReceived { get; } long BytesReceived { get; }
bool IsReadingPacket { get; }
Task ConnectAsync(CancellationToken cancellationToken); Task ConnectAsync(CancellationToken cancellationToken);
Task DisconnectAsync(CancellationToken cancellationToken); Task DisconnectAsync(CancellationToken cancellationToken);
+29 -39
View File
@@ -55,8 +55,6 @@ namespace MQTTnet.Adapter
public string Endpoint => _channel.Endpoint; public string Endpoint => _channel.Endpoint;
public bool IsReadingPacket { get; private set; }
public bool IsSecureConnection => _channel.IsSecureConnection; public bool IsSecureConnection => _channel.IsSecureConnection;
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; } public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
@@ -389,53 +387,45 @@ namespace MQTTnet.Adapter
return ReceivedMqttPacket.Empty; return ReceivedMqttPacket.Empty;
} }
IsReadingPacket = true; var fixedHeader = readFixedHeaderResult.FixedHeader;
try if (fixedHeader.RemainingLength == 0)
{ {
var fixedHeader = readFixedHeaderResult.FixedHeader; return new ReceivedMqttPacket(fixedHeader.Flags, EmptyBuffer.ArraySegment, 2);
if (fixedHeader.RemainingLength == 0) }
var bodyLength = fixedHeader.RemainingLength;
var body = new byte[bodyLength];
var bodyOffset = 0;
var chunkSize = Math.Min(ReadBufferSize, bodyLength);
do
{
var bytesLeft = body.Length - bodyOffset;
if (chunkSize > bytesLeft)
{ {
return new ReceivedMqttPacket(fixedHeader.Flags, EmptyBuffer.ArraySegment, 2); chunkSize = bytesLeft;
} }
var bodyLength = fixedHeader.RemainingLength; var readBytes = await _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false);
var body = new byte[bodyLength];
var bodyOffset = 0; if (cancellationToken.IsCancellationRequested)
var chunkSize = Math.Min(ReadBufferSize, bodyLength);
do
{ {
var bytesLeft = body.Length - bodyOffset; return ReceivedMqttPacket.Empty;
if (chunkSize > bytesLeft) }
{
chunkSize = bytesLeft;
}
var readBytes = await _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false); if (readBytes == 0)
{
return ReceivedMqttPacket.Empty;
}
if (cancellationToken.IsCancellationRequested) bodyOffset += readBytes;
{ } while (bodyOffset < bodyLength);
return ReceivedMqttPacket.Empty;
}
if (readBytes == 0) PacketInspector?.FillReceiveBuffer(body);
{
return ReceivedMqttPacket.Empty;
}
bodyOffset += readBytes; var bodySegment = new ArraySegment<byte>(body, 0, bodyLength);
} while (bodyOffset < bodyLength); return new ReceivedMqttPacket(fixedHeader.Flags, bodySegment, fixedHeader.TotalLength);
PacketInspector?.FillReceiveBuffer(body);
var bodySegment = new ArraySegment<byte>(body, 0, bodyLength);
return new ReceivedMqttPacket(fixedHeader.Flags, bodySegment, fixedHeader.TotalLength);
}
finally
{
IsReadingPacket = false;
}
} }
static bool WrapAndThrowException(Exception exception) static bool WrapAndThrowException(Exception exception)
@@ -107,13 +107,6 @@ namespace MQTTnet.Server
return; return;
} }
if (connection.ChannelAdapter.IsReadingPacket)
{
// The connection is currently reading a (large) packet. So it is obviously
// doing something and thus "connected".
return;
}
// Values described here: [MQTT-3.1.2-24]. // Values described here: [MQTT-3.1.2-24].
// If the client sends 5 sec. the server will allow up to 7.5 seconds. // If the client sends 5 sec. the server will allow up to 7.5 seconds.
// If the client sends 1 sec. the server will allow up to 1.5 seconds. // If the client sends 1 sec. the server will allow up to 1.5 seconds.
@@ -0,0 +1,21 @@
// 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.Server
{
public sealed class MqttServerKeepAliveOptions
{
/// <summary>
/// When this mode is enabled the MQTT server will not close a connection when the
/// client is currently sending a (large) payload. This may lead to "dead" connections
/// When this mode is disabled the MQTT server will disconnect a client when the keep
/// alive timeout is reached even if the client is currently sending a (large) payload.
/// </summary>
public bool DisconnectClientWhenReadingPayload { get; set; }
public TimeSpan MonitorInterval { get; set; } = TimeSpan.FromMilliseconds(500);
}
}
@@ -9,12 +9,19 @@ namespace MQTTnet.Server
public sealed class MqttServerOptions public sealed class MqttServerOptions
{ {
public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(100); public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(100);
public MqttServerTcpEndpointOptions DefaultEndpointOptions { get; } = new MqttServerTcpEndpointOptions(); public MqttServerTcpEndpointOptions DefaultEndpointOptions { get; } = new MqttServerTcpEndpointOptions();
public bool EnablePersistentSessions { get; set; } public bool EnablePersistentSessions { get; set; }
public TimeSpan KeepAliveMonitorInterval { get; set; } = TimeSpan.FromMilliseconds(500); [Obsolete("Use KeepAliveOptions instead.")]
public TimeSpan KeepAliveMonitorInterval
{
get => KeepAliveOptions.MonitorInterval;
set => KeepAliveOptions.MonitorInterval = value;
}
public MqttServerKeepAliveOptions KeepAliveOptions { get; } = new MqttServerKeepAliveOptions();
public int MaxPendingMessagesPerClient { get; set; } = 250; public int MaxPendingMessagesPerClient { get; set; } = 250;