Exemple #1
0
 private static void ValidateConnectPacket(MqttConnectPacket packet)
 {
     if (string.IsNullOrEmpty(packet.ClientId) && !packet.CleanSession)
     {
         throw new MqttProtocolViolationException("CleanSession must be set if ClientId is empty [MQTT-3.1.3-7].");
     }
 }
Exemple #2
0
        public MqttPublishPacket Create(MqttConnectPacket connectPacket)
        {
            if (connectPacket == null)
            {
                throw new ArgumentNullException(nameof(connectPacket));
            }

            if (!connectPacket.WillFlag)
            {
                throw new MqttProtocolViolationException("The CONNECT packet contains no will message (WillFlag).");
            }

            var packet = new MqttPublishPacket
            {
                Topic   = connectPacket.WillTopic,
                Payload = connectPacket.WillMessage,
                QualityOfServiceLevel = connectPacket.WillQoS,
                Retain                 = connectPacket.WillRetain,
                ContentType            = connectPacket.WillContentType,
                CorrelationData        = connectPacket.WillCorrelationData,
                MessageExpiryInterval  = connectPacket.WillMessageExpiryInterval,
                PayloadFormatIndicator = connectPacket.WillPayloadFormatIndicator,
                ResponseTopic          = connectPacket.WillResponseTopic,
                UserProperties         = connectPacket.WillUserProperties
            };

            return(packet);
        }
Exemple #3
0
        public MqttClientConnection(MqttConnectPacket connectPacket,
                                    IMqttChannelAdapter channelAdapter,
                                    MqttClientSession session,
                                    MqttConnectionValidatorContext connectionValidatorContext,
                                    IMqttServerOptions serverOptions,
                                    MqttClientSessionsManager sessionsManager,
                                    IMqttRetainedMessagesManager retainedMessagesManager,
                                    IMqttNetLogger logger)
        {
            Session                  = session ?? throw new ArgumentNullException(nameof(session));
            _serverOptions           = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions));
            _sessionsManager         = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager));
            _retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager));

            _channelAdapter             = channelAdapter ?? throw new ArgumentNullException(nameof(channelAdapter));
            _connectionValidatorContext = connectionValidatorContext ?? throw new ArgumentNullException(nameof(connectionValidatorContext));
            _dataConverter = _channelAdapter.PacketFormatterAdapter.DataConverter;
            _endpoint      = _channelAdapter.Endpoint;
            ConnectPacket  = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket));

            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            _logger = logger.CreateScopedLogger(nameof(MqttClientConnection));

            _connectedTimestamp         = DateTime.UtcNow;
            LastPacketReceivedTimestamp = _connectedTimestamp;
            _lastNonKeepAlivePacketReceivedTimestamp = LastPacketReceivedTimestamp;
        }
Exemple #4
0
        private async Task <MqttConnAckPacket> AuthenticateAsync(MqttApplicationMessage willApplicationMessage, CancellationToken cancellationToken)
        {
            string userName = null;
            string password = null;

            Options.Credentials?.Create(out userName, out password);

            var connectPacket = new MqttConnectPacket
            {
                ClientId        = Options.ClientId,
                Username        = userName,
                Password        = password,
                CleanSession    = Options.CleanSession,
                KeepAlivePeriod = (ushort)Options.KeepAlivePeriod.TotalSeconds,
                WillMessage     = willApplicationMessage
            };

            var response = await SendAndReceiveAsync <MqttConnAckPacket>(connectPacket, cancellationToken).ConfigureAwait(false);

            if (response.ConnectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
            {
                throw new MqttConnectingFailedException(response.ConnectReturnCode);
            }

            return(response);
        }
Exemple #5
0
        public MqttClient(
            MqttConnectPacket connectPacket,
            IMqttChannelAdapter channelAdapter,
            MqttSession session,
            MqttServerOptions serverOptions,
            MqttServerEventContainer eventContainer,
            MqttClientSessionsManager sessionsManager,
            IMqttNetLogger logger)
        {
            _serverOptions   = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions));
            _eventContainer  = eventContainer;
            _sessionsManager = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager));

            ChannelAdapter = channelAdapter ?? throw new ArgumentNullException(nameof(channelAdapter));
            Endpoint       = channelAdapter.Endpoint;

            Session        = session ?? throw new ArgumentNullException(nameof(session));
            _connectPacket = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket));

            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            _logger = logger.WithSource(nameof(MqttClient));
        }
        public MqttClientConnection(
            MqttConnectPacket connectPacket,
            IMqttChannelAdapter channelAdapter,
            MqttClientSession session,
            IMqttServerOptions serverOptions,
            MqttClientSessionsManager sessionsManager,
            MqttRetainedMessagesManager retainedMessagesManager,
            IMqttNetChildLogger logger)
        {
            Session                  = session ?? throw new ArgumentNullException(nameof(session));
            _serverOptions           = serverOptions ?? throw new ArgumentNullException(nameof(serverOptions));
            _sessionsManager         = sessionsManager ?? throw new ArgumentNullException(nameof(sessionsManager));
            _retainedMessagesManager = retainedMessagesManager ?? throw new ArgumentNullException(nameof(retainedMessagesManager));

            _channelAdapter = channelAdapter ?? throw new ArgumentNullException(nameof(channelAdapter));
            _dataConverter  = _channelAdapter.PacketFormatterAdapter.DataConverter;
            _endpoint       = _channelAdapter.Endpoint;
            _connectPacket  = connectPacket ?? throw new ArgumentNullException(nameof(connectPacket));

            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            _logger = logger.CreateChildLogger(nameof(MqttClientConnection));

            _keepAliveMonitor = new MqttClientKeepAliveMonitor(_connectPacket.ClientId, StopAsync, _logger);

            _connectedTimestamp                      = DateTime.UtcNow;
            _lastPacketReceivedTimestamp             = _connectedTimestamp;
            _lastNonKeepAlivePacketReceivedTimestamp = _lastPacketReceivedTimestamp;
        }
