async Task <MqttApplicationMessageInterceptorContext> InterceptApplicationMessageAsync(
            IMqttServerApplicationMessageInterceptor interceptor,
            MqttClientConnection clientConnection,
            MqttApplicationMessage applicationMessage)
        {
            string senderClientId;
            IDictionary <object, object> sessionItems;

            var messageIsFromServer = clientConnection == null;

            if (messageIsFromServer)
            {
                senderClientId = _options.ClientId;
                sessionItems   = _serverSessionItems;
            }
            else
            {
                senderClientId = clientConnection.ClientId;
                sessionItems   = clientConnection.Session.Items;
            }

            var interceptorContext = new MqttApplicationMessageInterceptorContext
            {
                ClientId           = senderClientId,
                SessionItems       = sessionItems,
                AcceptPublish      = true,
                ApplicationMessage = applicationMessage,
                CloseConnection    = false
            };

            await interceptor.InterceptApplicationMessagePublishAsync(interceptorContext).ConfigureAwait(false);

            return(interceptorContext);
        }
Exemple #2
0
        void TryMaintainConnection(MqttClientConnection connection, DateTime now)
        {
            try
            {
                if (!connection.IsRunning)
                {
                    // The connection is already dead or just created so there is no need to check it.
                    return;
                }

                if (connection.KeepAlivePeriod == 0)
                {
                    // The keep alive feature is not used by the current connection.
                    return;
                }

                if (connection.IsReadingPacket)
                {
                    // The connection is currently reading a (large) packet. So it is obviously
                    // doing something and thus "connected".
                    return;
                }

                // Values described here: [MQTT-3.1.2-24].
                // If the client sends 5 sec. the server will allow up to 7.5 seconds.
                // If the client sends 1 sec. the server will allow up to 1.5 seconds.
                var maxDurationWithoutPacket = connection.KeepAlivePeriod * 1.5D;

                var secondsWithoutPackage = (now - connection.Statistics.LastPacketSentTimestamp).TotalSeconds;
                if (secondsWithoutPackage < maxDurationWithoutPacket)
                {
                    // A packet was received before the timeout is affected.
                    return;
                }

                _logger.Warning("Client '{0}': Did not receive any packet or keep alive signal.", connection.ClientId);

                // Execute the disconnection in background so that the keep alive monitor can continue
                // with checking other connections.
                // We do not need to wait for the task so no await is needed.
                // Also the internal state of the connection must be swapped to "Finalizing" because the
                // next iteration of the keep alive timer happens.
                var _ = connection.StopAsync(MqttClientDisconnectReason.KeepAliveTimeout);
            }
            catch (Exception exception)
            {
                _logger.Error(exception, "Client {0}: Unhandled exception while checking keep alive timeouts.", connection.ClientId);
            }
        }
        public async Task HandleClientConnectionAsync(IMqttChannelAdapter channelAdapter,
                                                      CancellationToken cancellationToken)
        {
            MqttClientConnection clientConnection = null;

            try
            {
                var connectPacket = await ReceiveConnectPacket(channelAdapter, cancellationToken).ConfigureAwait(false);

                if (connectPacket == null)
                {
                    // Nothing was received in time etc.
                    return;
                }

                MqttConnAckPacket connAckPacket;

                var connectionValidatorContext =
                    await ValidateConnection(connectPacket, channelAdapter).ConfigureAwait(false);

                if (connectionValidatorContext.ReasonCode != MqttConnectReasonCode.Success)
                {
                    // Send failure response here without preparing a session!
                    connAckPacket =
                        channelAdapter.PacketFormatterAdapter.DataConverter.CreateConnAckPacket(
                            connectionValidatorContext);
                    await channelAdapter.SendPacketAsync(connAckPacket, cancellationToken).ConfigureAwait(false);

                    return;
                }

                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);

                await clientConnection.RunAsync().ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception exception)
            {
                _logger.Error(exception, exception.Message);
            }
            finally
            {
                if (clientConnection != null)
                {
                    if (clientConnection.ClientId != null)
                    {
                        // in case it is a takeover _clientConnections already contains the new connection
                        if (!clientConnection.IsTakenOver)
                        {
                            lock (_clientConnections)
                            {
                                _clientConnections.Remove(clientConnection.ClientId);
                            }

                            if (!_options.EnablePersistentSessions)
                            {
                                await DeleteSessionAsync(clientConnection.ClientId).ConfigureAwait(false);
                            }
                        }
                    }

                    var endpoint = clientConnection.Endpoint;

                    if (clientConnection.ClientId != null && !clientConnection.IsTakenOver)
                    {
                        // The event is fired at a separate place in case of a handover!
                        await _eventDispatcher.SafeNotifyClientDisconnectedAsync(
                            clientConnection.ClientId,
                            clientConnection.IsCleanDisconnect
                            ?MqttClientDisconnectType.Clean
                            : MqttClientDisconnectType.NotClean,
                            endpoint).ConfigureAwait(false);
                    }
                }

                clientConnection?.Dispose();

                await channelAdapter.DisconnectAsync(_options.DefaultCommunicationTimeout, CancellationToken.None)
                .ConfigureAwait(false);
            }
        }
        public void DispatchApplicationMessage(MqttApplicationMessage applicationMessage, MqttClientConnection sender)
        {
            if (applicationMessage == null)
            {
                throw new ArgumentNullException(nameof(applicationMessage));
            }

            _messageQueue.Add(new MqttPendingApplicationMessage(applicationMessage, sender));
        }