Ejemplo n.º 1
0
        public Task ConnectAsync(TimeSpan timeout)
        {
            ThrowIfDisposed();
            _logger.Trace <MqttChannelAdapter>("Connecting [Timeout={0}]", timeout);

            return(ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout)));
        }
Ejemplo n.º 2
0
        public async Task SendPacketsAsync(TimeSpan timeout, CancellationToken cancellationToken, IEnumerable <MqttBasePacket> packets)
        {
            await ExecuteAndWrapExceptionAsync(async() =>
            {
                await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
                try
                {
                    foreach (var packet in packets)
                    {
                        if (packet == null)
                        {
                            continue;
                        }

                        _logger.Trace <MqttChannelAdapter>("TX >>> {0} [Timeout={1}]", packet, timeout);

                        var writeBuffer = PacketSerializer.Serialize(packet);
                        await _channel.SendStream.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken).ConfigureAwait(false);
                    }

                    if (timeout > TimeSpan.Zero)
                    {
                        await _channel.SendStream.FlushAsync(cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false);
                    }
                    else
                    {
                        await _channel.SendStream.FlushAsync(cancellationToken).ConfigureAwait(false);
                    }
                }
                finally
                {
                    _semaphore.Release();
                }
            });
        }
Ejemplo n.º 3
0
        public void Enqueue(MqttBasePacket packet)
        {
            if (packet == null)
            {
                throw new ArgumentNullException(nameof(packet));
            }

            _queue.Add(packet);
            _logger.Trace <MqttClientPendingMessagesQueue>("Enqueued packet (ClientId: {0}).", _session.ClientId);
        }
Ejemplo n.º 4
0
        private async Task <GetOrCreateClientSessionResult> GetOrCreateClientSessionAsync(MqttConnectPacket connectPacket)
        {
            await _semaphore.WaitAsync().ConfigureAwait(false);

            try
            {
                var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var clientSession);
                if (isSessionPresent)
                {
                    if (connectPacket.CleanSession)
                    {
                        _sessions.Remove(connectPacket.ClientId);

                        await clientSession.StopAsync().ConfigureAwait(false);

                        clientSession.Dispose();
                        clientSession = null;

                        _logger.Trace <MqttClientSessionsManager>("Stopped existing session of client '{0}'.", connectPacket.ClientId);
                    }
                    else
                    {
                        _logger.Trace <MqttClientSessionsManager>("Reusing existing session of client '{0}'.", connectPacket.ClientId);
                    }
                }

                var isExistingSession = true;
                if (clientSession == null)
                {
                    isExistingSession = false;

                    clientSession = new MqttClientSession(connectPacket.ClientId, _options, _retainedMessagesManager, _logger)
                    {
                        ApplicationMessageReceivedCallback = DispatchApplicationMessageAsync
                    };

                    clientSession.SubscriptionsManager.TopicSubscribedCallback   = ClientSubscribedTopicCallback;
                    clientSession.SubscriptionsManager.TopicUnsubscribedCallback = ClientUnsubscribedTopicCallback;

                    _sessions[connectPacket.ClientId] = clientSession;

                    _logger.Trace <MqttClientSessionsManager>("Created a new session for client '{0}'.", connectPacket.ClientId);
                }

                return(new GetOrCreateClientSessionResult {
                    IsExistingSession = isExistingSession, Session = clientSession
                });
            }
            finally
            {
                _semaphore.Release();
            }
        }
Ejemplo n.º 5
0
        public async Task <MqttClientConnectResult> ConnectAsync(IMqttClientOptions options)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (options.ChannelOptions == null)
            {
                throw new ArgumentException("ChannelOptions are not set.");
            }

            ThrowIfConnected("It is not allowed to connect with a server after the connection is established.");

            try
            {
                _options = options;
                _cancellationTokenSource = new CancellationTokenSource();
                _packetIdentifierProvider.Reset();
                _packetDispatcher.Reset();

                _adapter = _adapterFactory.CreateClientAdapter(options.ChannelOptions, _logger);

                _logger.Trace <MqttClient>("Trying to connect with server.");
                await _adapter.ConnectAsync(_options.CommunicationTimeout).ConfigureAwait(false);

                _logger.Trace <MqttClient>("Connection with server established.");

                await StartReceivingPacketsAsync().ConfigureAwait(false);

                var connectResponse = await AuthenticateAsync(options.WillMessage).ConfigureAwait(false);

                _logger.Trace <MqttClient>("MQTT connection with server established.");

                _sendTracker.Restart();

                if (_options.KeepAlivePeriod != TimeSpan.Zero)
                {
                    StartSendingKeepAliveMessages();
                }

                IsConnected = true;
                Connected?.Invoke(this, new MqttClientConnectedEventArgs(connectResponse.IsSessionPresent));
                return(new MqttClientConnectResult(connectResponse.IsSessionPresent));
            }
            catch (Exception exception)
            {
                _logger.Error <MqttClient>(exception, "Error while connecting with server.");
                await DisconnectInternalAsync(exception).ConfigureAwait(false);

                throw;
            }
        }
