Fix upgrading and downgrading of retained messages QoS for subscriptions (#1564)

This commit is contained in:
Christian
2022-11-06 10:35:59 +01:00
committed by GitHub
parent 5b1cc7d713
commit 3fc6982e9a
9 changed files with 111 additions and 23 deletions
+2 -3
View File
@@ -296,15 +296,14 @@ namespace MQTTnet.Server
if (subscribeResult.RetainedMessages != null)
{
foreach (var retainedApplicationMessage in subscribeResult.RetainedMessages)
foreach (var retainedMessageMatch in subscribeResult.RetainedMessages)
{
var publishPacket = _packetFactories.Publish.Create(retainedApplicationMessage.ApplicationMessage);
var publishPacket = _packetFactories.Publish.Create(retainedMessageMatch);
Session.EnqueueDataPacket(new MqttPacketBusItem(publishPacket));
}
}
}
async Task HandleIncomingUnsubscribePacket(MqttUnsubscribePacket unsubscribePacket, CancellationToken cancellationToken)
{
var unsubscribeResult = await Session.SubscriptionsManager.Unsubscribe(unsubscribePacket, cancellationToken).ConfigureAwait(false);
@@ -418,9 +418,9 @@ namespace MQTTnet.Server
if (subscribeResult.RetainedMessages != null)
{
foreach (var retainedApplicationMessage in subscribeResult.RetainedMessages)
foreach (var retainedMessageMatch in subscribeResult.RetainedMessages)
{
var publishPacket = _packetFactories.Publish.Create(retainedApplicationMessage.ApplicationMessage);
var publishPacket = _packetFactories.Publish.Create(retainedMessageMatch);
clientSession.EnqueueDataPacket(new MqttPacketBusItem(publishPacket));
}
}
@@ -169,10 +169,7 @@ namespace MQTTnet.Server
}
var retainedApplicationMessages = await _retainedMessagesManager.GetMessages().ConfigureAwait(false);
var result = new SubscribeResult
{
ReasonCodes = new List<MqttSubscribeReasonCode>(subscribePacket.TopicFilters.Count)
};
var result = new SubscribeResult(subscribePacket.TopicFilters.Count);
var addedSubscriptions = new List<string>();
var finalTopicFilters = new List<MqttTopicFilter>();
@@ -412,14 +409,14 @@ namespace MQTTnet.Server
}
static void FilterRetainedApplicationMessages(
IList<MqttApplicationMessage> retainedApplicationMessages,
IList<MqttApplicationMessage> retainedMessages,
CreateSubscriptionResult createSubscriptionResult,
SubscribeResult subscribeResult)
{
for (var index = retainedApplicationMessages.Count - 1; index >= 0; index--)
for (var index = retainedMessages.Count - 1; index >= 0; index--)
{
var retainedApplicationMessage = retainedApplicationMessages[index];
if (retainedApplicationMessage == null)
var retainedMessage = retainedMessages[index];
if (retainedMessage == null)
{
continue;
}
@@ -436,16 +433,21 @@ namespace MQTTnet.Server
continue;
}
if (MqttTopicFilterComparer.Compare(retainedApplicationMessage.Topic, createSubscriptionResult.Subscription.Topic) != MqttTopicFilterCompareResult.IsMatch)
if (MqttTopicFilterComparer.Compare(retainedMessage.Topic, createSubscriptionResult.Subscription.Topic) != MqttTopicFilterCompareResult.IsMatch)
{
continue;
}
var retainedMessageMatch = new MqttRetainedMessageMatch
var retainedMessageMatch = new MqttRetainedMessageMatch(retainedMessage, createSubscriptionResult.Subscription.GrantedQualityOfServiceLevel);
if (retainedMessageMatch.SubscriptionQualityOfServiceLevel > retainedMessageMatch.ApplicationMessage.QualityOfServiceLevel)
{
ApplicationMessage = retainedApplicationMessage,
SubscriptionQualityOfServiceLevel = createSubscriptionResult.Subscription.GrantedQualityOfServiceLevel
};
// UPGRADING the QoS is not allowed!
// From MQTT spec: Subscribing to a Topic Filter at QoS 2 is equivalent to saying
// "I would like to receive Messages matching this filter at the QoS with which they were published".
// This means a publisher is responsible for determining the maximum QoS a Message can be delivered at,
// but a subscriber is able to require that the Server downgrades the QoS to one more suitable for its usage.
retainedMessageMatch.SubscriptionQualityOfServiceLevel = retainedMessageMatch.ApplicationMessage.QualityOfServiceLevel;
}
if (subscribeResult.RetainedMessages == null)
{
@@ -456,7 +458,7 @@ namespace MQTTnet.Server
// Clear the retained message from the list because the client should receive every message only
// one time even if multiple subscriptions affect them.
retainedApplicationMessages[index] = null;
retainedMessages[index] = null;
}
}
@@ -10,8 +10,13 @@ namespace MQTTnet.Server
{
public sealed class SubscribeResult
{
public SubscribeResult(int topicsCount)
{
ReasonCodes = new List<MqttSubscribeReasonCode>(topicsCount);
}
public bool CloseConnection { get; set; }
public List<MqttSubscribeReasonCode> ReasonCodes { get; set; }
public string ReasonString { get; set; }
@@ -2,13 +2,20 @@
// 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 MQTTnet.Protocol;
namespace MQTTnet.Server
{
public sealed class MqttRetainedMessageMatch
{
public MqttApplicationMessage ApplicationMessage { get; set; }
public MqttRetainedMessageMatch(MqttApplicationMessage applicationMessage, MqttQualityOfServiceLevel subscriptionQualityOfServiceLevel)
{
ApplicationMessage = applicationMessage ?? throw new ArgumentNullException(nameof(applicationMessage));
SubscriptionQualityOfServiceLevel = subscriptionQualityOfServiceLevel;
}
public MqttApplicationMessage ApplicationMessage { get; }
public MqttQualityOfServiceLevel SubscriptionQualityOfServiceLevel { get; set; }
}