From 396f040aae482c5f8a5068d9f0831f8b084a556c Mon Sep 17 00:00:00 2001 From: Christian Kratky Date: Tue, 14 May 2019 20:45:45 +0200 Subject: [PATCH] Add support for extended authentication exchange. --- Build/MQTTnet.nuspec | 1 + ...ttExtendedAuthenticationExchangeHandler.cs | 9 + ...ttExtendedAuthenticationExchangeContext.cs | 35 ++++ .../MqttExtendedAuthenticationExchangeData.cs | 17 ++ Source/MQTTnet/Client/IMqttClient.cs | 2 + Source/MQTTnet/Client/MqttClient.cs | 26 +++ Source/MQTTnet/Client/MqttClientExtensions.cs | 16 ++ .../Client/Options/IMqttClientOptions.cs | 2 + .../Client/Options/MqttClientOptions.cs | 2 + .../Options/MqttClientOptionsBuilder.cs | 7 + .../Formatter/V3/MqttV310PacketFormatter.cs | 14 +- .../Formatter/V5/MqttV500DataConverter.cs | 4 +- .../Formatter/V5/MqttV500PacketDecoder.cs | 179 ++++++++++++++---- .../Packets/MqttAuthPacketProperties.cs | 2 +- .../Packets/MqttConnAckPacketProperties.cs | 2 +- .../Packets/MqttConnectPacketProperties.cs | 2 +- .../Packets/MqttDisconnectPacketProperties.cs | 2 +- .../Packets/MqttPubAckPacketProperties.cs | 2 +- .../Packets/MqttPubCompPacketProperties.cs | 2 +- .../Packets/MqttPubRecPacketProperties.cs | 2 +- .../Packets/MqttPubRelPacketProperties.cs | 2 +- Source/MQTTnet/Packets/MqttSubAckPacket.cs | 2 +- .../Packets/MqttSubAckPacketProperties.cs | 2 +- Source/MQTTnet/Packets/MqttSubscribePacket.cs | 2 +- .../Packets/MqttSubscribePacketProperties.cs | 2 +- Source/MQTTnet/Packets/MqttUnsubAckPacket.cs | 2 +- .../Packets/MqttUnsubAckPacketProperties.cs | 2 +- .../MQTTnet/Packets/MqttUnsubscribePacket.cs | 2 +- .../MqttUnsubscribePacketProperties.cs | 2 +- 29 files changed, 289 insertions(+), 57 deletions(-) create mode 100644 Source/MQTTnet/Client/ExtendedAuthenticationExchange/IMqttExtendedAuthenticationExchangeHandler.cs create mode 100644 Source/MQTTnet/Client/ExtendedAuthenticationExchange/MqttExtendedAuthenticationExchangeContext.cs create mode 100644 Source/MQTTnet/Client/ExtendedAuthenticationExchange/MqttExtendedAuthenticationExchangeData.cs diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec index 2ecfc07..cd49b7f 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 issues in MQTTv5 message encoding and decoding. +* [Client] Added support for extended authentication exchange. Copyright Christian Kratky 2016-2019 MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin diff --git a/Source/MQTTnet/Client/ExtendedAuthenticationExchange/IMqttExtendedAuthenticationExchangeHandler.cs b/Source/MQTTnet/Client/ExtendedAuthenticationExchange/IMqttExtendedAuthenticationExchangeHandler.cs new file mode 100644 index 0000000..8cd3542 --- /dev/null +++ b/Source/MQTTnet/Client/ExtendedAuthenticationExchange/IMqttExtendedAuthenticationExchangeHandler.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace MQTTnet.Client.ExtendedAuthenticationExchange +{ + public interface IMqttExtendedAuthenticationExchangeHandler + { + Task HandleRequestAsync(MqttExtendedAuthenticationExchangeContext context); + } +} diff --git a/Source/MQTTnet/Client/ExtendedAuthenticationExchange/MqttExtendedAuthenticationExchangeContext.cs b/Source/MQTTnet/Client/ExtendedAuthenticationExchange/MqttExtendedAuthenticationExchangeContext.cs new file mode 100644 index 0000000..9e88f03 --- /dev/null +++ b/Source/MQTTnet/Client/ExtendedAuthenticationExchange/MqttExtendedAuthenticationExchangeContext.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using MQTTnet.Packets; +using MQTTnet.Protocol; + +namespace MQTTnet.Client.ExtendedAuthenticationExchange +{ + public class MqttExtendedAuthenticationExchangeContext + { + public MqttExtendedAuthenticationExchangeContext(MqttAuthPacket authPacket, IMqttClient client) + { + if (authPacket == null) throw new ArgumentNullException(nameof(authPacket)); + + ReasonCode = authPacket.ReasonCode; + ReasonString = authPacket.Properties?.ReasonString; + AuthenticationMethod = authPacket.Properties?.AuthenticationMethod; + AuthenticationData = authPacket.Properties?.AuthenticationData; + UserProperties = authPacket.Properties?.UserProperties; + + Client = client ?? throw new ArgumentNullException(nameof(client)); + } + + public MqttAuthenticateReasonCode ReasonCode { get; } + + public string ReasonString { get; } + + public string AuthenticationMethod { get; } + + public byte[] AuthenticationData { get; } + + public List UserProperties { get; } + + public IMqttClient Client { get; } + } +} diff --git a/Source/MQTTnet/Client/ExtendedAuthenticationExchange/MqttExtendedAuthenticationExchangeData.cs b/Source/MQTTnet/Client/ExtendedAuthenticationExchange/MqttExtendedAuthenticationExchangeData.cs new file mode 100644 index 0000000..8a49b08 --- /dev/null +++ b/Source/MQTTnet/Client/ExtendedAuthenticationExchange/MqttExtendedAuthenticationExchangeData.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using MQTTnet.Packets; +using MQTTnet.Protocol; + +namespace MQTTnet.Client.ExtendedAuthenticationExchange +{ + public class MqttExtendedAuthenticationExchangeData + { + public MqttAuthenticateReasonCode ReasonCode { get; set; } + + public string ReasonString { get; set; } + + public byte[] AuthenticationData { get; set; } + + public List UserProperties { get; } + } +} diff --git a/Source/MQTTnet/Client/IMqttClient.cs b/Source/MQTTnet/Client/IMqttClient.cs index 70259cf..059f2e6 100644 --- a/Source/MQTTnet/Client/IMqttClient.cs +++ b/Source/MQTTnet/Client/IMqttClient.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; using MQTTnet.Client.Connecting; using MQTTnet.Client.Disconnecting; +using MQTTnet.Client.ExtendedAuthenticationExchange; using MQTTnet.Client.Options; using MQTTnet.Client.Subscribing; using MQTTnet.Client.Unsubscribing; @@ -21,6 +22,7 @@ namespace MQTTnet.Client Task ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken); Task DisconnectAsync(MqttClientDisconnectOptions options, CancellationToken cancellationToken); + Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken); Task SubscribeAsync(MqttClientSubscribeOptions options, CancellationToken cancellationToken); Task UnsubscribeAsync(MqttClientUnsubscribeOptions options, CancellationToken cancellationToken); } diff --git a/Source/MQTTnet/Client/MqttClient.cs b/Source/MQTTnet/Client/MqttClient.cs index 8d877f6..76bceee 100644 --- a/Source/MQTTnet/Client/MqttClient.cs +++ b/Source/MQTTnet/Client/MqttClient.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using MQTTnet.Adapter; using MQTTnet.Client.Connecting; using MQTTnet.Client.Disconnecting; +using MQTTnet.Client.ExtendedAuthenticationExchange; using MQTTnet.Client.Options; using MQTTnet.Client.Publishing; using MQTTnet.Client.Receiving; @@ -138,6 +139,23 @@ namespace MQTTnet.Client } } + public Task SendExtendedAuthenticationExchangeDataAsync(MqttExtendedAuthenticationExchangeData data, CancellationToken cancellationToken) + { + if (data == null) throw new ArgumentNullException(nameof(data)); + + return SendAsync(new MqttAuthPacket + { + Properties = new MqttAuthPacketProperties + { + // This must always be equal to the value from the CONNECT packet. So we use it here to ensure that. + AuthenticationMethod = Options.AuthenticationMethod, + AuthenticationData = data.AuthenticationData, + ReasonString = data.ReasonString, + UserProperties = data.UserProperties + } + }, cancellationToken); + } + public async Task SubscribeAsync(MqttClientSubscribeOptions options, CancellationToken cancellationToken) { if (options == null) throw new ArgumentNullException(nameof(options)); @@ -474,6 +492,14 @@ namespace MQTTnet.Client await DisconnectAsync(null, cancellationToken).ConfigureAwait(false); } + else if (packet is MqttAuthPacket authPacket) + { + var extendedAuthenticationExchangeHandler = Options.ExtendedAuthenticationExchangeHandler; + if (extendedAuthenticationExchangeHandler != null) + { + await extendedAuthenticationExchangeHandler.HandleRequestAsync(new MqttExtendedAuthenticationExchangeContext(authPacket, this)).ConfigureAwait(false); + } + } else { _packetDispatcher.Dispatch(packet); diff --git a/Source/MQTTnet/Client/MqttClientExtensions.cs b/Source/MQTTnet/Client/MqttClientExtensions.cs index e5e3cd7..58040f7 100644 --- a/Source/MQTTnet/Client/MqttClientExtensions.cs +++ b/Source/MQTTnet/Client/MqttClientExtensions.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using MQTTnet.Client.Connecting; using MQTTnet.Client.Disconnecting; +using MQTTnet.Client.ExtendedAuthenticationExchange; using MQTTnet.Client.Options; using MQTTnet.Client.Publishing; using MQTTnet.Client.Receiving; @@ -170,21 +171,36 @@ namespace MQTTnet.Client public static Task ConnectAsync(this IMqttClient client, IMqttClientOptions options) { + if (client == null) throw new ArgumentNullException(nameof(client)); + return client.ConnectAsync(options, CancellationToken.None); } public static Task DisconnectAsync(this IMqttClient client, MqttClientDisconnectOptions options) { + if (client == null) throw new ArgumentNullException(nameof(client)); + return client.DisconnectAsync(options, CancellationToken.None); } + public static Task SendExtendedAuthenticationExchangeDataAsync(this IMqttClient client, MqttExtendedAuthenticationExchangeData data) + { + if (client == null) throw new ArgumentNullException(nameof(client)); + + return client.SendExtendedAuthenticationExchangeDataAsync(data, CancellationToken.None); + } + public static Task SubscribeAsync(this IMqttClient client, MqttClientSubscribeOptions options) { + if (client == null) throw new ArgumentNullException(nameof(client)); + return client.SubscribeAsync(options, CancellationToken.None); } public static Task UnsubscribeAsync(this IMqttClient client, MqttClientUnsubscribeOptions options) { + if (client == null) throw new ArgumentNullException(nameof(client)); + return client.UnsubscribeAsync(options, CancellationToken.None); } diff --git a/Source/MQTTnet/Client/Options/IMqttClientOptions.cs b/Source/MQTTnet/Client/Options/IMqttClientOptions.cs index 3150baa..822603d 100644 --- a/Source/MQTTnet/Client/Options/IMqttClientOptions.cs +++ b/Source/MQTTnet/Client/Options/IMqttClientOptions.cs @@ -1,4 +1,5 @@ using System; +using MQTTnet.Client.ExtendedAuthenticationExchange; using MQTTnet.Formatter; namespace MQTTnet.Client.Options @@ -8,6 +9,7 @@ namespace MQTTnet.Client.Options string ClientId { get; } bool CleanSession { get; } IMqttClientCredentials Credentials { get; } + IMqttExtendedAuthenticationExchangeHandler ExtendedAuthenticationExchangeHandler { get; } MqttProtocolVersion ProtocolVersion { get; } IMqttClientChannelOptions ChannelOptions { get; } diff --git a/Source/MQTTnet/Client/Options/MqttClientOptions.cs b/Source/MQTTnet/Client/Options/MqttClientOptions.cs index be9dc7b..c47f5c6 100644 --- a/Source/MQTTnet/Client/Options/MqttClientOptions.cs +++ b/Source/MQTTnet/Client/Options/MqttClientOptions.cs @@ -1,4 +1,5 @@ using System; +using MQTTnet.Client.ExtendedAuthenticationExchange; using MQTTnet.Formatter; namespace MQTTnet.Client.Options @@ -8,6 +9,7 @@ namespace MQTTnet.Client.Options public string ClientId { get; set; } = Guid.NewGuid().ToString("N"); public bool CleanSession { get; set; } = true; public IMqttClientCredentials Credentials { get; set; } + public IMqttExtendedAuthenticationExchangeHandler ExtendedAuthenticationExchangeHandler { get; set; } public MqttProtocolVersion ProtocolVersion { get; set; } = MqttProtocolVersion.V311; public IMqttClientChannelOptions ChannelOptions { get; set; } diff --git a/Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs b/Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs index c4d7e6c..25563fe 100644 --- a/Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs +++ b/Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using MQTTnet.Client.ExtendedAuthenticationExchange; using MQTTnet.Formatter; namespace MQTTnet.Client.Options @@ -125,6 +126,12 @@ namespace MQTTnet.Client.Options return this; } + public MqttClientOptionsBuilder WithExtendedAuthenticationExchangeHandler(IMqttExtendedAuthenticationExchangeHandler handler) + { + _options.ExtendedAuthenticationExchangeHandler = handler; + return this; + } + public MqttClientOptionsBuilder WithTcpServer(string server, int? port = null) { _tcpOptions = new MqttClientTcpOptions diff --git a/Source/MQTTnet/Formatter/V3/MqttV310PacketFormatter.cs b/Source/MQTTnet/Formatter/V3/MqttV310PacketFormatter.cs index 70af10e..56ffab6 100644 --- a/Source/MQTTnet/Formatter/V3/MqttV310PacketFormatter.cs +++ b/Source/MQTTnet/Formatter/V3/MqttV310PacketFormatter.cs @@ -10,7 +10,11 @@ namespace MQTTnet.Formatter.V3 public class MqttV310PacketFormatter : IMqttPacketFormatter { private const int FixedHeaderSize = 1; - + + private static readonly MqttPingReqPacket PingReqPacket = new MqttPingReqPacket(); + private static readonly MqttPingRespPacket PingRespPacket = new MqttPingRespPacket(); + private static readonly MqttDisconnectPacket DisconnectPacket = new MqttDisconnectPacket(); + private readonly IMqttPacketWriter _packetWriter; public MqttV310PacketFormatter() @@ -67,14 +71,14 @@ namespace MQTTnet.Formatter.V3 { case MqttControlPacketType.Connect: return DecodeConnectPacket(receivedMqttPacket.Body); case MqttControlPacketType.ConnAck: return DecodeConnAckPacket(receivedMqttPacket.Body); - case MqttControlPacketType.Disconnect: return new MqttDisconnectPacket(); + case MqttControlPacketType.Disconnect: return DisconnectPacket; case MqttControlPacketType.Publish: return DecodePublishPacket(receivedMqttPacket); case MqttControlPacketType.PubAck: return DecodePubAckPacket(receivedMqttPacket.Body); case MqttControlPacketType.PubRec: return DecodePubRecPacket(receivedMqttPacket.Body); case MqttControlPacketType.PubRel: return DecodePubRelPacket(receivedMqttPacket.Body); case MqttControlPacketType.PubComp: return DecodePubCompPacket(receivedMqttPacket.Body); - case MqttControlPacketType.PingReq: return new MqttPingReqPacket(); - case MqttControlPacketType.PingResp: return new MqttPingRespPacket(); + case MqttControlPacketType.PingReq: return PingReqPacket; + case MqttControlPacketType.PingResp: return PingRespPacket; case MqttControlPacketType.Subscribe: return DecodeSubscribePacket(receivedMqttPacket.Body); case MqttControlPacketType.SubAck: return DecodeSubAckPacket(receivedMqttPacket.Body); case MqttControlPacketType.Unsubscibe: return DecodeUnsubscribePacket(receivedMqttPacket.Body); @@ -229,7 +233,7 @@ namespace MQTTnet.Formatter.V3 if (!receivedMqttPacket.Body.EndOfStream) { - packet.Payload = receivedMqttPacket.Body.ReadRemainingData().ToArray(); + packet.Payload = receivedMqttPacket.Body.ReadRemainingData(); } return packet; diff --git a/Source/MQTTnet/Formatter/V5/MqttV500DataConverter.cs b/Source/MQTTnet/Formatter/V5/MqttV500DataConverter.cs index 9276617..203181b 100644 --- a/Source/MQTTnet/Formatter/V5/MqttV500DataConverter.cs +++ b/Source/MQTTnet/Formatter/V5/MqttV500DataConverter.cs @@ -160,7 +160,7 @@ namespace MQTTnet.Formatter.V5 packet.TopicFilters.AddRange(options.TopicFilters); packet.Properties.SubscriptionIdentifier = options.SubscriptionIdentifier; - packet.Properties.UserProperties.AddRange(options.UserProperties); + packet.Properties.UserProperties = options.UserProperties; return packet; } @@ -175,7 +175,7 @@ namespace MQTTnet.Formatter.V5 }; packet.TopicFilters.AddRange(options.TopicFilters); - packet.Properties.UserProperties.AddRange(options.UserProperties); + packet.Properties.UserProperties = options.UserProperties; return packet; } diff --git a/Source/MQTTnet/Formatter/V5/MqttV500PacketDecoder.cs b/Source/MQTTnet/Formatter/V5/MqttV500PacketDecoder.cs index 4c394e4..701c338 100644 --- a/Source/MQTTnet/Formatter/V5/MqttV500PacketDecoder.cs +++ b/Source/MQTTnet/Formatter/V5/MqttV500PacketDecoder.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using MQTTnet.Adapter; using MQTTnet.Exceptions; using MQTTnet.Packets; @@ -10,6 +9,10 @@ namespace MQTTnet.Formatter.V5 { public class MqttV500PacketDecoder { + private static readonly MqttPingReqPacket PingReqPacket = new MqttPingReqPacket(); + + private static readonly MqttPingRespPacket PingRespPacket = new MqttPingRespPacket(); + public MqttBasePacket Decode(ReceivedMqttPacket receivedMqttPacket) { if (receivedMqttPacket == null) throw new ArgumentNullException(nameof(receivedMqttPacket)); @@ -46,10 +49,7 @@ namespace MQTTnet.Formatter.V5 { ThrowIfBodyIsEmpty(body); - var packet = new MqttConnectPacket - { - Properties = new MqttConnectPacketProperties() - }; + var packet = new MqttConnectPacket(); var protocolName = body.ReadStringWithLengthPrefix(); var protocolVersion = body.ReadByte(); @@ -84,6 +84,11 @@ namespace MQTTnet.Formatter.V5 var propertiesReader = new MqttV500PropertiesReader(body); while (propertiesReader.MoveNext()) { + if (packet.Properties == null) + { + packet.Properties = new MqttConnectPacketProperties(); + } + if (propertiesReader.CurrentPropertyId == MqttPropertyId.SessionExpiryInterval) { packet.Properties.SessionExpiryInterval = propertiesReader.ReadSessionExpiryInterval(); @@ -118,6 +123,11 @@ namespace MQTTnet.Formatter.V5 } else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty) { + if (packet.Properties.UserProperties == null) + { + packet.Properties.UserProperties = new List(); + } + propertiesReader.AddUserPropertyTo(packet.Properties.UserProperties); } else @@ -213,13 +223,17 @@ namespace MQTTnet.Formatter.V5 var packet = new MqttConnAckPacket { IsSessionPresent = (acknowledgeFlags & 0x1) > 0, - ReasonCode = (MqttConnectReasonCode)body.ReadByte(), - Properties = new MqttConnAckPacketProperties() + ReasonCode = (MqttConnectReasonCode)body.ReadByte() }; var propertiesReader = new MqttV500PropertiesReader(body); while (propertiesReader.MoveNext()) { + if (packet.Properties == null) + { + packet.Properties = new MqttConnAckPacketProperties(); + } + if (propertiesReader.CurrentPropertyId == MqttPropertyId.SessionExpiryInterval) { packet.Properties.SessionExpiryInterval = propertiesReader.ReadSessionExpiryInterval(); @@ -282,6 +296,11 @@ namespace MQTTnet.Formatter.V5 } else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty) { + if (packet.Properties.UserProperties == null) + { + packet.Properties.UserProperties = new List(); + } + propertiesReader.AddUserPropertyTo(packet.Properties.UserProperties); } else @@ -299,13 +318,17 @@ namespace MQTTnet.Formatter.V5 var packet = new MqttDisconnectPacket { - ReasonCode = (MqttDisconnectReasonCode)body.ReadByte(), - Properties = new MqttDisconnectPacketProperties() + ReasonCode = (MqttDisconnectReasonCode)body.ReadByte() }; var propertiesReader = new MqttV500PropertiesReader(body); while (propertiesReader.MoveNext()) { + if (packet.Properties == null) + { + packet.Properties = new MqttDisconnectPacketProperties(); + } + if (propertiesReader.CurrentPropertyId == MqttPropertyId.SessionExpiryInterval) { packet.Properties.SessionExpiryInterval = propertiesReader.ReadSessionExpiryInterval(); @@ -320,6 +343,11 @@ namespace MQTTnet.Formatter.V5 } else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty) { + if (packet.Properties.UserProperties == null) + { + packet.Properties.UserProperties = new List(); + } + propertiesReader.AddUserPropertyTo(packet.Properties.UserProperties); } else @@ -337,19 +365,28 @@ namespace MQTTnet.Formatter.V5 var packet = new MqttSubscribePacket { - PacketIdentifier = body.ReadTwoByteInteger(), - Properties = new MqttSubscribePacketProperties() + PacketIdentifier = body.ReadTwoByteInteger() }; var propertiesReader = new MqttV500PropertiesReader(body); while (propertiesReader.MoveNext()) { + if (packet.Properties == null) + { + packet.Properties = new MqttSubscribePacketProperties(); + } + if (propertiesReader.CurrentPropertyId == MqttPropertyId.SubscriptionIdentifier) { packet.Properties.SubscriptionIdentifier = propertiesReader.ReadSubscriptionIdentifier(); } else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty) { + if (packet.Properties.UserProperties == null) + { + packet.Properties.UserProperties = new List(); + } + propertiesReader.AddUserPropertyTo(packet.Properties.UserProperties); } else @@ -387,19 +424,28 @@ namespace MQTTnet.Formatter.V5 var packet = new MqttSubAckPacket { - PacketIdentifier = body.ReadTwoByteInteger(), - Properties = new MqttSubAckPacketProperties() + PacketIdentifier = body.ReadTwoByteInteger() }; var propertiesReader = new MqttV500PropertiesReader(body); while (propertiesReader.MoveNext()) { + if (packet.Properties == null) + { + packet.Properties = new MqttSubAckPacketProperties(); + } + if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString) { packet.Properties.ReasonString = propertiesReader.ReadReasonString(); } else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty) { + if (packet.Properties.UserProperties == null) + { + packet.Properties.UserProperties = new List(); + } + propertiesReader.AddUserPropertyTo(packet.Properties.UserProperties); } else @@ -423,15 +469,24 @@ namespace MQTTnet.Formatter.V5 var packet = new MqttUnsubscribePacket { - PacketIdentifier = body.ReadTwoByteInteger(), - Properties = new MqttUnsubscribePacketProperties() + PacketIdentifier = body.ReadTwoByteInteger() }; var propertiesReader = new MqttV500PropertiesReader(body); while (propertiesReader.MoveNext()) { + if (packet.Properties == null) + { + packet.Properties = new MqttUnsubscribePacketProperties(); + } + if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty) { + if (packet.Properties.UserProperties == null) + { + packet.Properties.UserProperties = new List(); + } + propertiesReader.AddUserPropertyTo(packet.Properties.UserProperties); } else @@ -454,19 +509,28 @@ namespace MQTTnet.Formatter.V5 var packet = new MqttUnsubAckPacket { - PacketIdentifier = body.ReadTwoByteInteger(), - Properties = new MqttUnsubAckPacketProperties() + PacketIdentifier = body.ReadTwoByteInteger() }; var propertiesReader = new MqttV500PropertiesReader(body); while (propertiesReader.MoveNext()) { + if (packet.Properties == null) + { + packet.Properties = new MqttUnsubAckPacketProperties(); + } + if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString) { packet.Properties.ReasonString = propertiesReader.ReadReasonString(); } else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty) { + if (packet.Properties.UserProperties == null) + { + packet.Properties.UserProperties = new List(); + } + propertiesReader.AddUserPropertyTo(packet.Properties.UserProperties); } else @@ -486,12 +550,12 @@ namespace MQTTnet.Formatter.V5 private static MqttBasePacket DecodePingReqPacket() { - return new MqttPingReqPacket(); + return PingReqPacket; } private static MqttBasePacket DecodePingRespPacket() { - return new MqttPingRespPacket(); + return PingRespPacket; } private static MqttBasePacket DecodePublishPacket(byte header, IMqttPacketBodyReader body) @@ -507,8 +571,7 @@ namespace MQTTnet.Formatter.V5 Topic = body.ReadStringWithLengthPrefix(), Retain = retain, QualityOfServiceLevel = qos, - Dup = dup, - Properties = new MqttPublishPacketProperties() + Dup = dup }; if (qos > 0) @@ -519,6 +582,11 @@ namespace MQTTnet.Formatter.V5 var propertiesReader = new MqttV500PropertiesReader(body); while (propertiesReader.MoveNext()) { + if (packet.Properties == null) + { + packet.Properties = new MqttPublishPacketProperties(); + } + if (propertiesReader.CurrentPropertyId == MqttPropertyId.PayloadFormatIndicator) { packet.Properties.PayloadFormatIndicator = propertiesReader.ReadPayloadFormatIndicator(); @@ -569,7 +637,7 @@ namespace MQTTnet.Formatter.V5 if (!body.EndOfStream) { - packet.Payload = body.ReadRemainingData().ToArray(); + packet.Payload = body.ReadRemainingData(); } return packet; @@ -581,8 +649,7 @@ namespace MQTTnet.Formatter.V5 var packet = new MqttPubAckPacket { - PacketIdentifier = body.ReadTwoByteInteger(), - Properties = new MqttPubAckPacketProperties() + PacketIdentifier = body.ReadTwoByteInteger() }; if (body.EndOfStream) @@ -596,12 +663,22 @@ namespace MQTTnet.Formatter.V5 var propertiesReader = new MqttV500PropertiesReader(body); while (propertiesReader.MoveNext()) { + if (packet.Properties == null) + { + packet.Properties = new MqttPubAckPacketProperties(); + } + if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString) { packet.Properties.ReasonString = propertiesReader.ReadReasonString(); } else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty) { + if (packet.Properties.UserProperties == null) + { + packet.Properties.UserProperties = new List(); + } + propertiesReader.AddUserPropertyTo(packet.Properties.UserProperties); } else @@ -619,8 +696,7 @@ namespace MQTTnet.Formatter.V5 var packet = new MqttPubRecPacket { - PacketIdentifier = body.ReadTwoByteInteger(), - Properties = new MqttPubRecPacketProperties() + PacketIdentifier = body.ReadTwoByteInteger() }; if (body.EndOfStream) @@ -634,12 +710,22 @@ namespace MQTTnet.Formatter.V5 var propertiesReader = new MqttV500PropertiesReader(body); while (propertiesReader.MoveNext()) { + if (packet.Properties == null) + { + packet.Properties = new MqttPubRecPacketProperties(); + } + if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString) { packet.Properties.ReasonString = propertiesReader.ReadReasonString(); } else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty) { + if (packet.Properties.UserProperties == null) + { + packet.Properties.UserProperties = new List(); + } + propertiesReader.AddUserPropertyTo(packet.Properties.UserProperties); } else @@ -657,8 +743,7 @@ namespace MQTTnet.Formatter.V5 var packet = new MqttPubRelPacket { - PacketIdentifier = body.ReadTwoByteInteger(), - Properties = new MqttPubRelPacketProperties() + PacketIdentifier = body.ReadTwoByteInteger() }; if (body.EndOfStream) @@ -672,12 +757,22 @@ namespace MQTTnet.Formatter.V5 var propertiesReader = new MqttV500PropertiesReader(body); while (propertiesReader.MoveNext()) { + if (packet.Properties == null) + { + packet.Properties = new MqttPubRelPacketProperties(); + } + if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString) { packet.Properties.ReasonString = propertiesReader.ReadReasonString(); } else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty) { + if (packet.Properties.UserProperties == null) + { + packet.Properties.UserProperties = new List(); + } + propertiesReader.AddUserPropertyTo(packet.Properties.UserProperties); } else @@ -695,8 +790,7 @@ namespace MQTTnet.Formatter.V5 var packet = new MqttPubCompPacket { - PacketIdentifier = body.ReadTwoByteInteger(), - Properties = new MqttPubCompPacketProperties() + PacketIdentifier = body.ReadTwoByteInteger() }; if (body.EndOfStream) @@ -710,12 +804,22 @@ namespace MQTTnet.Formatter.V5 var propertiesReader = new MqttV500PropertiesReader(body); while (propertiesReader.MoveNext()) { + if (packet.Properties == null) + { + packet.Properties = new MqttPubCompPacketProperties(); + } + if (propertiesReader.CurrentPropertyId == MqttPropertyId.ReasonString) { packet.Properties.ReasonString = propertiesReader.ReadReasonString(); } else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty) { + if (packet.Properties.UserProperties == null) + { + packet.Properties.UserProperties = new List(); + } + propertiesReader.AddUserPropertyTo(packet.Properties.UserProperties); } else @@ -731,10 +835,7 @@ namespace MQTTnet.Formatter.V5 { ThrowIfBodyIsEmpty(body); - var packet = new MqttAuthPacket - { - Properties = new MqttAuthPacketProperties() - }; + var packet = new MqttAuthPacket(); if (body.EndOfStream) { @@ -747,6 +848,11 @@ namespace MQTTnet.Formatter.V5 var propertiesReader = new MqttV500PropertiesReader(body); while (propertiesReader.MoveNext()) { + if (packet.Properties == null) + { + packet.Properties = new MqttAuthPacketProperties(); + } + if (propertiesReader.CurrentPropertyId == MqttPropertyId.AuthenticationMethod) { packet.Properties.AuthenticationMethod = propertiesReader.ReadAuthenticationMethod(); @@ -761,6 +867,11 @@ namespace MQTTnet.Formatter.V5 } else if (propertiesReader.CurrentPropertyId == MqttPropertyId.UserProperty) { + if (packet.Properties.UserProperties == null) + { + packet.Properties.UserProperties = new List(); + } + propertiesReader.AddUserPropertyTo(packet.Properties.UserProperties); } else diff --git a/Source/MQTTnet/Packets/MqttAuthPacketProperties.cs b/Source/MQTTnet/Packets/MqttAuthPacketProperties.cs index 6ed25ee..057004d 100644 --- a/Source/MQTTnet/Packets/MqttAuthPacketProperties.cs +++ b/Source/MQTTnet/Packets/MqttAuthPacketProperties.cs @@ -10,6 +10,6 @@ namespace MQTTnet.Packets public string ReasonString { get; set; } - public List UserProperties { get; } = new List(); + public List UserProperties { get; set; } } } diff --git a/Source/MQTTnet/Packets/MqttConnAckPacketProperties.cs b/Source/MQTTnet/Packets/MqttConnAckPacketProperties.cs index 262222d..d59735c 100644 --- a/Source/MQTTnet/Packets/MqttConnAckPacketProperties.cs +++ b/Source/MQTTnet/Packets/MqttConnAckPacketProperties.cs @@ -18,7 +18,7 @@ namespace MQTTnet.Packets public string ReasonString { get; set; } - public List UserProperties { get; } = new List(); + public List UserProperties { get; set; } public bool? WildcardSubscriptionAvailable { get; set; } diff --git a/Source/MQTTnet/Packets/MqttConnectPacketProperties.cs b/Source/MQTTnet/Packets/MqttConnectPacketProperties.cs index 25cf5bd..4cc405e 100644 --- a/Source/MQTTnet/Packets/MqttConnectPacketProperties.cs +++ b/Source/MQTTnet/Packets/MqttConnectPacketProperties.cs @@ -22,6 +22,6 @@ namespace MQTTnet.Packets public uint? MaximumPacketSize { get; set; } - public List UserProperties { get; } = new List(); + public List UserProperties { get; set; } } } \ No newline at end of file diff --git a/Source/MQTTnet/Packets/MqttDisconnectPacketProperties.cs b/Source/MQTTnet/Packets/MqttDisconnectPacketProperties.cs index a5385cb..e05529f 100644 --- a/Source/MQTTnet/Packets/MqttDisconnectPacketProperties.cs +++ b/Source/MQTTnet/Packets/MqttDisconnectPacketProperties.cs @@ -8,7 +8,7 @@ namespace MQTTnet.Packets public string ReasonString { get; set; } - public List UserProperties { get; } = new List(); + public List UserProperties { get; set; } public string ServerReference { get; set; } } diff --git a/Source/MQTTnet/Packets/MqttPubAckPacketProperties.cs b/Source/MQTTnet/Packets/MqttPubAckPacketProperties.cs index 061f72f..e2debd4 100644 --- a/Source/MQTTnet/Packets/MqttPubAckPacketProperties.cs +++ b/Source/MQTTnet/Packets/MqttPubAckPacketProperties.cs @@ -6,6 +6,6 @@ namespace MQTTnet.Packets { public string ReasonString { get; set; } - public List UserProperties { get; } = new List(); + public List UserProperties { get; set; } } } diff --git a/Source/MQTTnet/Packets/MqttPubCompPacketProperties.cs b/Source/MQTTnet/Packets/MqttPubCompPacketProperties.cs index c29ad6a..35e040f 100644 --- a/Source/MQTTnet/Packets/MqttPubCompPacketProperties.cs +++ b/Source/MQTTnet/Packets/MqttPubCompPacketProperties.cs @@ -6,6 +6,6 @@ namespace MQTTnet.Packets { public string ReasonString { get; set; } - public List UserProperties { get; } = new List(); + public List UserProperties { get; set; } } } diff --git a/Source/MQTTnet/Packets/MqttPubRecPacketProperties.cs b/Source/MQTTnet/Packets/MqttPubRecPacketProperties.cs index 574bc61..0cd7225 100644 --- a/Source/MQTTnet/Packets/MqttPubRecPacketProperties.cs +++ b/Source/MQTTnet/Packets/MqttPubRecPacketProperties.cs @@ -6,6 +6,6 @@ namespace MQTTnet.Packets { public string ReasonString { get; set; } - public List UserProperties { get; } = new List(); + public List UserProperties { get; set; } } } diff --git a/Source/MQTTnet/Packets/MqttPubRelPacketProperties.cs b/Source/MQTTnet/Packets/MqttPubRelPacketProperties.cs index d7a21f6..aa9625d 100644 --- a/Source/MQTTnet/Packets/MqttPubRelPacketProperties.cs +++ b/Source/MQTTnet/Packets/MqttPubRelPacketProperties.cs @@ -6,6 +6,6 @@ namespace MQTTnet.Packets { public string ReasonString { get; set; } - public List UserProperties { get; } = new List(); + public List UserProperties { get; set; } } } diff --git a/Source/MQTTnet/Packets/MqttSubAckPacket.cs b/Source/MQTTnet/Packets/MqttSubAckPacket.cs index 053e713..4600a4e 100644 --- a/Source/MQTTnet/Packets/MqttSubAckPacket.cs +++ b/Source/MQTTnet/Packets/MqttSubAckPacket.cs @@ -8,7 +8,7 @@ namespace MQTTnet.Packets { public ushort? PacketIdentifier { get; set; } - public List ReturnCodes { get; } = new List(); + public List ReturnCodes { get; set; } = new List(); #region Added in MQTTv5.0.0 diff --git a/Source/MQTTnet/Packets/MqttSubAckPacketProperties.cs b/Source/MQTTnet/Packets/MqttSubAckPacketProperties.cs index b2b3eff..74d3e7f 100644 --- a/Source/MQTTnet/Packets/MqttSubAckPacketProperties.cs +++ b/Source/MQTTnet/Packets/MqttSubAckPacketProperties.cs @@ -6,6 +6,6 @@ namespace MQTTnet.Packets { public string ReasonString { get; set; } - public List UserProperties { get; } = new List(); + public List UserProperties { get; set; } } } diff --git a/Source/MQTTnet/Packets/MqttSubscribePacket.cs b/Source/MQTTnet/Packets/MqttSubscribePacket.cs index c96c75b..1ea1685 100644 --- a/Source/MQTTnet/Packets/MqttSubscribePacket.cs +++ b/Source/MQTTnet/Packets/MqttSubscribePacket.cs @@ -7,7 +7,7 @@ namespace MQTTnet.Packets { public ushort? PacketIdentifier { get; set; } - public List TopicFilters { get; } = new List(); + public List TopicFilters { get; set; } = new List(); #region Added in MQTTv5 diff --git a/Source/MQTTnet/Packets/MqttSubscribePacketProperties.cs b/Source/MQTTnet/Packets/MqttSubscribePacketProperties.cs index 5b92c5f..34f58f2 100644 --- a/Source/MQTTnet/Packets/MqttSubscribePacketProperties.cs +++ b/Source/MQTTnet/Packets/MqttSubscribePacketProperties.cs @@ -6,6 +6,6 @@ namespace MQTTnet.Packets { public uint? SubscriptionIdentifier { get; set; } - public List UserProperties { get; } = new List(); + public List UserProperties { get; set; } } } diff --git a/Source/MQTTnet/Packets/MqttUnsubAckPacket.cs b/Source/MQTTnet/Packets/MqttUnsubAckPacket.cs index 0b45df6..a17261e 100644 --- a/Source/MQTTnet/Packets/MqttUnsubAckPacket.cs +++ b/Source/MQTTnet/Packets/MqttUnsubAckPacket.cs @@ -12,7 +12,7 @@ namespace MQTTnet.Packets public MqttUnsubAckPacketProperties Properties { get; set; } - public List ReasonCodes { get; } = new List(); + public List ReasonCodes { get; set; } = new List(); #endregion diff --git a/Source/MQTTnet/Packets/MqttUnsubAckPacketProperties.cs b/Source/MQTTnet/Packets/MqttUnsubAckPacketProperties.cs index ca444d9..2a102c6 100644 --- a/Source/MQTTnet/Packets/MqttUnsubAckPacketProperties.cs +++ b/Source/MQTTnet/Packets/MqttUnsubAckPacketProperties.cs @@ -6,6 +6,6 @@ namespace MQTTnet.Packets { public string ReasonString { get; set; } - public List UserProperties { get; } = new List(); + public List UserProperties { get; set; } } } diff --git a/Source/MQTTnet/Packets/MqttUnsubscribePacket.cs b/Source/MQTTnet/Packets/MqttUnsubscribePacket.cs index bb1d4c2..7b07a24 100644 --- a/Source/MQTTnet/Packets/MqttUnsubscribePacket.cs +++ b/Source/MQTTnet/Packets/MqttUnsubscribePacket.cs @@ -6,7 +6,7 @@ namespace MQTTnet.Packets { public ushort? PacketIdentifier { get; set; } - public List TopicFilters { get; } = new List(); + public List TopicFilters { get; set; } = new List(); #region Added in MQTTv5 diff --git a/Source/MQTTnet/Packets/MqttUnsubscribePacketProperties.cs b/Source/MQTTnet/Packets/MqttUnsubscribePacketProperties.cs index 5fb4d66..3ec68f1 100644 --- a/Source/MQTTnet/Packets/MqttUnsubscribePacketProperties.cs +++ b/Source/MQTTnet/Packets/MqttUnsubscribePacketProperties.cs @@ -4,6 +4,6 @@ namespace MQTTnet.Packets { public class MqttUnsubscribePacketProperties { - public List UserProperties { get; } = new List(); + public List UserProperties { get; set; } } }