Ejemplo n.º 6
0
        private async Task CheckKeepAliveTimeoutAsync(TimeSpan keepAlivePeriod, CancellationToken cancellationToken)
        {
            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    // Values described here: [MQTT-3.1.2-24].
                    if (_lastPacketReceivedTracker.Elapsed.TotalSeconds > keepAlivePeriod.TotalSeconds * 1.5D)
                    {
                        _logger.Warning <MqttClientSession>("Client '{0}': Did not receive any packet or keep alive signal.", ClientId);
                        await StopAsync();

                        return;
                    }

                    await Task.Delay(keepAlivePeriod, cancellationToken);
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception exception)
            {
                _logger.Error <MqttClientSession>(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", ClientId);
            }
            finally
            {
                _logger.Trace <MqttClientSession>("Client {0}: Stopped checking keep alive timeout.", ClientId);
            }
        }
Ejemplo n.º 7
0
        private async Task PublishQueuedMessagesAsync(CancellationToken cancellationToken)
        {
            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    var message = _messageQueue.Take(cancellationToken);
                    if (message == null)
                    {
                        continue;
                    }

                    if (cancellationToken.IsCancellationRequested)
                    {
                        continue;
                    }

                    await TryPublishQueuedMessageAsync(message).ConfigureAwait(false);
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception exception)
            {
                _logger.Error <ManagedMqttClient>(exception, "Unhandled exception while publishing queued application messages.");
            }
            finally
            {
                _logger.Trace <ManagedMqttClient>("Stopped publishing messages.");
            }
        }
Ejemplo n.º 8
0
        private async Task <GetOrCreateClientSessionResult> GetOrCreateClientSessionAsync(MqttConnectPacket connectPacket)
        {
            await _sessionsSemaphore.WaitAsync().ConfigureAwait(false);

            try
            {
                var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var clientSession);
                if (isSessionPresent)
                {
                    if (connectPacket.CleanSession)
                    {
                        _sessions.Remove(connectPacket.ClientId);
                        await clientSession.StopAsync();

                        clientSession = null;

                        _logger.Trace <MqttClientSessionsManager>("Stopped existing session of client '{0}'.", connectPacket.ClientId);
                    }
                    else
                    {
                        _logger.Trace <MqttClientSessionsManager>("Reusing existing session of client '{0}'.", connectPacket.ClientId);
                    }
                }

                var isExistingSession = true;
                if (clientSession == null)
                {
                    isExistingSession = false;

                    clientSession = new MqttClientSession(connectPacket.ClientId, _options, this, _logger);
                    _sessions[connectPacket.ClientId] = clientSession;

                    _logger.Trace <MqttClientSessionsManager>("Created a new session for client '{0}'.", connectPacket.ClientId);
                }

                return(new GetOrCreateClientSessionResult {
                    IsExistingSession = isExistingSession, Session = clientSession
                });
            }
            finally
            {
                _sessionsSemaphore.Release();
            }
        }
Ejemplo n.º 9
0
        private async Task HandleMessageInternalAsync(string clientId, MqttApplicationMessage applicationMessage)
        {
            var saveIsRequired = false;

            if (applicationMessage.Payload?.Any() == false)
            {
                saveIsRequired = _retainedMessages.Remove(applicationMessage.Topic);
                _logger.Info <MqttRetainedMessagesManager>("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic);
            }
            else
            {
                if (!_retainedMessages.ContainsKey(applicationMessage.Topic))
                {
                    _retainedMessages[applicationMessage.Topic] = applicationMessage;
                    saveIsRequired = true;
                }
                else
                {
                    var existingMessage = _retainedMessages[applicationMessage.Topic];
                    if (existingMessage.QualityOfServiceLevel != applicationMessage.QualityOfServiceLevel || !existingMessage.Payload.SequenceEqual(applicationMessage.Payload ?? new byte[0]))
                    {
                        _retainedMessages[applicationMessage.Topic] = applicationMessage;
                        saveIsRequired = true;
                    }
                }

                _logger.Info <MqttRetainedMessagesManager>("Client '{0}' set retained message for topic '{1}'.", clientId, applicationMessage.Topic);
            }

            if (!saveIsRequired)
            {
                _logger.Trace <MqttRetainedMessagesManager>("Skipped saving retained messages because no changes were detected.");
            }

            if (saveIsRequired && _options.Storage != null)
            {
                await _options.Storage.SaveRetainedMessagesAsync(_retainedMessages.Values.ToList());
            }
        }
Ejemplo n.º 10
0
        private async Task RunAsync(int keepAlivePeriod, CancellationToken cancellationToken)
        {
            try
            {
                _lastPacketReceivedTracker.Restart();
                _lastNonKeepAlivePacketReceivedTracker.Restart();

                while (!cancellationToken.IsCancellationRequested)
                {
                    // Values described here: [MQTT-3.1.2-24].
                    if (_lastPacketReceivedTracker.Elapsed.TotalSeconds > keepAlivePeriod * 1.5D)
                    {
                        _logger.Warning <MqttClientSession>("Client '{0}': Did not receive any packet or keep alive signal.", _clientId);

                        if (_timeoutCallback != null)
                        {
                            await _timeoutCallback().ConfigureAwait(false);
                        }

                        return;
                    }

                    await Task.Delay(keepAlivePeriod, cancellationToken).ConfigureAwait(false);
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception exception)
            {
                _logger.Error <MqttClientSession>(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", _clientId);
            }
            finally
            {
                _logger.Trace <MqttClientSession>("Client {0}: Stopped checking keep alive timeout.", _clientId);
            }
        }