From 981ea021491b4bc11dfec815c1dffeded40b5b3b Mon Sep 17 00:00:00 2001 From: Victornor <1-1@hotmail.dk> Date: Tue, 10 Dec 2024 19:37:29 +0100 Subject: [PATCH 1/2] Unused parameter in WithTryPrivate causing client to send incorrect version byte in header. (#2125) * fix: unused tryPrivate parameter in WithTryPrivate * Fix wrong usage of try private --------- Co-authored-by: christian <6939810+chkr1011@users.noreply.github.com> --- .../Formatter/V3/MqttV3PacketFormatter.cs | 37 +++++++++---------- Source/MQTTnet/Options/MqttClientOptions.cs | 2 +- .../Options/MqttClientOptionsBuilder.cs | 4 +- .../Options/MqttClientOptionsValidator.cs | 6 ++- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/Source/MQTTnet/Formatter/V3/MqttV3PacketFormatter.cs b/Source/MQTTnet/Formatter/V3/MqttV3PacketFormatter.cs index 5e5a2f150..20dd59f49 100644 --- a/Source/MQTTnet/Formatter/V3/MqttV3PacketFormatter.cs +++ b/Source/MQTTnet/Formatter/V3/MqttV3PacketFormatter.cs @@ -18,9 +18,9 @@ public sealed class MqttV3PacketFormatter : IMqttPacketFormatter { const int FixedHeaderSize = 1; - static readonly MqttDisconnectPacket DisconnectPacket = new MqttDisconnectPacket(); + static readonly MqttDisconnectPacket DisconnectPacket = new(); - readonly MqttBufferReader _bufferReader = new MqttBufferReader(); + readonly MqttBufferReader _bufferReader = new(); readonly MqttBufferWriter _bufferWriter; readonly MqttProtocolVersion _mqttProtocolVersion; @@ -68,10 +68,8 @@ public MqttPacket Decode(ReceivedMqttPacket receivedMqttPacket) { return DecodeConnAckPacketV311(receivedMqttPacket.Body); } - else - { - return DecodeConnAckPacket(receivedMqttPacket.Body); - } + + return DecodeConnAckPacket(receivedMqttPacket.Body); case MqttControlPacketType.Disconnect: return DisconnectPacket; @@ -106,10 +104,6 @@ public MqttPacketBuffer Encode(MqttPacket packet) payload = publishPacket.Payload; remainingLength += (uint)payload.Length; } - else - { - publishPacket = null; - } var remainingLengthSize = MqttBufferWriter.GetVariableByteIntegerSize(remainingLength); @@ -481,7 +475,16 @@ byte EncodeConnectPacketV311(MqttConnectPacket packet, MqttBufferWriter bufferWr ValidateConnectPacket(packet); bufferWriter.WriteString("MQTT"); - bufferWriter.WriteByte(4); // 3.1.2.2 Protocol Level 4 + + // 3.1.2.2 Protocol Level 4 + var protocolVersion = 4; + + if (packet.TryPrivate) + { + protocolVersion |= 0x80; + } + + bufferWriter.WriteByte((byte)protocolVersion); byte connectFlags = 0x0; if (packet.CleanSession) @@ -552,19 +555,15 @@ byte EncodePacket(MqttPacket packet, MqttBufferWriter bufferWriter) { return EncodeConnectPacketV311(connectPacket, bufferWriter); } - else - { - return EncodeConnectPacket(connectPacket, bufferWriter); - } + + return EncodeConnectPacket(connectPacket, bufferWriter); case MqttConnAckPacket connAckPacket: if (_mqttProtocolVersion == MqttProtocolVersion.V311) { return EncodeConnAckPacketV311(connAckPacket, bufferWriter); } - else - { - return EncodeConnAckPacket(connAckPacket, bufferWriter); - } + + return EncodeConnAckPacket(connAckPacket, bufferWriter); case MqttDisconnectPacket _: return EncodeEmptyPacket(MqttControlPacketType.Disconnect); case MqttPingReqPacket _: diff --git a/Source/MQTTnet/Options/MqttClientOptions.cs b/Source/MQTTnet/Options/MqttClientOptions.cs index d337ea0e8..d17dd0548 100644 --- a/Source/MQTTnet/Options/MqttClientOptions.cs +++ b/Source/MQTTnet/Options/MqttClientOptions.cs @@ -127,7 +127,7 @@ public sealed class MqttClientOptions /// connect properly. /// /// - public bool TryPrivate { get; set; } = true; + public bool TryPrivate { get; set; } // Implementation in Mosquitto: https://github.com/eclipse-mosquitto/mosquitto/blob/3cbe805e71ac41a2a20cc9b2ea6b3b619f49554a/lib/send_connect.c#L153 /// /// Gets or sets the user properties. diff --git a/Source/MQTTnet/Options/MqttClientOptionsBuilder.cs b/Source/MQTTnet/Options/MqttClientOptionsBuilder.cs index a4dedff97..b1e14a797 100644 --- a/Source/MQTTnet/Options/MqttClientOptionsBuilder.cs +++ b/Source/MQTTnet/Options/MqttClientOptionsBuilder.cs @@ -361,9 +361,9 @@ public MqttClientOptionsBuilder WithTopicAliasMaximum(ushort topicAliasMaximum) /// Not all brokers support this feature so it may be necessary to set it to false if your bridge does not connect /// properly. /// - public MqttClientOptionsBuilder WithTryPrivate(bool tryPrivate = true) + public MqttClientOptionsBuilder WithTryPrivate(bool value = true) { - _options.TryPrivate = true; + _options.TryPrivate = value; return this; } diff --git a/Source/MQTTnet/Options/MqttClientOptionsValidator.cs b/Source/MQTTnet/Options/MqttClientOptionsValidator.cs index 6e9c09f9b..19b2c91c3 100644 --- a/Source/MQTTnet/Options/MqttClientOptionsValidator.cs +++ b/Source/MQTTnet/Options/MqttClientOptionsValidator.cs @@ -17,7 +17,11 @@ public static void ThrowIfNotSupported(MqttClientOptions options) if (options.ProtocolVersion == MqttProtocolVersion.V500) { - // Everything is supported. + if (options.TryPrivate) + { + throw new NotSupportedException("Feature TryPrivate only works with MQTT version 3.1 and 3.1.1."); + } + return; } From e2f8d0f0ac15b01eeebdef3821df3a5a46560641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E4=B9=9D?= <366193849@qq.com> Date: Wed, 11 Dec 2024 02:44:38 +0800 Subject: [PATCH 2/2] Added UserName property to various Server EventArgs. (#2123) * Added UserName property to various Server EventArgs. * InjectedMqttApplicationMessage: Add SenderUserName property. * Reformat code * Reformat code --------- Co-authored-by: christian <6939810+chkr1011@users.noreply.github.com> --- ...ClientAcknowledgedPublishPacketEventArgs.cs | 8 +++++++- .../Events/ClientConnectedEventArgs.cs | 6 ++++++ .../Events/ClientDisconnectedEventArgs.cs | 18 +++++++++++++++--- .../Events/ClientSubscribedTopicEventArgs.cs | 8 +++++++- .../Events/ClientUnsubscribedTopicEventArgs.cs | 8 +++++++- .../Events/InterceptingPacketEventArgs.cs | 8 +++++++- .../Events/InterceptingPublishEventArgs.cs | 8 +++++++- .../InterceptingSubscriptionEventArgs.cs | 7 +++++++ .../InterceptingUnsubscriptionEventArgs.cs | 8 +++++++- .../Events/SessionDeletedEventArgs.cs | 8 +++++++- .../InjectedMqttApplicationMessage.cs | 2 ++ .../Internal/MqttClientSessionsManager.cs | 14 ++++++++++---- .../Internal/MqttClientSubscriptionsManager.cs | 8 ++++---- .../Internal/MqttConnectedClient.cs | 13 ++++++++----- Source/MQTTnet.Server/Internal/MqttSession.cs | 2 ++ Source/MQTTnet.Server/MqttServer.cs | 1 + Source/MQTTnet.Tests/Server/Events_Tests.cs | 17 ++++++++++++----- 17 files changed, 116 insertions(+), 28 deletions(-) diff --git a/Source/MQTTnet.Server/Events/ClientAcknowledgedPublishPacketEventArgs.cs b/Source/MQTTnet.Server/Events/ClientAcknowledgedPublishPacketEventArgs.cs index 5b126060c..8a206cc2f 100644 --- a/Source/MQTTnet.Server/Events/ClientAcknowledgedPublishPacketEventArgs.cs +++ b/Source/MQTTnet.Server/Events/ClientAcknowledgedPublishPacketEventArgs.cs @@ -10,9 +10,10 @@ namespace MQTTnet.Server { public sealed class ClientAcknowledgedPublishPacketEventArgs : EventArgs { - public ClientAcknowledgedPublishPacketEventArgs(string clientId, IDictionary sessionItems, MqttPublishPacket publishPacket, MqttPacketWithIdentifier acknowledgePacket) + public ClientAcknowledgedPublishPacketEventArgs(string clientId, string userName, IDictionary sessionItems, MqttPublishPacket publishPacket, MqttPacketWithIdentifier acknowledgePacket) { ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId)); + UserName = userName; SessionItems = sessionItems ?? throw new ArgumentNullException(nameof(sessionItems)); PublishPacket = publishPacket ?? throw new ArgumentNullException(nameof(publishPacket)); AcknowledgePacket = acknowledgePacket ?? throw new ArgumentNullException(nameof(acknowledgePacket)); @@ -28,6 +29,11 @@ public ClientAcknowledgedPublishPacketEventArgs(string clientId, IDictionary ses /// public string ClientId { get; } + /// + /// Gets the user name of the client. + /// + public string UserName { get; } + /// /// Gets whether the PUBLISH packet is fully acknowledged. This is the case for PUBACK (QoS 1) and PUBCOMP (QoS 2. /// diff --git a/Source/MQTTnet.Server/Events/ClientConnectedEventArgs.cs b/Source/MQTTnet.Server/Events/ClientConnectedEventArgs.cs index 27701db6f..4249eea6f 100644 --- a/Source/MQTTnet.Server/Events/ClientConnectedEventArgs.cs +++ b/Source/MQTTnet.Server/Events/ClientConnectedEventArgs.cs @@ -6,6 +6,7 @@ using System.Collections; using System.Collections.Generic; using System.Net; +using System.Text; using MQTTnet.Formatter; using MQTTnet.Packets; @@ -56,6 +57,11 @@ public ClientConnectedEventArgs(MqttConnectPacket connectPacket, MqttProtocolVer /// public string UserName => _connectPacket.Username; + /// + /// Gets the password of the connected client. + /// + public string Password => Encoding.UTF8.GetString(_connectPacket.Password.AsSpan()); + /// /// Gets the user properties sent by the client. /// MQTT 5.0.0+ feature. diff --git a/Source/MQTTnet.Server/Events/ClientDisconnectedEventArgs.cs b/Source/MQTTnet.Server/Events/ClientDisconnectedEventArgs.cs index b552e4e96..f64a2f3bd 100644 --- a/Source/MQTTnet.Server/Events/ClientDisconnectedEventArgs.cs +++ b/Source/MQTTnet.Server/Events/ClientDisconnectedEventArgs.cs @@ -6,6 +6,7 @@ using System.Collections; using System.Collections.Generic; using System.Net; +using System.Text; using MQTTnet.Packets; using MQTTnet.Protocol; @@ -13,20 +14,21 @@ namespace MQTTnet.Server { public sealed class ClientDisconnectedEventArgs : EventArgs { + readonly MqttConnectPacket _connectPacket; readonly MqttDisconnectPacket _disconnectPacket; public ClientDisconnectedEventArgs( - string clientId, + MqttConnectPacket connectPacket, MqttDisconnectPacket disconnectPacket, MqttClientDisconnectType disconnectType, EndPoint remoteEndPoint, IDictionary sessionItems) { - ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId)); DisconnectType = disconnectType; RemoteEndPoint = remoteEndPoint; SessionItems = sessionItems ?? throw new ArgumentNullException(nameof(sessionItems)); + _connectPacket = connectPacket; // The DISCONNECT packet can be null in case of a non clean disconnect or session takeover. _disconnectPacket = disconnectPacket; } @@ -35,7 +37,17 @@ public ClientDisconnectedEventArgs( /// Gets the client identifier. /// Hint: This identifier needs to be unique over all used clients / devices on the broker to avoid connection issues. /// - public string ClientId { get; } + public string ClientId => _connectPacket.ClientId; + + /// + /// Gets the user name of the client. + /// + public string UserName => _connectPacket.Username; + + /// + /// Gets the password of the client. + /// + public string Password => Encoding.UTF8.GetString(_connectPacket.Password.AsSpan()); public MqttClientDisconnectType DisconnectType { get; } diff --git a/Source/MQTTnet.Server/Events/ClientSubscribedTopicEventArgs.cs b/Source/MQTTnet.Server/Events/ClientSubscribedTopicEventArgs.cs index 639ad98e3..2f5246835 100644 --- a/Source/MQTTnet.Server/Events/ClientSubscribedTopicEventArgs.cs +++ b/Source/MQTTnet.Server/Events/ClientSubscribedTopicEventArgs.cs @@ -10,9 +10,10 @@ namespace MQTTnet.Server { public sealed class ClientSubscribedTopicEventArgs : EventArgs { - public ClientSubscribedTopicEventArgs(string clientId, MqttTopicFilter topicFilter, IDictionary sessionItems) + public ClientSubscribedTopicEventArgs(string clientId, string userName, MqttTopicFilter topicFilter, IDictionary sessionItems) { ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId)); + UserName = userName; TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter)); SessionItems = sessionItems ?? throw new ArgumentNullException(nameof(sessionItems)); } @@ -23,6 +24,11 @@ public ClientSubscribedTopicEventArgs(string clientId, MqttTopicFilter topicFilt /// public string ClientId { get; } + /// + /// Gets the user name of the client. + /// + public string UserName { get; } + /// /// Gets or sets a key/value collection that can be used to share data within the scope of this session. /// diff --git a/Source/MQTTnet.Server/Events/ClientUnsubscribedTopicEventArgs.cs b/Source/MQTTnet.Server/Events/ClientUnsubscribedTopicEventArgs.cs index d521b857e..677236b37 100644 --- a/Source/MQTTnet.Server/Events/ClientUnsubscribedTopicEventArgs.cs +++ b/Source/MQTTnet.Server/Events/ClientUnsubscribedTopicEventArgs.cs @@ -9,9 +9,10 @@ namespace MQTTnet.Server { public sealed class ClientUnsubscribedTopicEventArgs : EventArgs { - public ClientUnsubscribedTopicEventArgs(string clientId, string topicFilter, IDictionary sessionItems) + public ClientUnsubscribedTopicEventArgs(string clientId, string userName, string topicFilter, IDictionary sessionItems) { ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId)); + UserName = userName; TopicFilter = topicFilter ?? throw new ArgumentNullException(nameof(topicFilter)); SessionItems = sessionItems ?? throw new ArgumentNullException(nameof(sessionItems)); } @@ -22,6 +23,11 @@ public ClientUnsubscribedTopicEventArgs(string clientId, string topicFilter, IDi /// public string ClientId { get; } + /// + /// Gets the user name of the client. + /// + public string UserName { get; } + /// /// Gets or sets a key/value collection that can be used to share data within the scope of this session. /// diff --git a/Source/MQTTnet.Server/Events/InterceptingPacketEventArgs.cs b/Source/MQTTnet.Server/Events/InterceptingPacketEventArgs.cs index 0b1eef2e8..6067a17e4 100644 --- a/Source/MQTTnet.Server/Events/InterceptingPacketEventArgs.cs +++ b/Source/MQTTnet.Server/Events/InterceptingPacketEventArgs.cs @@ -12,10 +12,11 @@ namespace MQTTnet.Server { public sealed class InterceptingPacketEventArgs : EventArgs { - public InterceptingPacketEventArgs(CancellationToken cancellationToken, string clientId, EndPoint remoteEndPoint, MqttPacket packet, IDictionary sessionItems) + public InterceptingPacketEventArgs(CancellationToken cancellationToken, string clientId, string userName, EndPoint remoteEndPoint, MqttPacket packet, IDictionary sessionItems) { CancellationToken = cancellationToken; ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId)); + UserName = userName; RemoteEndPoint = remoteEndPoint; Packet = packet ?? throw new ArgumentNullException(nameof(packet)); SessionItems = sessionItems; @@ -32,6 +33,11 @@ public InterceptingPacketEventArgs(CancellationToken cancellationToken, string c /// public string ClientId { get; } + /// + /// Gets the user name of the client. + /// + public string UserName { get; } + /// /// Gets the endpoint of the sending or receiving client. /// diff --git a/Source/MQTTnet.Server/Events/InterceptingPublishEventArgs.cs b/Source/MQTTnet.Server/Events/InterceptingPublishEventArgs.cs index 34b12b565..b20961049 100644 --- a/Source/MQTTnet.Server/Events/InterceptingPublishEventArgs.cs +++ b/Source/MQTTnet.Server/Events/InterceptingPublishEventArgs.cs @@ -10,11 +10,12 @@ namespace MQTTnet.Server { public sealed class InterceptingPublishEventArgs : EventArgs { - public InterceptingPublishEventArgs(MqttApplicationMessage applicationMessage, CancellationToken cancellationToken, string clientId, IDictionary sessionItems) + public InterceptingPublishEventArgs(MqttApplicationMessage applicationMessage, CancellationToken cancellationToken, string clientId, string userName, IDictionary sessionItems) { ApplicationMessage = applicationMessage ?? throw new ArgumentNullException(nameof(applicationMessage)); CancellationToken = cancellationToken; ClientId = clientId ?? throw new ArgumentNullException(nameof(clientId)); + UserName = userName; SessionItems = sessionItems ?? throw new ArgumentNullException(nameof(sessionItems)); } @@ -31,6 +32,11 @@ public InterceptingPublishEventArgs(MqttApplicationMessage applicationMessage, C /// public string ClientId { get; } + /// + /// Gets the user name of the client. + /// + public string UserName { get; } + public bool CloseConnection { get; set; } /// diff --git a/Source/MQTTnet.Server/Events/InterceptingSubscriptionEventArgs.cs b/Source/MQTTnet.Server/Events/InterceptingSubscriptionEventArgs.cs index fa26d13e8..7f62d68e9 100644 --- a/Source/MQTTnet.Server/Events/InterceptingSubscriptionEventArgs.cs +++ b/Source/MQTTnet.Server/Events/InterceptingSubscriptionEventArgs.cs @@ -15,12 +15,14 @@ public sealed class InterceptingSubscriptionEventArgs : EventArgs public InterceptingSubscriptionEventArgs( CancellationToken cancellationToken, string clientId, + string userName, MqttSessionStatus session, MqttTopicFilter topicFilter, List userProperties) { CancellationToken = cancellationToken; ClientId = clientId; + UserName = userName; Session = session; TopicFilter = topicFilter; UserProperties = userProperties; @@ -37,6 +39,11 @@ public InterceptingSubscriptionEventArgs( /// public string ClientId { get; } + /// + /// Gets the user name of the client. + /// + public string UserName { get; } + /// /// Gets or sets whether the broker should close the client connection. /// diff --git a/Source/MQTTnet.Server/Events/InterceptingUnsubscriptionEventArgs.cs b/Source/MQTTnet.Server/Events/InterceptingUnsubscriptionEventArgs.cs index 36d08df3d..5838aadcb 100644 --- a/Source/MQTTnet.Server/Events/InterceptingUnsubscriptionEventArgs.cs +++ b/Source/MQTTnet.Server/Events/InterceptingUnsubscriptionEventArgs.cs @@ -12,10 +12,11 @@ namespace MQTTnet.Server { public sealed class InterceptingUnsubscriptionEventArgs : EventArgs { - public InterceptingUnsubscriptionEventArgs(CancellationToken cancellationToken, string clientId, IDictionary sessionItems, string topic, List userProperties) + public InterceptingUnsubscriptionEventArgs(CancellationToken cancellationToken, string clientId, string userName, IDictionary sessionItems, string topic, List userProperties) { CancellationToken = cancellationToken; ClientId = clientId; + UserName = userName; SessionItems = sessionItems; Topic = topic; UserProperties = userProperties; @@ -32,6 +33,11 @@ public InterceptingUnsubscriptionEventArgs(CancellationToken cancellationToken, /// public string ClientId { get; } + /// + /// Gets the user name of the client. + /// + public string UserName { get; } + /// /// Gets or sets whether the broker should close the client connection. /// diff --git a/Source/MQTTnet.Server/Events/SessionDeletedEventArgs.cs b/Source/MQTTnet.Server/Events/SessionDeletedEventArgs.cs index 3d27036c7..dd9037239 100644 --- a/Source/MQTTnet.Server/Events/SessionDeletedEventArgs.cs +++ b/Source/MQTTnet.Server/Events/SessionDeletedEventArgs.cs @@ -9,9 +9,10 @@ namespace MQTTnet.Server { public sealed class SessionDeletedEventArgs : EventArgs { - public SessionDeletedEventArgs(string id, IDictionary sessionItems) + public SessionDeletedEventArgs(string id, string userName, IDictionary sessionItems) { Id = id ?? throw new ArgumentNullException(nameof(id)); + UserName = userName; SessionItems = sessionItems ?? throw new ArgumentNullException(nameof(sessionItems)); } @@ -20,6 +21,11 @@ public SessionDeletedEventArgs(string id, IDictionary sessionItems) /// public string Id { get; } + /// + /// Gets the user name of the session. + /// + public string UserName { get; } + /// /// Gets or sets a key/value collection that can be used to share data within the scope of this session. /// diff --git a/Source/MQTTnet.Server/InjectedMqttApplicationMessage.cs b/Source/MQTTnet.Server/InjectedMqttApplicationMessage.cs index 3a9add06a..56929dd42 100644 --- a/Source/MQTTnet.Server/InjectedMqttApplicationMessage.cs +++ b/Source/MQTTnet.Server/InjectedMqttApplicationMessage.cs @@ -23,4 +23,6 @@ public InjectedMqttApplicationMessage(MqttApplicationMessage applicationMessage) public IDictionary CustomSessionItems { get; set; } public string SenderClientId { get; set; } = string.Empty; + + public string SenderUserName { get; set; } } \ No newline at end of file diff --git a/Source/MQTTnet.Server/Internal/MqttClientSessionsManager.cs b/Source/MQTTnet.Server/Internal/MqttClientSessionsManager.cs index 67728a8d3..b99fa8e03 100644 --- a/Source/MQTTnet.Server/Internal/MqttClientSessionsManager.cs +++ b/Source/MQTTnet.Server/Internal/MqttClientSessionsManager.cs @@ -101,7 +101,7 @@ public async Task DeleteSessionAsync(string clientId) { if (_eventContainer.SessionDeletedEvent.HasHandlers && session != null) { - var eventArgs = new SessionDeletedEventArgs(clientId, session.Items); + var eventArgs = new SessionDeletedEventArgs(clientId, session.UserName, session.Items); await _eventContainer.SessionDeletedEvent.TryInvokeAsync(eventArgs, _logger).ConfigureAwait(false); } } @@ -117,6 +117,7 @@ public async Task DeleteSessionAsync(string clientId) public async Task DispatchApplicationMessage( string senderId, + string senderUserName, IDictionary senderSessionItems, MqttApplicationMessage applicationMessage, CancellationToken cancellationToken) @@ -130,7 +131,7 @@ public async Task DispatchApplicationMessage( // Allow the user to intercept application message... if (_eventContainer.InterceptingPublishEvent.HasHandlers) { - var interceptingPublishEventArgs = new InterceptingPublishEventArgs(applicationMessage, cancellationToken, senderId, senderSessionItems); + var interceptingPublishEventArgs = new InterceptingPublishEventArgs(applicationMessage, cancellationToken, senderId, senderUserName, senderSessionItems); if (string.IsNullOrEmpty(interceptingPublishEventArgs.ApplicationMessage.Topic)) { // This can happen if a topic alias us used but the topic is @@ -408,7 +409,12 @@ public async Task HandleClientConnectionAsync(IMqttChannelAdapter channelAdapter if (connectedClient.Id != null && !connectedClient.IsTakenOver && _eventContainer.ClientDisconnectedEvent.HasHandlers) { var disconnectType = connectedClient.DisconnectPacket != null ? MqttClientDisconnectType.Clean : MqttClientDisconnectType.NotClean; - var eventArgs = new ClientDisconnectedEventArgs(connectedClient.Id, connectedClient.DisconnectPacket, disconnectType, endpoint, connectedClient.Session.Items); + var eventArgs = new ClientDisconnectedEventArgs( + connectedClient.ConnectPacket, + connectedClient.DisconnectPacket, + disconnectType, + endpoint, + connectedClient.Session.Items); await _eventContainer.ClientDisconnectedEvent.InvokeAsync(eventArgs).ConfigureAwait(false); } @@ -592,7 +598,7 @@ async Task CreateClientConnection( if (_eventContainer.ClientDisconnectedEvent.HasHandlers) { var eventArgs = new ClientDisconnectedEventArgs( - oldConnectedClient.Id, + oldConnectedClient.ConnectPacket, null, MqttClientDisconnectType.Takeover, oldConnectedClient.RemoteEndPoint, diff --git a/Source/MQTTnet.Server/Internal/MqttClientSubscriptionsManager.cs b/Source/MQTTnet.Server/Internal/MqttClientSubscriptionsManager.cs index 4413755ad..7c1023e52 100644 --- a/Source/MQTTnet.Server/Internal/MqttClientSubscriptionsManager.cs +++ b/Source/MQTTnet.Server/Internal/MqttClientSubscriptionsManager.cs @@ -209,7 +209,7 @@ public async Task Subscribe(MqttSubscribePacket subscribePacket { foreach (var finalTopicFilter in finalTopicFilters) { - var eventArgs = new ClientSubscribedTopicEventArgs(_session.Id, finalTopicFilter, _session.Items); + var eventArgs = new ClientSubscribedTopicEventArgs(_session.Id, _session.UserName, finalTopicFilter, _session.Items); await _eventContainer.ClientSubscribedTopicEvent.InvokeAsync(eventArgs).ConfigureAwait(false); } } @@ -297,7 +297,7 @@ public async Task Unsubscribe(MqttUnsubscribePacket unsubscri { foreach (var topicFilter in unsubscribePacket.TopicFilters) { - var eventArgs = new ClientUnsubscribedTopicEventArgs(_session.Id, topicFilter, _session.Items); + var eventArgs = new ClientUnsubscribedTopicEventArgs(_session.Id, _session.UserName, topicFilter, _session.Items); await _eventContainer.ClientUnsubscribedTopicEvent.InvokeAsync(eventArgs).ConfigureAwait(false); } } @@ -460,7 +460,7 @@ async Task InterceptSubscribe( List userProperties, CancellationToken cancellationToken) { - var eventArgs = new InterceptingSubscriptionEventArgs(cancellationToken, _session.Id, new MqttSessionStatus(_session), topicFilter, userProperties); + var eventArgs = new InterceptingSubscriptionEventArgs(cancellationToken, _session.Id, _session.UserName, new MqttSessionStatus(_session), topicFilter, userProperties); if (topicFilter.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce) { @@ -493,7 +493,7 @@ async Task InterceptUnsubscribe( List userProperties, CancellationToken cancellationToken) { - var clientUnsubscribingTopicEventArgs = new InterceptingUnsubscriptionEventArgs(cancellationToken, _session.Id, _session.Items, topicFilter, userProperties) + var clientUnsubscribingTopicEventArgs = new InterceptingUnsubscriptionEventArgs(cancellationToken, _session.Id, _session.UserName, _session.Items, topicFilter, userProperties) { Response = { diff --git a/Source/MQTTnet.Server/Internal/MqttConnectedClient.cs b/Source/MQTTnet.Server/Internal/MqttConnectedClient.cs index 84f26570d..bfdb21307 100644 --- a/Source/MQTTnet.Server/Internal/MqttConnectedClient.cs +++ b/Source/MQTTnet.Server/Internal/MqttConnectedClient.cs @@ -72,6 +72,8 @@ public MqttConnectedClient( public MqttClientStatistics Statistics { get; } = new(); + public string UserName => ConnectPacket.Username; + public void Dispose() { _cancellationToken?.Dispose(); @@ -117,7 +119,7 @@ public async Task RunAsync() var willPublishPacket = MqttPublishPacketFactory.Create(Session.LatestConnectPacket); var willApplicationMessage = MqttApplicationMessageFactory.Create(willPublishPacket); - _ = _sessionsManager.DispatchApplicationMessage(Id, Session.Items, willApplicationMessage, CancellationToken.None); + _ = _sessionsManager.DispatchApplicationMessage(Id, UserName, Session.Items, willApplicationMessage, CancellationToken.None); Session.WillMessageSent = true; _logger.Info("Client '{0}': Published will message", Id); @@ -174,7 +176,7 @@ Task ClientAcknowledgedPublishPacket(MqttPublishPacket publishPacket, MqttPacket { if (_eventContainer.ClientAcknowledgedPublishPacketEvent.HasHandlers) { - var eventArgs = new ClientAcknowledgedPublishPacketEventArgs(Id, Session.Items, publishPacket, acknowledgePacket); + var eventArgs = new ClientAcknowledgedPublishPacketEventArgs(Id, UserName, Session.Items, publishPacket, acknowledgePacket); return _eventContainer.ClientAcknowledgedPublishPacketEvent.TryInvokeAsync(eventArgs, _logger); } @@ -217,7 +219,8 @@ async Task HandleIncomingPublishPacket(MqttPublishPacket publishPacket, Cancella var applicationMessage = MqttApplicationMessageFactory.Create(publishPacket); - var dispatchApplicationMessageResult = await _sessionsManager.DispatchApplicationMessage(Id, Session.Items, applicationMessage, cancellationToken).ConfigureAwait(false); + var dispatchApplicationMessageResult = + await _sessionsManager.DispatchApplicationMessage(Id, UserName, Session.Items, applicationMessage, cancellationToken).ConfigureAwait(false); if (dispatchApplicationMessageResult.CloseConnection) { @@ -339,7 +342,7 @@ async Task InterceptPacketAsync(MqttPacket packet, CancellationToken return packet; } - var interceptingPacketEventArgs = new InterceptingPacketEventArgs(cancellationToken, Id, RemoteEndPoint, packet, Session.Items); + var interceptingPacketEventArgs = new InterceptingPacketEventArgs(cancellationToken, Id, UserName, RemoteEndPoint, packet, Session.Items); await _eventContainer.InterceptingOutboundPacketEvent.InvokeAsync(interceptingPacketEventArgs).ConfigureAwait(false); if (!interceptingPacketEventArgs.ProcessPacket || packet == null) @@ -385,7 +388,7 @@ async Task ReceivePackagesLoop(CancellationToken cancellationToken) if (_eventContainer.InterceptingInboundPacketEvent.HasHandlers) { - var interceptingPacketEventArgs = new InterceptingPacketEventArgs(cancellationToken, Id, RemoteEndPoint, currentPacket, Session.Items); + var interceptingPacketEventArgs = new InterceptingPacketEventArgs(cancellationToken, Id, UserName, RemoteEndPoint, currentPacket, Session.Items); await _eventContainer.InterceptingInboundPacketEvent.InvokeAsync(interceptingPacketEventArgs).ConfigureAwait(false); currentPacket = interceptingPacketEventArgs.Packet; processPacket = interceptingPacketEventArgs.ProcessPacket; diff --git a/Source/MQTTnet.Server/Internal/MqttSession.cs b/Source/MQTTnet.Server/Internal/MqttSession.cs index 0aea7d803..55814b849 100644 --- a/Source/MQTTnet.Server/Internal/MqttSession.cs +++ b/Source/MQTTnet.Server/Internal/MqttSession.cs @@ -53,6 +53,8 @@ public MqttSession( public string Id => _connectPacket.ClientId; + public string UserName => _connectPacket.Username; + public IDictionary Items { get; } public MqttConnectPacket LatestConnectPacket { get; set; } diff --git a/Source/MQTTnet.Server/MqttServer.cs b/Source/MQTTnet.Server/MqttServer.cs index dc30ac93f..f0f423f0e 100644 --- a/Source/MQTTnet.Server/MqttServer.cs +++ b/Source/MQTTnet.Server/MqttServer.cs @@ -255,6 +255,7 @@ public Task InjectApplicationMessage(InjectedMqttApplicationMessage injectedAppl return _clientSessionsManager.DispatchApplicationMessage( injectedApplicationMessage.SenderClientId, + injectedApplicationMessage.SenderUserName, sessionItems, injectedApplicationMessage.ApplicationMessage, cancellationToken); diff --git a/Source/MQTTnet.Tests/Server/Events_Tests.cs b/Source/MQTTnet.Tests/Server/Events_Tests.cs index 415a2a2d2..bce9197ed 100644 --- a/Source/MQTTnet.Tests/Server/Events_Tests.cs +++ b/Source/MQTTnet.Tests/Server/Events_Tests.cs @@ -29,7 +29,7 @@ public async Task Fire_Client_Connected_Event() return CompletedTask.Instance; }; - await testEnvironment.ConnectClient(o => o.WithCredentials("TheUser")); + await testEnvironment.ConnectClient(o => o.WithCredentials("TheUser", "ThePassword")); await LongTestDelay(); @@ -39,6 +39,7 @@ public async Task Fire_Client_Connected_Event() Assert.IsTrue(eventArgs.RemoteEndPoint.ToString().Contains("127.0.0.1")); Assert.AreEqual(MqttProtocolVersion.V311, eventArgs.ProtocolVersion); Assert.AreEqual("TheUser", eventArgs.UserName); + Assert.AreEqual("ThePassword", eventArgs.Password); } } @@ -56,7 +57,7 @@ public async Task Fire_Client_Disconnected_Event() return CompletedTask.Instance; }; - var client = await testEnvironment.ConnectClient(o => o.WithCredentials("TheUser")); + var client = await testEnvironment.ConnectClient(o => o.WithCredentials("TheUser", "ThePassword")); await client.DisconnectAsync(); await LongTestDelay(); @@ -66,6 +67,9 @@ public async Task Fire_Client_Disconnected_Event() Assert.IsTrue(eventArgs.ClientId.StartsWith(nameof(Fire_Client_Disconnected_Event))); Assert.IsTrue(eventArgs.RemoteEndPoint.ToString().Contains("127.0.0.1")); Assert.AreEqual(MqttClientDisconnectType.Clean, eventArgs.DisconnectType); + + Assert.AreEqual("TheUser", eventArgs.UserName); + Assert.AreEqual("ThePassword", eventArgs.Password); } } @@ -83,7 +87,7 @@ public async Task Fire_Client_Subscribed_Event() return CompletedTask.Instance; }; - var client = await testEnvironment.ConnectClient(); + var client = await testEnvironment.ConnectClient(o => o.WithCredentials("TheUser")); await client.SubscribeAsync("The/Topic", MqttQualityOfServiceLevel.AtLeastOnce); await LongTestDelay(); @@ -93,6 +97,7 @@ public async Task Fire_Client_Subscribed_Event() Assert.IsTrue(eventArgs.ClientId.StartsWith(nameof(Fire_Client_Subscribed_Event))); Assert.AreEqual("The/Topic", eventArgs.TopicFilter.Topic); Assert.AreEqual(MqttQualityOfServiceLevel.AtLeastOnce, eventArgs.TopicFilter.QualityOfServiceLevel); + Assert.AreEqual("TheUser", eventArgs.UserName); } } @@ -110,7 +115,7 @@ public async Task Fire_Client_Unsubscribed_Event() return CompletedTask.Instance; }; - var client = await testEnvironment.ConnectClient(); + var client = await testEnvironment.ConnectClient(o => o.WithCredentials("TheUser")); await client.UnsubscribeAsync("The/Topic"); await LongTestDelay(); @@ -119,6 +124,7 @@ public async Task Fire_Client_Unsubscribed_Event() Assert.IsTrue(eventArgs.ClientId.StartsWith(nameof(Fire_Client_Unsubscribed_Event))); Assert.AreEqual("The/Topic", eventArgs.TopicFilter); + Assert.AreEqual("TheUser", eventArgs.UserName); } } @@ -136,7 +142,7 @@ public async Task Fire_Application_Message_Received_Event() return CompletedTask.Instance; }; - var client = await testEnvironment.ConnectClient(); + var client = await testEnvironment.ConnectClient(o => o.WithCredentials("TheUser")); await client.PublishStringAsync("The_Topic", "The_Payload"); await LongTestDelay(); @@ -146,6 +152,7 @@ public async Task Fire_Application_Message_Received_Event() Assert.IsTrue(eventArgs.ClientId.StartsWith(nameof(Fire_Application_Message_Received_Event))); Assert.AreEqual("The_Topic", eventArgs.ApplicationMessage.Topic); Assert.AreEqual("The_Payload", eventArgs.ApplicationMessage.ConvertPayloadToString()); + Assert.AreEqual("TheUser", eventArgs.UserName); } }