Closed
Description
🐛 Bug Report
It seems like there is no check in place to ensure the SubAckPacket
is the response to the SubscribePacket
that is sent. From what I see it could be just any SubAckPacket
.
hivemq-mqtt-client-dotnet/Source/HiveMQtt/Client/HiveMQClient.cs
Lines 307 to 345 in 04593d4
So sometimes the wrong SubAckPacket
ends up in here paired with the wrong SubscribeOptions
. This leads to an ArgumentOutOfRangeException
here:
🔬 How To Reproduce
Steps to reproduce the behavior:
Call Subscribe a lot of times in a concurrent manner with a different number of topics.
class Program
{
static async Task Main(string[] args)
{
var client =
new HiveMQClient(
new HiveMQClientOptionsBuilder()
.WithClientId("ConcurrentSubscribe")
.WithAutomaticReconnect(true)
.Build()
);
var connectResult = await client.ConnectAsync().ConfigureAwait(false);
Assert.True(connectResult.ReasonCode == ConnAckReasonCode.Success);
Assert.True(client.IsConnected());
foreach (var worker in Enumerable.Range(0, 50))
{
Task.Run(async () =>
{
var call = 0;
while (true)
{
var topicPrefix = $"/test/topic/{worker}/{call}";
var allTopics = new[]
{
$"{topicPrefix}/a",
$"{topicPrefix}/b",
$"{topicPrefix}/c",
$"{topicPrefix}/d",
$"{topicPrefix}/e",
$"{topicPrefix}/f",
$"{topicPrefix}/g"
};
var randomTopics =
allTopics
.OrderBy(x => Guid.NewGuid())
.Take(Random.Shared.Next(1, allTopics.Length))
.ToArray();
try
{
var subscribeResult =
await client
.SubscribeAsync(new SubscribeOptions()
{
TopicFilters = randomTopics.Select(x => new TopicFilter(x)).ToList()
})
.ConfigureAwait(false);
var unsubscribeResult =
await client
.UnsubscribeAsync(new UnsubscribeOptions()
{
Subscriptions = subscribeResult.Subscriptions
})
.ConfigureAwait(false);
}
catch (Exception e)
{
Console.WriteLine(e);
}
call += 1;
}
});
}
await Task.Delay(-1).ConfigureAwait(false);
}
}
Code sample
Environment
Where are you running/using this client?
Windows, Linux, MacOS.
Reproduces with HiveMQtt 0.24.0 and current master.