Exemple #7
0
        async Task <MqttConnectionValidatorContext> ValidateConnectionAsync(MqttConnectPacket connectPacket, IMqttChannelAdapter channelAdapter)
        {
            var context = new MqttConnectionValidatorContext(connectPacket, channelAdapter, new ConcurrentDictionary <object, object>());

            var connectionValidator = _options.ConnectionValidator;

            if (connectionValidator == null)
            {
                context.ReasonCode = MqttConnectReasonCode.Success;
                return(context);
            }

            await connectionValidator.ValidateConnectionAsync(context).ConfigureAwait(false);

            // Check the client ID and set a random one if supported.
            if (string.IsNullOrEmpty(connectPacket.ClientId) && channelAdapter.PacketFormatterAdapter.ProtocolVersion == MqttProtocolVersion.V500)
            {
                connectPacket.ClientId = context.AssignedClientIdentifier;
            }

            if (string.IsNullOrEmpty(connectPacket.ClientId))
            {
                context.ReasonCode = MqttConnectReasonCode.ClientIdentifierNotValid;
            }

            return(context);
        }
Exemple #8
0
        public void DetectVersionFromMqttConnectPacket()
        {
            var packet = new MqttConnectPacket
            {
                ClientId        = "XYZ",
                Password        = Encoding.UTF8.GetBytes("PASS"),
                Username        = "******",
                KeepAlivePeriod = 123,
                CleanSession    = true
            };

            Assert.AreEqual(
                MqttProtocolVersion.V310,
                DeserializeAndDetectVersion(new MqttPacketFormatterAdapter(new MqttPacketWriter()), Serialize(packet, MqttProtocolVersion.V310)));

            Assert.AreEqual(
                MqttProtocolVersion.V311,
                DeserializeAndDetectVersion(new MqttPacketFormatterAdapter(new MqttPacketWriter()), Serialize(packet, MqttProtocolVersion.V311)));

            Assert.AreEqual(
                MqttProtocolVersion.V500,
                DeserializeAndDetectVersion(new MqttPacketFormatterAdapter(new MqttPacketWriter()), Serialize(packet, MqttProtocolVersion.V500)));

            var adapter = new MqttPacketFormatterAdapter(new MqttPacketWriter());

            var ex = Assert.ThrowsException <MqttProtocolViolationException>(() => DeserializeAndDetectVersion(adapter, WriterFactory().AddMqttHeader(MqttControlPacketType.Connect, new byte[0])));

            Assert.AreEqual("CONNECT packet must have at least 7 bytes.", ex.Message);
            ex = Assert.ThrowsException <MqttProtocolViolationException>(() => DeserializeAndDetectVersion(adapter, WriterFactory().AddMqttHeader(MqttControlPacketType.Connect, new byte[7])));
            Assert.AreEqual("Protocol '' not supported.", ex.Message);
            ex = Assert.ThrowsException <MqttProtocolViolationException>(() => DeserializeAndDetectVersion(adapter, WriterFactory().AddMqttHeader(MqttControlPacketType.Connect, new byte[] { 255, 255, 0, 0, 0, 0, 0 })));
            Assert.AreEqual("Expected at least 65537 bytes but there are only 7 bytes", ex.Message);
        }
