diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec
index 9603423..9c2e0d3 100644
--- a/Build/MQTTnet.nuspec
+++ b/Build/MQTTnet.nuspec
@@ -12,6 +12,7 @@
MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker).
* [Core] Fixed some still thread blocking parts in the code (thanks to @kpreisser).
* [Core] Updated 3rd-Party packages.
+* [Core] Fixed wrong packet identifier calculation (thanks to @benpittoors).
* [Core] Fixed an issue when reading the body of a package from a disconnected sender (thanks to @kpreisser).
* [Core] Fixed wrong parsing of the body length (thanks to @kpreisser).
* [Client] The client interfaces are now implementing _IDisposable_.
diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs
index a4ec82f..f71ada1 100644
--- a/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs
+++ b/Frameworks/MQTTnet.NetStandard/Client/MqttClient.cs
@@ -14,13 +14,13 @@ namespace MQTTnet.Client
{
public class MqttClient : IMqttClient
{
+ private readonly MqttPacketIdentifierProvider _packetIdentifierProvider = new MqttPacketIdentifierProvider();
private readonly IMqttClientAdapterFactory _adapterFactory;
private readonly MqttPacketDispatcher _packetDispatcher;
private readonly IMqttNetLogger _logger;
private IMqttClientOptions _options;
private bool _isReceivingPackets;
- private int _latestPacketIdentifier;
private CancellationTokenSource _cancellationTokenSource;
private IMqttChannelAdapter _adapter;
@@ -49,7 +49,7 @@ namespace MQTTnet.Client
{
_options = options;
_cancellationTokenSource = new CancellationTokenSource();
- _latestPacketIdentifier = 0;
+ _packetIdentifierProvider.Reset();
_packetDispatcher.Reset();
_adapter = _adapterFactory.CreateClientAdapter(options.ChannelOptions, _logger);
@@ -106,7 +106,7 @@ namespace MQTTnet.Client
var subscribePacket = new MqttSubscribePacket
{
- PacketIdentifier = GetNewPacketIdentifier(),
+ PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier(),
TopicFilters = topicFilters.ToList()
};
@@ -128,7 +128,7 @@ namespace MQTTnet.Client
var unsubscribePacket = new MqttUnsubscribePacket
{
- PacketIdentifier = GetNewPacketIdentifier(),
+ PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier(),
TopicFilters = topicFilters.ToList()
};
@@ -156,7 +156,7 @@ namespace MQTTnet.Client
{
foreach (var publishPacket in qosGroup)
{
- publishPacket.PacketIdentifier = GetNewPacketIdentifier();
+ publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier();
await SendAndReceiveAsync(publishPacket).ConfigureAwait(false);
}
@@ -166,7 +166,7 @@ namespace MQTTnet.Client
{
foreach (var publishPacket in qosGroup)
{
- publishPacket.PacketIdentifier = GetNewPacketIdentifier();
+ publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier();
var pubRecPacket = await SendAndReceiveAsync(publishPacket).ConfigureAwait(false);
await SendAndReceiveAsync(pubRecPacket.CreateResponse()).ConfigureAwait(false);
}
@@ -340,11 +340,6 @@ namespace MQTTnet.Client
return (TResponsePacket)await packetAwaiter.ConfigureAwait(false);
}
- private ushort GetNewPacketIdentifier()
- {
- return (ushort)Interlocked.Increment(ref _latestPacketIdentifier);
- }
-
private async Task SendKeepAliveMessagesAsync(CancellationToken cancellationToken)
{
_logger.Info("Start sending keep alive packets.");
diff --git a/Frameworks/MQTTnet.NetStandard/Client/MqttPacketIdentifierProvider.cs b/Frameworks/MQTTnet.NetStandard/Client/MqttPacketIdentifierProvider.cs
new file mode 100644
index 0000000..dc09918
--- /dev/null
+++ b/Frameworks/MQTTnet.NetStandard/Client/MqttPacketIdentifierProvider.cs
@@ -0,0 +1,32 @@
+namespace MQTTnet.Client
+{
+ public class MqttPacketIdentifierProvider
+ {
+ private readonly object _syncRoot = new object();
+ private ushort _value;
+
+ public void Reset()
+ {
+ lock (_syncRoot)
+ {
+ _value = 0;
+ }
+ }
+
+ public ushort GetNewPacketIdentifier()
+ {
+ lock (_syncRoot)
+ {
+ _value++;
+
+ if (_value == 0)
+ {
+ // As per official MQTT documentation the package identifier should never be 0.
+ _value = 1;
+ }
+
+ return _value;
+ }
+ }
+ }
+}
diff --git a/Tests/MQTTnet.Core.Tests/MqttPacketIdentifierProviderTests.cs b/Tests/MQTTnet.Core.Tests/MqttPacketIdentifierProviderTests.cs
new file mode 100644
index 0000000..ab7070e
--- /dev/null
+++ b/Tests/MQTTnet.Core.Tests/MqttPacketIdentifierProviderTests.cs
@@ -0,0 +1,32 @@
+using Microsoft.VisualStudio.TestTools .UnitTesting;
+using MQTTnet.Client;
+
+namespace MQTTnet.Core.Tests
+{
+ [TestClass]
+ public class MqttPacketIdentifierProviderTests
+ {
+ [TestMethod]
+ public void Reset()
+ {
+ var p = new MqttPacketIdentifierProvider();
+ Assert.AreEqual(1, p.GetNewPacketIdentifier());
+ Assert.AreEqual(2, p.GetNewPacketIdentifier());
+ p.Reset();
+ Assert.AreEqual(1, p.GetNewPacketIdentifier());
+ }
+
+ [TestMethod]
+ public void ReachBoundaries()
+ {
+ var p = new MqttPacketIdentifierProvider();
+
+ for (ushort i = 0; i < ushort.MaxValue; i++)
+ {
+ Assert.AreEqual(i + 1, p.GetNewPacketIdentifier());
+ }
+
+ Assert.AreEqual(1, p.GetNewPacketIdentifier());
+ }
+ }
+}