@@ -20,7 +20,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov | |||||
* Async support | * Async support | ||||
* TLS 1.2 support for client and server (but not UWP servers) | * TLS 1.2 support for client and server (but not UWP servers) | ||||
* Extensible communication channels (i.e. In-Memory, TCP, TCP+TLS, WS) | |||||
* Extensible communication channels (e.g. In-Memory, TCP, TCP+TLS, WS) | |||||
* Lightweight (only the low level implementation of MQTT, no overhead) | * Lightweight (only the low level implementation of MQTT, no overhead) | ||||
* Performance optimized (processing ~70.000 messages / second)* | * Performance optimized (processing ~70.000 messages / second)* | ||||
* Interfaces included for mocking and testing | * Interfaces included for mocking and testing | ||||
@@ -48,6 +48,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov | |||||
* WebSockets supported (via ASP.NET Core 2.0, separate nuget) | * WebSockets supported (via ASP.NET Core 2.0, separate nuget) | ||||
* A custom message interceptor can be added which allows transforming or extending every received application message | * A custom message interceptor can be added which allows transforming or extending every received application message | ||||
* Validate subscriptions and deny subscribing of certain topics depending on requesting clients | * Validate subscriptions and deny subscribing of certain topics depending on requesting clients | ||||
* Connect clients with different protocol versions at the same time. | |||||
## Supported frameworks | ## Supported frameworks | ||||
@@ -62,7 +63,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov | |||||
## Supported MQTT versions | ## Supported MQTT versions | ||||
* 5.0.0 (planned) | |||||
* 5.0.0 | |||||
* 3.1.1 | * 3.1.1 | ||||
* 3.1.0 | * 3.1.0 | ||||
@@ -21,7 +21,7 @@ namespace MQTTnet.Formatter.V500 | |||||
packet.IsSessionPresent = (acknowledgeFlags & 0x1) > 0; | packet.IsSessionPresent = (acknowledgeFlags & 0x1) > 0; | ||||
packet.ConnectReturnCode = (MqttConnectReturnCode)body.ReadByte(); | packet.ConnectReturnCode = (MqttConnectReturnCode)body.ReadByte(); | ||||
packet.ConnectReasonCode = (MqttConnectReasonCode)body.ReadByte(); | |||||
packet.ReasonCode = (MqttConnectReasonCode)body.ReadByte(); | |||||
var propertiesLength = body.ReadVariableLengthInteger(); | var propertiesLength = body.ReadVariableLengthInteger(); | ||||
if (propertiesLength > 0) | if (propertiesLength > 0) | ||||
@@ -97,9 +97,9 @@ namespace MQTTnet.Formatter.V500 | |||||
if (packet == null) throw new ArgumentNullException(nameof(packet)); | if (packet == null) throw new ArgumentNullException(nameof(packet)); | ||||
if (packetWriter == null) throw new ArgumentNullException(nameof(packetWriter)); | if (packetWriter == null) throw new ArgumentNullException(nameof(packetWriter)); | ||||
if (!packet.ConnectReasonCode.HasValue) | |||||
if (!packet.ReasonCode.HasValue) | |||||
{ | { | ||||
throw new MqttProtocolViolationException("The ConnectReasonCode must be set for MQTT version 5."); | |||||
throw new MqttProtocolViolationException("The ReasonCode must be set for MQTT version 5."); | |||||
} | } | ||||
byte connectAcknowledgeFlags = 0x0; | byte connectAcknowledgeFlags = 0x0; | ||||
@@ -110,7 +110,7 @@ namespace MQTTnet.Formatter.V500 | |||||
packetWriter.Write(connectAcknowledgeFlags); | packetWriter.Write(connectAcknowledgeFlags); | ||||
packetWriter.Write((byte)packet.ConnectReturnCode); | packetWriter.Write((byte)packet.ConnectReturnCode); | ||||
packetWriter.Write((byte)packet.ConnectReasonCode.Value); | |||||
packetWriter.Write((byte)packet.ReasonCode.Value); | |||||
var propertiesWriter = new MqttV500PropertiesWriter(); | var propertiesWriter = new MqttV500PropertiesWriter(); | ||||
if (packet.Properties != null) | if (packet.Properties != null) | ||||
@@ -209,13 +209,13 @@ namespace MQTTnet.Formatter.V500 | |||||
throw new MqttProtocolViolationException("PubAck packet has no packet identifier."); | throw new MqttProtocolViolationException("PubAck packet has no packet identifier."); | ||||
} | } | ||||
if (!packet.ConnectReasonCode.HasValue) | |||||
if (!packet.ReasonCode.HasValue) | |||||
{ | { | ||||
throw new MqttProtocolViolationException("PubAck packet must contain a connect reason."); | throw new MqttProtocolViolationException("PubAck packet must contain a connect reason."); | ||||
} | } | ||||
packetWriter.Write(packet.PacketIdentifier.Value); | packetWriter.Write(packet.PacketIdentifier.Value); | ||||
packetWriter.Write((byte)packet.ConnectReasonCode.Value); | |||||
packetWriter.Write((byte)packet.ReasonCode.Value); | |||||
return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubAck); | return MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.PubAck); | ||||
} | } | ||||
@@ -1,4 +1,5 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | |||||
using MQTTnet.Formatter.V311; | using MQTTnet.Formatter.V311; | ||||
using MQTTnet.Packets; | using MQTTnet.Packets; | ||||
@@ -22,7 +23,7 @@ namespace MQTTnet.Formatter.V500 | |||||
Dup = false, | Dup = false, | ||||
Properties = new MqttPublishPacketProperties | Properties = new MqttPublishPacketProperties | ||||
{ | { | ||||
UserProperties = applicationMessage.UserProperties | |||||
UserProperties = new List<MqttUserProperty>(applicationMessage.UserProperties) | |||||
} | } | ||||
}; | }; | ||||
} | } | ||||
@@ -13,7 +13,7 @@ namespace MQTTnet.Packets | |||||
#region Added in MQTTv5 | #region Added in MQTTv5 | ||||
public MqttConnectReasonCode? ConnectReasonCode { get; set; } | |||||
public MqttConnectReasonCode? ReasonCode { get; set; } | |||||
public MqttConnAckPacketProperties Properties { get; set; } | public MqttConnAckPacketProperties Properties { get; set; } | ||||
@@ -21,7 +21,7 @@ namespace MQTTnet.Packets | |||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
return "ConnAck: [ConnectReturnCode=" + ConnectReturnCode + "] [IsSessionPresent=" + IsSessionPresent + "]"; | |||||
return string.Concat("ConnAck: [ConnectReturnCode=", ConnectReturnCode, "] [ReasonCode=", ReasonCode, "] [IsSessionPresent=", IsSessionPresent, "]"); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -29,7 +29,7 @@ | |||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
return "Connect: [ProtocolLevel=" + ProtocolLevel + "] [ClientId=" + ClientId + "] [Username=" + Username + "] [Password=" + Password + "] [KeepAlivePeriod=" + KeepAlivePeriod + "] [CleanSession=" + CleanSession + "]"; | |||||
return string.Concat("Connect: [ProtocolLevel=", ProtocolLevel, "] [ClientId=", ClientId, "] [Username=", Username, "] [Password=", Password, "] [KeepAlivePeriod=", KeepAlivePeriod, "] [CleanSession=", CleanSession, "]"); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -6,7 +6,7 @@ namespace MQTTnet.Packets | |||||
{ | { | ||||
#region Added in MQTTv5 | #region Added in MQTTv5 | ||||
public MqttPubAckReasonCode? ConnectReasonCode { get; set; } | |||||
public MqttPubAckReasonCode? ReasonCode { get; set; } | |||||
public MqttPubAckPacketProperties Properties { get; set; } | public MqttPubAckPacketProperties Properties { get; set; } | ||||
@@ -14,7 +14,7 @@ namespace MQTTnet.Packets | |||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
return $"PubAck: [PacketIdentifier={PacketIdentifier}] [ConnectReasonCode={ConnectReasonCode}]"; | |||||
return string.Concat("PubAck: [PacketIdentifier=", PacketIdentifier, "] [ConnectReasonCode=", ReasonCode, "]"); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -1,10 +1,20 @@ | |||||
namespace MQTTnet.Packets | |||||
using MQTTnet.Protocol; | |||||
namespace MQTTnet.Packets | |||||
{ | { | ||||
public class MqttPubCompPacket : MqttBasePublishPacket | public class MqttPubCompPacket : MqttBasePublishPacket | ||||
{ | { | ||||
#region Added in MQTTv5 | |||||
public MqttPubCompReasonCode? ReasonCode { get; set; } | |||||
public MqttPubCompPacketProperties Properties { get; set; } | |||||
#endregion | |||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
return "PubComp"; | |||||
return string.Concat("PubComp: [PacketIdentifier=", PacketIdentifier, "] [ReasonCode=", ReasonCode, "]"); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -0,0 +1,11 @@ | |||||
using System.Collections.Generic; | |||||
namespace MQTTnet.Packets | |||||
{ | |||||
public class MqttPubCompPacketProperties | |||||
{ | |||||
public string ReasonString { get; set; } | |||||
public List<MqttUserProperty> UserProperties { get; set; } | |||||
} | |||||
} |
@@ -1,10 +1,20 @@ | |||||
namespace MQTTnet.Packets | |||||
using MQTTnet.Protocol; | |||||
namespace MQTTnet.Packets | |||||
{ | { | ||||
public class MqttPubRecPacket : MqttBasePublishPacket | public class MqttPubRecPacket : MqttBasePublishPacket | ||||
{ | { | ||||
#region Added in MQTTv5 | |||||
public MqttPubRecReasonCode? ReasonCode { get; set; } | |||||
public MqttPubRecPacketProperties Properties { get; set; } | |||||
#endregion | |||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
return "PubRec"; | |||||
return string.Concat("PubRec: [PacketIdentifier=", PacketIdentifier, "] [ReasonCode=", ReasonCode, "]"); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -0,0 +1,11 @@ | |||||
using System.Collections.Generic; | |||||
namespace MQTTnet.Packets | |||||
{ | |||||
public class MqttPubRecPacketProperties | |||||
{ | |||||
public string ReasonString { get; set; } | |||||
public List<MqttUserProperty> UserProperties { get; set; } | |||||
} | |||||
} |
@@ -1,10 +1,20 @@ | |||||
namespace MQTTnet.Packets | |||||
using MQTTnet.Protocol; | |||||
namespace MQTTnet.Packets | |||||
{ | { | ||||
public class MqttPubRelPacket : MqttBasePublishPacket | public class MqttPubRelPacket : MqttBasePublishPacket | ||||
{ | { | ||||
#region Added in MQTTv5 | |||||
public MqttPubRelReasonCode? ReasonCode { get; set; } | |||||
public MqttPubRelPacketProperties Properties { get; set; } | |||||
#endregion | |||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
return "PubRel"; | |||||
return string.Concat("PubRel: [PacketIdentifier=", PacketIdentifier, "] [ReasonCode=", ReasonCode, "]"); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -0,0 +1,11 @@ | |||||
using System.Collections.Generic; | |||||
namespace MQTTnet.Packets | |||||
{ | |||||
public class MqttPubRelPacketProperties | |||||
{ | |||||
public string ReasonString { get; set; } | |||||
public List<MqttUserProperty> UserProperties { get; set; } | |||||
} | |||||
} |
@@ -15,19 +15,14 @@ namespace MQTTnet.Packets | |||||
public byte[] Payload { get; set; } | public byte[] Payload { get; set; } | ||||
#region Added in MQTTv5 | #region Added in MQTTv5 | ||||
public MqttPublishPacketProperties Properties { get; set; } | public MqttPublishPacketProperties Properties { get; set; } | ||||
#endregion | #endregion | ||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
return "Publish: [Topic=" + Topic + "]" + | |||||
" [Payload.Length=" + Payload?.Length + "]" + | |||||
" [QoSLevel=" + QualityOfServiceLevel + "]" + | |||||
" [Dup=" + Dup + "]" + | |||||
" [Retain=" + Retain + "]" + | |||||
" [PacketIdentifier=" + PacketIdentifier + "]"; | |||||
return string.Concat("Publish: [Topic=", Topic, "] [Payload.Length=", Payload?.Length, "] [QoSLevel=", QualityOfServiceLevel, "] [Dup=", Dup, "] [Retain=", Retain, "] [PacketIdentifier=", PacketIdentifier, "]"); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -8,12 +8,20 @@ namespace MQTTnet.Packets | |||||
{ | { | ||||
public ushort? PacketIdentifier { get; set; } | public ushort? PacketIdentifier { get; set; } | ||||
public IList<MqttSubscribeReturnCode> SubscribeReturnCodes { get; } = new List<MqttSubscribeReturnCode>(); | |||||
public List<MqttSubscribeReturnCode> SubscribeReturnCodes { get; } = new List<MqttSubscribeReturnCode>(); | |||||
#region Added in MQTTv5 | |||||
public List<MqttSubscribeReasonCode?> ReasonCodes { get; set; } | |||||
public MqttSubAckPacketProperties Properties { get; set; } | |||||
#endregion | |||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
var subscribeReturnCodesText = string.Join(",", SubscribeReturnCodes.Select(f => f.ToString())); | var subscribeReturnCodesText = string.Join(",", SubscribeReturnCodes.Select(f => f.ToString())); | ||||
return "SubAck: [PacketIdentifier=" + PacketIdentifier + "] [SubscribeReturnCodes=" + subscribeReturnCodesText + "]"; | |||||
return string.Concat("SubAck: [PacketIdentifier=", PacketIdentifier, "] [SubscribeReturnCodes=", subscribeReturnCodesText, "]"); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -0,0 +1,11 @@ | |||||
using System.Collections.Generic; | |||||
namespace MQTTnet.Packets | |||||
{ | |||||
public class MqttSubAckPacketProperties | |||||
{ | |||||
public string ReasonString { get; set; } | |||||
public List<MqttUserProperty> UserProperties { get; set; } | |||||
} | |||||
} |
@@ -9,10 +9,16 @@ namespace MQTTnet.Packets | |||||
public IList<TopicFilter> TopicFilters { get; set; } = new List<TopicFilter>(); | public IList<TopicFilter> TopicFilters { get; set; } = new List<TopicFilter>(); | ||||
#region Added in MQTTv5 | |||||
public MqttSubscribePacketProperties Properties { get; set; } | |||||
#endregion | |||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
var topicFiltersText = string.Join(",", TopicFilters.Select(f => f.Topic + "@" + f.QualityOfServiceLevel)); | var topicFiltersText = string.Join(",", TopicFilters.Select(f => f.Topic + "@" + f.QualityOfServiceLevel)); | ||||
return "Subscribe: [PacketIdentifier=" + PacketIdentifier + "] [TopicFilters=" + topicFiltersText + "]"; | |||||
return string.Concat("Subscribe: [PacketIdentifier=", PacketIdentifier, "] [TopicFilters=", topicFiltersText, "]"); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -0,0 +1,11 @@ | |||||
using System.Collections.Generic; | |||||
namespace MQTTnet.Packets | |||||
{ | |||||
public class MqttSubscribePacketProperties | |||||
{ | |||||
public uint? SubscriptionIdentifier { get; set; } | |||||
public List<MqttUserProperty> UserProperties { get; set; } | |||||
} | |||||
} |
@@ -6,7 +6,7 @@ | |||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
return "UnsubAck: [PacketIdentifier=" + PacketIdentifier + "]"; | |||||
return string.Concat("UnsubAck: [PacketIdentifier=", PacketIdentifier, "]"); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -11,7 +11,7 @@ namespace MQTTnet.Packets | |||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
var topicFiltersText = string.Join(",", TopicFilters); | var topicFiltersText = string.Join(",", TopicFilters); | ||||
return "Unsubscribe: [PacketIdentifier=" + PacketIdentifier + "] [TopicFilters=" + topicFiltersText + "]"; | |||||
return string.Concat("Unsubscribe: [PacketIdentifier=", PacketIdentifier, "] [TopicFilters=", topicFiltersText, "]"); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -0,0 +1,8 @@ | |||||
namespace MQTTnet.Protocol | |||||
{ | |||||
public enum MqttPubCompReasonCode | |||||
{ | |||||
Success = 0, | |||||
PacketIdentifierNotFound = 146 | |||||
} | |||||
} |
@@ -0,0 +1,15 @@ | |||||
namespace MQTTnet.Protocol | |||||
{ | |||||
public enum MqttPubRecReasonCode | |||||
{ | |||||
Success = 0, | |||||
NoMatchingSubscribers = 16, | |||||
UnspecifiedError = 128, | |||||
ImplementationSpecificError = 131, | |||||
NotAuthorized = 135, | |||||
TopicNameInvalid = 144, | |||||
PacketIdentifierInUse = 145, | |||||
QuotaExceeded = 151, | |||||
PayloadFormatInvalid = 153 | |||||
} | |||||
} |
@@ -0,0 +1,8 @@ | |||||
namespace MQTTnet.Protocol | |||||
{ | |||||
public enum MqttPubRelReasonCode | |||||
{ | |||||
Success = 0, | |||||
PacketIdentifierNotFound = 146 | |||||
} | |||||
} |
@@ -0,0 +1,9 @@ | |||||
namespace MQTTnet.Protocol | |||||
{ | |||||
public enum MqttRetainHandling | |||||
{ | |||||
SendAtSubscribe = 0, | |||||
SendAtSubscribeIfNewSubscriptionOnly = 1, | |||||
DoNotSendOnSubscribe = 2 | |||||
} | |||||
} |
@@ -0,0 +1,18 @@ | |||||
namespace MQTTnet.Protocol | |||||
{ | |||||
public enum MqttSubscribeReasonCode | |||||
{ | |||||
GrantedQoS0 = 0, | |||||
GrantedQoS1 = 1, | |||||
GrantedQoS2 = 2, | |||||
UnspecifiedError = 128, | |||||
ImplementationSpecificError = 131, | |||||
NotAuthorized = 135, | |||||
TopicFilterInvalid = 143, | |||||
PacketIdentifierInUse = 145, | |||||
QuotaExceeded = 151, | |||||
SharedSubscriptionsNotSupported = 158, | |||||
SubscriptionIdentifiersNotSupported = 161, | |||||
WildcardSubscriptionsNotSupported = 162 | |||||
} | |||||
} |
@@ -14,6 +14,25 @@ namespace MQTTnet | |||||
public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; } | public MqttQualityOfServiceLevel QualityOfServiceLevel { get; set; } | ||||
#region Added in MQTTv5 | |||||
/// <summary> | |||||
/// This is only available when using MQTT version 5. | |||||
/// </summary> | |||||
public bool? NoLocal { get; set; } | |||||
/// <summary> | |||||
/// This is only available when using MQTT version 5. | |||||
/// </summary> | |||||
public bool? RetainAsPublished { get; set; } | |||||
/// <summary> | |||||
/// This is only available when using MQTT version 5. | |||||
/// </summary> | |||||
public MqttRetainHandling? RetainHandling { get; set; } | |||||
#endregion | |||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
return Topic + "@" + QualityOfServiceLevel; | return Topic + "@" + QualityOfServiceLevel; | ||||