Exemple #9
0
        private byte Serialize(MqttConnectPacket packet, MqttPacketWriter writer)
        {
            ValidateConnectPacket(packet);

            // Write variable header
            writer.Write(0x00, 0x04); // 3.1.2.1 Protocol Name
            if (ProtocolVersion == MqttProtocolVersion.V311)
            {
                writer.Write(ProtocolVersionV311Name);
                writer.Write(0x04); // 3.1.2.2 Protocol Level (4)
            }
            else
            {
                writer.Write(ProtocolVersionV310Name);
                writer.Write(0x64, 0x70, 0x03); // Protocol Level (0x03)
            }

            var connectFlags = new ByteWriter(); // 3.1.2.3 Connect Flags

            connectFlags.Write(false);           // Reserved
            connectFlags.Write(packet.CleanSession);
            connectFlags.Write(packet.WillMessage != null);

            if (packet.WillMessage != null)
            {
                connectFlags.Write((int)packet.WillMessage.QualityOfServiceLevel, 2);
                connectFlags.Write(packet.WillMessage.Retain);
            }
            else
            {
                connectFlags.Write(0, 2);
                connectFlags.Write(false);
            }

            connectFlags.Write(packet.Password != null);
            connectFlags.Write(packet.Username != null);

            writer.Write(connectFlags);
            writer.Write(packet.KeepAlivePeriod);
            writer.WriteWithLengthPrefix(packet.ClientId);

            if (packet.WillMessage != null)
            {
                writer.WriteWithLengthPrefix(packet.WillMessage.Topic);
                writer.WriteWithLengthPrefix(packet.WillMessage.Payload);
            }

            if (packet.Username != null)
            {
                writer.WriteWithLengthPrefix(packet.Username);
            }

            if (packet.Password != null)
            {
                writer.WriteWithLengthPrefix(packet.Password);
            }

            return(MqttPacketWriter.BuildFixedHeader(MqttControlPacketType.Connect));
        }
        async Task <MqttClientConnection> CreateClientConnection(
            MqttConnectPacket connectPacket,
            MqttConnAckPacket connAckPacket,
            IMqttChannelAdapter channelAdapter,
            IDictionary <object, object> sessionItems)
        {
            MqttClientConnection connection;

            using (await _createConnectionSyncRoot.WaitAsync(CancellationToken.None).ConfigureAwait(false))
            {
                MqttClientSession session;
                lock (_clientSessions)
                {
                    if (!_clientSessions.TryGetValue(connectPacket.ClientId, out session))
                    {
                        _logger.Verbose("Created a new session for client '{0}'.", connectPacket.ClientId);
                        session = CreateSession(connectPacket.ClientId, sessionItems);
                    }
                    else
                    {
                        if (connectPacket.CleanSession)
                        {
                            _logger.Verbose("Deleting existing session of client '{0}'.", connectPacket.ClientId);
                            session = CreateSession(connectPacket.ClientId, sessionItems);
                        }
                        else
                        {
                            _logger.Verbose("Reusing existing session of client '{0}'.", connectPacket.ClientId);
                            connAckPacket.IsSessionPresent = true;
                        }
                    }

                    _clientSessions[connectPacket.ClientId] = session;
                }

                MqttClientConnection existingConnection;

                lock (_clientConnections)
                {
                    _clientConnections.TryGetValue(connectPacket.ClientId, out existingConnection);
                    connection = CreateConnection(connectPacket, channelAdapter, session);

                    _clientConnections[connectPacket.ClientId] = connection;
                }

                if (existingConnection != null)
                {
                    await _eventDispatcher.SafeNotifyClientDisconnectedAsync(existingConnection.ClientId,
                                                                             MqttClientDisconnectType.Takeover, existingConnection.Endpoint);

                    existingConnection.IsTakenOver = true;
                    await existingConnection.StopAsync(MqttClientDisconnectReason.SessionTakenOver)
                    .ConfigureAwait(false);
                }
            }

            return(connection);
        }
