diff --git a/Source/MQTTnet/Server/Internal/MqttClientSessionsManager.cs b/Source/MQTTnet/Server/Internal/MqttClientSessionsManager.cs index 33627e9..22631df 100644 --- a/Source/MQTTnet/Server/Internal/MqttClientSessionsManager.cs +++ b/Source/MQTTnet/Server/Internal/MqttClientSessionsManager.cs @@ -106,9 +106,11 @@ namespace MQTTnet.Server.Internal return; } - clientConnection = await CreateClientConnection(connectPacket, channelAdapter, connectionValidatorContext.SessionItems).ConfigureAwait(false); - connAckPacket = channelAdapter.PacketFormatterAdapter.DataConverter.CreateConnAckPacket(connectionValidatorContext); + + // Pass connAckPacket so that IsSessionPresent flag can be set if the client session already exists + clientConnection = await CreateClientConnection(connectPacket, connAckPacket, channelAdapter, connectionValidatorContext.SessionItems).ConfigureAwait(false); + await channelAdapter.SendPacketAsync(connAckPacket, cancellationToken).ConfigureAwait(false); await _eventDispatcher.SafeNotifyClientConnectedAsync(connectPacket, channelAdapter).ConfigureAwait(false); @@ -450,7 +452,8 @@ namespace MQTTnet.Server.Internal } async Task CreateClientConnection( - MqttConnectPacket connectPacket, + MqttConnectPacket connectPacket, + MqttConnAckPacket connAckPacket, IMqttChannelAdapter channelAdapter, IDictionary sessionItems) { @@ -476,6 +479,7 @@ namespace MQTTnet.Server.Internal else { _logger.Verbose("Reusing existing session of client '{0}'.", connectPacket.ClientId); + connAckPacket.IsSessionPresent = true; } } diff --git a/Tests/MQTTnet.Core.Tests/MQTTv5/Server_Tests.cs b/Tests/MQTTnet.Core.Tests/MQTTv5/Server_Tests.cs index be589d5..18fde51 100644 --- a/Tests/MQTTnet.Core.Tests/MQTTv5/Server_Tests.cs +++ b/Tests/MQTTnet.Core.Tests/MQTTv5/Server_Tests.cs @@ -1,4 +1,4 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using MQTTnet.Client; using MQTTnet.Client.Options; using MQTTnet.Formatter; @@ -38,5 +38,57 @@ namespace MQTTnet.Tests.MQTTv5 Assert.AreEqual(1, receivedMessagesCount); } } + + [TestMethod] + public async Task Validate_IsSessionPresent() + { + using (var testEnvironment = new TestEnvironment(TestContext)) + { + // Create server with persistent sessions enabled + + await testEnvironment.StartServer(o => o.WithPersistentSessions()); + + const string ClientId = "Client1"; + + // Create client without clean session and long session expiry interval + + var client1 = await testEnvironment.ConnectClient(o => o + .WithProtocolVersion(MqttProtocolVersion.V500) + .WithTcpServer("127.0.0.1", testEnvironment.ServerPort) + .WithSessionExpiryInterval(9999) + .WithCleanSession(false) + .WithClientId(ClientId) + .Build() + ); + + // Disconnect; empty session should remain on server + + await client1.DisconnectAsync(); + + // Simulate some time delay between connections + + await Task.Delay(1000); + + // Reconnect the same client ID to existing session + + var client2 = testEnvironment.CreateClient(); + var options = testEnvironment.Factory.CreateClientOptionsBuilder() + .WithProtocolVersion(MqttProtocolVersion.V500) + .WithTcpServer("127.0.0.1", testEnvironment.ServerPort) + .WithSessionExpiryInterval(9999) + .WithCleanSession(false) + .WithClientId(ClientId) + .Build(); + + + var result = await client2.ConnectAsync(options).ConfigureAwait(false); + + await client2.DisconnectAsync(); + + // Session should be present + + Assert.IsTrue(result.IsSessionPresent, "Session not present"); + } + } } }