Exemple #11
0
        private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket)
        {
            if (_options.ConnectionValidator != null)
            {
                return(_options.ConnectionValidator(connectPacket));
            }

            return(MqttConnectReturnCode.ConnectionAccepted);
        }
        private static async Task <MqttBasePacket> DeserializeConnectAsync(MqttPacketReader reader)
        {
            await reader.ReadRemainingDataAsync(2); // Skip 2 bytes

            var protocolName = await reader.ReadRemainingDataAsync(4);

            if (Encoding.UTF8.GetString(protocolName, 0, protocolName.Length) != "MQTT")
            {
                throw new MqttProtocolViolationException("Protocol name is not 'MQTT'.");
            }

            var protocolLevel = await reader.ReadRemainingDataByteAsync();

            var connectFlags = await reader.ReadRemainingDataByteAsync();

            var connectFlagsReader = new ByteReader(connectFlags);

            connectFlagsReader.Read(); // Reserved.

            var packet = new MqttConnectPacket
            {
                CleanSession = connectFlagsReader.Read()
            };

            var willFlag     = connectFlagsReader.Read();
            var willQoS      = connectFlagsReader.Read(2);
            var willRetain   = connectFlagsReader.Read();
            var passwordFlag = connectFlagsReader.Read();
            var usernameFlag = connectFlagsReader.Read();

            packet.KeepAlivePeriod = await reader.ReadRemainingDataUShortAsync();

            packet.ClientId = await reader.ReadRemainingDataStringWithLengthPrefixAsync();

            if (willFlag)
            {
                packet.WillMessage = new MqttApplicationMessage(
                    await reader.ReadRemainingDataStringWithLengthPrefixAsync(),
                    await reader.ReadRemainingDataWithLengthPrefixAsync(),
                    (MqttQualityOfServiceLevel)willQoS,
                    willRetain);
            }

            if (usernameFlag)
            {
                packet.Username = await reader.ReadRemainingDataStringWithLengthPrefixAsync();
            }

            if (passwordFlag)
            {
                packet.Password = await reader.ReadRemainingDataStringWithLengthPrefixAsync();
            }

            ValidateConnectPacket(packet);
            return(packet);
        }
 MqttClientConnection CreateConnection(MqttConnectPacket connectPacket, IMqttChannelAdapter channelAdapter,
                                       MqttClientSession session)
 {
     return(new MqttClientConnection(
                connectPacket,
                channelAdapter,
                session,
                _options,
                this,
                _rootLogger));
 }
        private Task SerializeAsync(MqttConnectPacket packet, IMqttCommunicationChannel destination)
        {
            ValidateConnectPacket(packet);

            using (var output = new MqttPacketWriter())
            {
                // Write variable header
                output.Write(0x00, 0x04);            // 3.1.2.1 Protocol Name
                output.Write(MqttPrefix);
                output.Write(0x04);                  // 3.1.2.2 Protocol Level

                var connectFlags = new ByteWriter(); // 3.1.2.3 Connect Flags
                connectFlags.Write(false);           // Reserved
                connectFlags.Write(packet.CleanSession);
                connectFlags.Write(packet.WillMessage != null);

                if (packet.WillMessage != null)
                {
                    connectFlags.Write((int)packet.WillMessage.QualityOfServiceLevel, 2);
                    connectFlags.Write(packet.WillMessage.Retain);
                }
                else
                {
                    connectFlags.Write(0, 2);
                    connectFlags.Write(false);
                }

                connectFlags.Write(packet.Password != null);
                connectFlags.Write(packet.Username != null);

                output.Write(connectFlags);
                output.Write(packet.KeepAlivePeriod);
                output.WriteWithLengthPrefix(packet.ClientId);

                if (packet.WillMessage != null)
                {
                    output.WriteWithLengthPrefix(packet.WillMessage.Topic);
                    output.WriteWithLengthPrefix(packet.WillMessage.Payload);
                }

                if (packet.Username != null)
                {
                    output.WriteWithLengthPrefix(packet.Username);
                }

                if (packet.Password != null)
                {
                    output.WriteWithLengthPrefix(packet.Password);
                }

                output.InjectFixedHeader(MqttControlPacketType.Connect);
                return(output.WriteToAsync(destination));
            }
        }
Exemple #15
0
        protected void ValidateConnectPacket(MqttConnectPacket packet)
        {
            if (packet == null)
            {
                throw new ArgumentNullException(nameof(packet));
            }

            if (string.IsNullOrEmpty(packet.ClientId) && !packet.CleanSession)
            {
                throw new MqttProtocolViolationException("CleanSession must be set if ClientId is empty [MQTT-3.1.3-7].");
            }
        }
 MqttClientConnection CreateConnection(MqttConnectPacket connectPacket, IMqttChannelAdapter channelAdapter, MqttClientSession session, MqttConnectionValidatorContext connectionValidatorContext)
 {
     return(new MqttClientConnection(
                connectPacket,
                channelAdapter,
                session,
                connectionValidatorContext,
                _options,
                this,
                _retainedMessagesManager,
                _rootLogger));
 }
        public void DeserializeV311_MqttConnectPacket()
        {
            var p = new MqttConnectPacket
            {
                ClientId        = "XYZ",
                Password        = Encoding.UTF8.GetBytes("PASS"),
                Username        = "******",
                KeepAlivePeriod = 123,
                CleanSession    = true
            };

            DeserializeAndCompare(p, "EBsABE1RVFQEwgB7AANYWVoABFVTRVIABFBBU1M=");
        }
        public void SerializeV310_MqttConnectPacket()
        {
            var p = new MqttConnectPacket
            {
                ClientId        = "XYZ",
                Password        = Encoding.UTF8.GetBytes("PASS"),
                Username        = "******",
                KeepAlivePeriod = 123,
                CleanSession    = true
            };

            SerializeAndCompare(p, "EB0ABk1RSXNkcAPCAHsAA1hZWgAEVVNFUgAEUEFTUw==", MqttProtocolVersion.V310);
        }
Exemple #19
0
        public async Task ConnectAsync(MqttApplicationMessage willApplicationMessage = null)
        {
            MqttTrace.Verbose(nameof(MqttClient), "Trying to connect.");

            if (IsConnected)
            {
                throw new MqttProtocolViolationException("It is not allowed to connect with a server after the connection is established.");
            }

            var connectPacket = new MqttConnectPacket
            {
                ClientId        = _options.ClientId,
                Username        = _options.UserName,
                Password        = _options.Password,
                CleanSession    = _options.CleanSession,
                KeepAlivePeriod = (ushort)_options.KeepAlivePeriod.TotalSeconds,
                WillMessage     = willApplicationMessage
            };

            await _adapter.ConnectAsync(_options, _options.DefaultCommunicationTimeout);

            MqttTrace.Verbose(nameof(MqttClient), "Connection with server established.");

            _cancellationTokenSource = new CancellationTokenSource();
            _latestPacketIdentifier  = 0;
            _processedPublishPackets.Clear();
            _packetDispatcher.Reset();
            IsConnected = true;

#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            Task.Run(() => ReceivePackets(_cancellationTokenSource.Token), _cancellationTokenSource.Token);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

            var response = await SendAndReceiveAsync <MqttConnAckPacket>(connectPacket);

            if (response.ConnectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
            {
                await DisconnectAsync();

                throw new MqttConnectingFailedException(response.ConnectReturnCode);
            }

            if (_options.KeepAlivePeriod != TimeSpan.Zero)
            {
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                Task.Run(() => SendKeepAliveMessagesAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            }

            Connected?.Invoke(this, EventArgs.Empty);
        }
Exemple #20
0
        public async Task ConnectAsync(MqttApplicationMessage willApplicationMessage = null)
        {
            ThrowIfConnected("It is not allowed to connect with a server after the connection is established.");

            try
            {
                _cancellationTokenSource = new CancellationTokenSource();
                _latestPacketIdentifier  = 0;
                _packetDispatcher.Reset();

                MqttTrace.Verbose(nameof(MqttClient), "Trying to connect with server.");
                await _adapter.ConnectAsync(_options.DefaultCommunicationTimeout, _options).ConfigureAwait(false);

                MqttTrace.Verbose(nameof(MqttClient), "Connection with server established.");

                StartReceivePackets(_cancellationTokenSource.Token);

                var connectPacket = new MqttConnectPacket
                {
                    ClientId        = _options.ClientId,
                    Username        = _options.UserName,
                    Password        = _options.Password,
                    CleanSession    = _options.CleanSession,
                    KeepAlivePeriod = (ushort)_options.KeepAlivePeriod.TotalSeconds,
                    WillMessage     = willApplicationMessage
                };

                var response = await SendAndReceiveAsync <MqttConnAckPacket>(connectPacket).ConfigureAwait(false);

                if (response.ConnectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
                {
                    throw new MqttConnectingFailedException(response.ConnectReturnCode);
                }

                MqttTrace.Verbose(nameof(MqttClient), "MQTT connection with server established.");

                if (_options.KeepAlivePeriod != TimeSpan.Zero)
                {
                    StartSendKeepAliveMessages(_cancellationTokenSource.Token);
                }

                Connected?.Invoke(this, EventArgs.Empty);
            }
            catch (Exception)
            {
                await DisconnectInternalAsync().ConfigureAwait(false);

                throw;
            }
        }
        private MqttConnectReturnCode ValidateConnection(MqttConnectPacket connectPacket)
        {
            if (_options.ConnectionValidator == null)
            {
                return(MqttConnectReturnCode.ConnectionAccepted);
            }

            var context = new MqttConnectionValidatorContext(
                connectPacket.ClientId,
                connectPacket.Username,
                connectPacket.Password,
                connectPacket.WillMessage);

            _options.ConnectionValidator(context);
            return(context.ReturnCode);
        }
        async Task <MqttClientConnection> CreateClientConnectionAsync(MqttConnectPacket connectPacket, MqttConnectionValidatorContext connectionValidatorContext, IMqttChannelAdapter channelAdapter)
        {
            MqttClientConnection existingConnection;
            MqttClientConnection connection;

            using (await _createConnectionSyncRoot.WaitAsync(CancellationToken.None).ConfigureAwait(false))
            {
                MqttClientSession session;
                lock (_sessions)
                {
                    if (!_sessions.TryGetValue(connectPacket.ClientId, out session))
                    {
                        _logger.Verbose("Created a new session for client '{0}'.", connectPacket.ClientId);
                        session = CreateSession(connectPacket.ClientId, connectionValidatorContext);
                    }
                    else
                    {
                        if (connectPacket.CleanSession)
                        {
                            _logger.Verbose("Deleting existing session of client '{0}'.", connectPacket.ClientId);
                            session = CreateSession(connectPacket.ClientId, connectionValidatorContext);
                        }
                        else
                        {
                            _logger.Verbose("Reusing existing session of client '{0}'.", connectPacket.ClientId);
                        }
                    }

                    _sessions[connectPacket.ClientId] = session;
                }

                lock (_connections)
                {
                    _connections.TryGetValue(connectPacket.ClientId, out existingConnection);
                    connection = CreateConnection(connectPacket, channelAdapter, session, connectionValidatorContext);

                    _connections[connectPacket.ClientId] = connection;
                }

                if (existingConnection != null)
                {
                    await existingConnection.StopAsync(MqttClientDisconnectReason.SessionTakenOver).ConfigureAwait(false);
                }
            }

            return(connection);
        }
Exemple #23
0
        async Task <MqttClientConnection> CreateClientConnectionAsync(MqttConnectPacket connectPacket, MqttConnectionValidatorContext connectionValidatorContext, IMqttChannelAdapter channelAdapter)
        {
            MqttClientConnection connection;
            MqttClientConnection existingConnection = null;

            using (await _createConnectionGate.WaitAsync(_cancellationToken).ConfigureAwait(false))
            {
                var session = _sessions.AddOrUpdate(
                    connectPacket.ClientId,
                    key =>
                {
                    _logger.Verbose("Created a new session for client '{0}'.", key);
                    return(new MqttClientSession(key, connectionValidatorContext.SessionItems, _eventDispatcher, _options, _retainedMessagesManager, _rootLogger));
                },
                    (key, existingSession) =>
                {
                    if (connectPacket.CleanSession)
                    {
                        _logger.Verbose("Deleting existing session of client '{0}'.", connectPacket.ClientId);
                        return(new MqttClientSession(key, connectionValidatorContext.SessionItems, _eventDispatcher, _options, _retainedMessagesManager, _rootLogger));
                    }

                    _logger.Verbose("Reusing existing session of client '{0}'.", connectPacket.ClientId);
                    return(existingSession);
                });

                connection = new MqttClientConnection(connectPacket, channelAdapter, session, connectionValidatorContext, _options, this, _retainedMessagesManager, _rootLogger);

                _connections.AddOrUpdate(
                    connectPacket.ClientId,
                    key => connection,
                    (key, tempExistingConnection) =>
                {
                    existingConnection = tempExistingConnection;
                    return(connection);
                });
            }

            // Disconnect the client outside of the lock so that new clients can still connect while a single
            // one is being disconnected.
            if (existingConnection != null)
            {
                await existingConnection.StopAsync(true).ConfigureAwait(false);
            }

            return(connection);
        }
        private async Task <MqttClientConnection> CreateConnectionAsync(MqttConnectPacket connectPacket, MqttConnectionValidatorContext connectionValidatorContext, IMqttChannelAdapter channelAdapter)
        {
            await _createConnectionGate.WaitAsync(_cancellationToken).ConfigureAwait(false);

            try
            {
                var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var session);

                var isConnectionPresent = _connections.TryGetValue(connectPacket.ClientId, out var existingConnection);
                if (isConnectionPresent)
                {
                    await existingConnection.StopAsync().ConfigureAwait(false);
                }

                if (isSessionPresent)
                {
                    if (connectPacket.CleanSession)
                    {
                        session = null;

                        _logger.Verbose("Deleting existing session of client '{0}'.", connectPacket.ClientId);
                    }
                    else
                    {
                        _logger.Verbose("Reusing existing session of client '{0}'.", connectPacket.ClientId);
                    }
                }

                if (session == null)
                {
                    session = new MqttClientSession(connectPacket.ClientId, connectionValidatorContext.SessionItems, _eventDispatcher, _options, _logger);
                    _logger.Verbose("Created a new session for client '{0}'.", connectPacket.ClientId);
                }

                var connection = new MqttClientConnection(connectPacket, channelAdapter, session, _options, this, _retainedMessagesManager, _logger);

                _connections[connection.ClientId] = connection;
                _sessions[session.ClientId]       = session;

                return(connection);
            }
            finally
            {
                _createConnectionGate.Release();
            }
        }
        public MqttConnectPacket Create(MqttClientOptions clientOptions)
        {
            if (clientOptions == null)
            {
                throw new ArgumentNullException(nameof(clientOptions));
            }

            var connectPacket = new MqttConnectPacket
            {
                ClientId                   = clientOptions.ClientId,
                Username                   = clientOptions.Credentials?.GetUserName(clientOptions),
                Password                   = clientOptions.Credentials?.GetPassword(clientOptions),
                CleanSession               = clientOptions.CleanSession,
                KeepAlivePeriod            = (ushort)clientOptions.KeepAlivePeriod.TotalSeconds,
                AuthenticationMethod       = clientOptions.AuthenticationMethod,
                AuthenticationData         = clientOptions.AuthenticationData,
                WillDelayInterval          = clientOptions.WillDelayInterval,
                MaximumPacketSize          = clientOptions.MaximumPacketSize,
                ReceiveMaximum             = clientOptions.ReceiveMaximum,
                RequestProblemInformation  = clientOptions.RequestProblemInformation,
                RequestResponseInformation = clientOptions.RequestResponseInformation,
                SessionExpiryInterval      = clientOptions.SessionExpiryInterval,
                TopicAliasMaximum          = clientOptions.TopicAliasMaximum,
                UserProperties             = clientOptions.UserProperties,
                TryPrivate                 = clientOptions.TryPrivate
            };

            if (!string.IsNullOrEmpty(clientOptions.WillTopic))
            {
                connectPacket.WillFlag                   = true;
                connectPacket.WillTopic                  = clientOptions.WillTopic;
                connectPacket.WillQoS                    = clientOptions.WillQualityOfServiceLevel;
                connectPacket.WillMessage                = clientOptions.WillPayload;
                connectPacket.WillRetain                 = clientOptions.WillRetain;
                connectPacket.WillDelayInterval          = clientOptions.WillDelayInterval;
                connectPacket.WillContentType            = clientOptions.WillContentType;
                connectPacket.WillCorrelationData        = clientOptions.WillCorrelationData;
                connectPacket.WillResponseTopic          = clientOptions.WillResponseTopic;
                connectPacket.WillMessageExpiryInterval  = clientOptions.WillMessageExpiryInterval;
                connectPacket.WillPayloadFormatIndicator = clientOptions.WillPayloadFormatIndicator;
                connectPacket.WillUserProperties         = clientOptions.WillUserProperties;
            }

            return(connectPacket);
        }
Exemple #26
0
        public void DeserializeV311_MqttConnectPacketWithWillMessage()
        {
            var p = new MqttConnectPacket
            {
                ClientId        = "XYZ",
                Password        = "******",
                Username        = "******",
                KeepAlivePeriod = 123,
                CleanSession    = true,
                WillMessage     = new MqttApplicationMessage(
                    "My/last/will",
                    Encoding.UTF8.GetBytes("Good byte."),
                    MqttQualityOfServiceLevel.AtLeastOnce,
                    true)
            };

            DeserializeAndCompare(p, "EDUABE1RVFQE7gB7AANYWVoADE15L2xhc3Qvd2lsbAAKR29vZCBieXRlLgAEVVNFUgAEUEFTUw==");
        }
        MqttClientConnection CreateClientConnection(MqttConnectPacket connectPacket, MqttConnectionValidatorContext connectionValidatorContext, IMqttChannelAdapter channelAdapter)
        {
            lock (_createConnectionSyncRoot)
            {
                MqttClientSession session;
                lock (_sessions)
                {
                    if (!_sessions.TryGetValue(connectPacket.ClientId, out session))
                    {
                        _logger.Verbose("Created a new session for client '{0}'.", connectPacket.ClientId);
                        session = CreateSession(connectPacket.ClientId, connectionValidatorContext);
                    }
                    else
                    {
                        if (connectPacket.CleanSession)
                        {
                            _logger.Verbose("Deleting existing session of client '{0}'.", connectPacket.ClientId);
                            session = CreateSession(connectPacket.ClientId, connectionValidatorContext);
                        }
                        else
                        {
                            _logger.Verbose("Reusing existing session of client '{0}'.", connectPacket.ClientId);
                        }
                    }

                    _sessions[connectPacket.ClientId] = session;
                }

                MqttClientConnection existingConnection;
                MqttClientConnection connection;
                lock (_connections)
                {
                    _connections.TryGetValue(connectPacket.ClientId, out existingConnection);
                    connection = CreateConnection(connectPacket, channelAdapter, session, connectionValidatorContext);

                    _connections[connectPacket.ClientId] = connection;
                }

                existingConnection?.StopAsync(MqttClientDisconnectReason.SessionTakenOver).GetAwaiter().GetResult();

                return(connection);
            }
        }
Exemple #28
0
        private async Task AuthenticateAsync(MqttApplicationMessage willApplicationMessage)
        {
            var connectPacket = new MqttConnectPacket
            {
                ClientId        = _options.ClientId,
                Username        = _options.UserName,
                Password        = _options.Password,
                CleanSession    = _options.CleanSession,
                KeepAlivePeriod = (ushort)_options.KeepAlivePeriod.TotalSeconds,
                WillMessage     = willApplicationMessage
            };

            var response = await SendAndReceiveAsync <MqttConnAckPacket>(connectPacket).ConfigureAwait(false);

            if (response.ConnectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
            {
                throw new MqttConnectingFailedException(response.ConnectReturnCode);
            }
        }
        public async Task RunAsync(MqttConnectPacket connectPacket, IMqttChannelAdapter adapter)
        {
            if (connectPacket == null)
            {
                throw new ArgumentNullException(nameof(connectPacket));
            }
            if (adapter == null)
            {
                throw new ArgumentNullException(nameof(adapter));
            }

            try
            {
                var cancellationTokenSource = new CancellationTokenSource();

                _willMessage             = connectPacket.WillMessage;
                _adapter                 = adapter;
                _cancellationTokenSource = cancellationTokenSource;

                _pendingMessagesQueue.Start(adapter, cancellationTokenSource.Token);

                _lastPacketReceivedTracker.Restart();
                _lastNonKeepAlivePacketReceivedTracker.Restart();

                if (connectPacket.KeepAlivePeriod > 0)
                {
                    StartCheckingKeepAliveTimeout(TimeSpan.FromSeconds(connectPacket.KeepAlivePeriod), cancellationTokenSource.Token);
                }

                await ReceivePacketsAsync(adapter, cancellationTokenSource.Token).ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
            }
            catch (MqttCommunicationException exception)
            {
                _logger.Warning <MqttClientSession>(exception, "Client '{0}': Communication exception while processing client packets.", ClientId);
            }
            catch (Exception exception)
            {
                _logger.Error <MqttClientSession>(exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId);
            }
        }
        async Task <ValidatingConnectionEventArgs> ValidateConnection(MqttConnectPacket connectPacket, IMqttChannelAdapter channelAdapter)
        {
            var context = new ValidatingConnectionEventArgs(connectPacket, channelAdapter)
            {
                SessionItems = new ConcurrentDictionary <object, object>()
            };

            await _eventContainer.ValidatingConnectionEvent.InvokeAsync(context).ConfigureAwait(false);

            // Check the client ID and set a random one if supported.
            if (string.IsNullOrEmpty(connectPacket.ClientId) && channelAdapter.PacketFormatterAdapter.ProtocolVersion == MqttProtocolVersion.V500)
            {
                connectPacket.ClientId = context.AssignedClientIdentifier;
            }

            if (string.IsNullOrEmpty(connectPacket.ClientId))
            {
                context.ReasonCode = MqttConnectReasonCode.ClientIdentifierNotValid;
            }

            return(context);
        }