Ejemplo n.º 1
0
        public void Enqueue(MqttBasePacket packet)
        {
            if (packet == null)
            {
                throw new ArgumentNullException(nameof(packet));
            }

            lock (_queue)
            {
                if (_queue.Count >= _options.MaxPendingMessagesPerClient)
                {
                    if (_options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropNewMessage)
                    {
                        return;
                    }

                    if (_options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage)
                    {
                        _queue.Dequeue();
                    }
                }

                _queue.Enqueue(packet);
            }

            _queueAutoResetEvent.Set();

            _logger.Verbose("Enqueued packet (ClientId: {0}).", _clientSession.ClientId);
        }
Ejemplo n.º 2
0
        public async Task HandleMessageAsync(string clientId, MqttMessage applicationMessage)
        {
            if (applicationMessage == null)
            {
                throw new ArgumentNullException(nameof(applicationMessage));
            }

            try
            {
                List <MqttMessage> messagesForSave = null;
                lock (_messages)
                {
                    var saveIsRequired = false;

                    if (applicationMessage.Payload?.Length == 0)
                    {
                        saveIsRequired = _messages.Remove(applicationMessage.Topic);
                        _logger.Verbose("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic);
                    }
                    else
                    {
                        if (!_messages.TryGetValue(applicationMessage.Topic, out var existingMessage))
                        {
                            _messages[applicationMessage.Topic] = applicationMessage;
                            saveIsRequired = true;
                        }
                        else
                        {
                            if (existingMessage.QualityOfServiceLevel != applicationMessage.QualityOfServiceLevel || !existingMessage.Payload.SequenceEqual(applicationMessage.Payload ?? new byte[0]))
                            {
                                _messages[applicationMessage.Topic] = applicationMessage;
                                saveIsRequired = true;
                            }
                        }

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

                    if (saveIsRequired)
                    {
                        messagesForSave = new List <MqttMessage>(_messages.Values);
                    }
                }

                if (messagesForSave == null)
                {
                    _logger.Verbose("Skipped saving retained messages because no changes were detected.");
                    return;
                }

                if (_options.Storage != null)
                {
                    await _options.Storage.SaveRetainedMessagesAsync(messagesForSave).ConfigureAwait(false);
                }
            }
            catch (Exception exception)
            {
                _logger.Error(exception, "Unhandled exception while handling retained messages.");
            }
        }
Ejemplo n.º 3
0
 public void Log_10000_Messages_NoHandler()
 {
     _useHandler = false;
     for (var i = 0; i < 10000; i++)
     {
         _childLogger.Verbose("test log message {0}", "parameter");
     }
 }
 public void DeleteSession(string clientId)
 {
     lock (_sessions)
     {
         _sessions.Remove(clientId);
     }
     _logger.Verbose("Session for client '{0}' deleted.", clientId);
 }
Ejemplo n.º 5
0
        public async Task HandleMessageAsync(string clientId, MqttApplicationMessage applicationMessage)
        {
            if (applicationMessage == null)
            {
                throw new ArgumentNullException(nameof(applicationMessage));
            }

            try
            {
                using (await _messagesLock.WaitAsync().ConfigureAwait(false))
                {
                    var saveIsRequired = false;
                    var hasPayload     = applicationMessage.Payload != null && applicationMessage.Payload.Length > 0;

                    if (!hasPayload)
                    {
                        saveIsRequired = _messages.Remove(applicationMessage.Topic);
                        _logger.Verbose("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic);
                    }
                    else
                    {
                        if (!_messages.TryGetValue(applicationMessage.Topic, out var existingMessage))
                        {
                            _messages[applicationMessage.Topic] = applicationMessage;
                            saveIsRequired = true;
                        }
                        else
                        {
                            if (existingMessage.QualityOfServiceLevel != applicationMessage.QualityOfServiceLevel || !existingMessage.Payload.SequenceEqual(applicationMessage.Payload ?? _emptyArray))
                            {
                                _messages[applicationMessage.Topic] = applicationMessage;
                                saveIsRequired = true;
                            }
                        }

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

                    if (saveIsRequired)
                    {
                        if (_options.Storage != null)
                        {
                            var messagesForSave = new List <MqttApplicationMessage>(_messages.Values);
                            await _options.Storage.SaveRetainedMessagesAsync(messagesForSave).ConfigureAwait(false);
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                _logger.Error(exception, "Unhandled exception while handling retained messages.");
            }
        }
Ejemplo n.º 6
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
            {
                _cancellationTokenSource = new CancellationTokenSource();
                _disconnectReason        = new TaskCompletionSource <bool>();
                _options = options;
                _packetIdentifierProvider.Reset();
                _packetDispatcher.Reset();

                _adapter = _adapterFactory.CreateClientAdapter(options, _logger);

                _logger.Verbose($"Trying to connect with server ({_options.ChannelOptions}).");
                await _adapter.ConnectAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token).ConfigureAwait(false);

                _logger.Verbose("Connection with server established.");

                StartReceivingPackets(_cancellationTokenSource.Token);

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

                _logger.Verbose("MQTT connection with server established.");

                _sendTracker.Restart();

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

                IsConnected = true;
                Connected?.Invoke(this, new MqttClientConnectedEventArgs(connectResponse.IsSessionPresent));

                _logger.Info("Connected.");
                return(new MqttClientConnectResult(connectResponse.IsSessionPresent));
            }
            catch (Exception exception)
            {
                _logger.Error(exception, "Error while connecting with server.");
                if (_disconnectReason.TrySetException(exception))
                {
                    await DisconnectInternalAsync(null, exception).ConfigureAwait(false);
                }
                throw;
            }
        }
        public async Task DeleteSessionAsync(string clientId)
        {
            if (_connections.TryGetValue(clientId, out var connection))
            {
                await connection.StopAsync().ConfigureAwait(false);
            }

            if (_sessions.TryRemove(clientId, out _))
            {
            }

            _logger.Verbose("Session for client '{0}' deleted.", clientId);
        }
        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 (!_isPaused && _lastPacketReceivedTracker.Elapsed.TotalSeconds > keepAlivePeriod * 1.5D)
                    {
                        _logger.Warning(null, "Client '{0}': Did not receive any packet or keep alive signal.", _clientSession.ClientId);
                        _clientSession.Stop(MqttClientDisconnectType.NotClean);

                        return;
                    }

                    await Task.Delay(keepAlivePeriod, cancellationToken).ConfigureAwait(false);
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception exception)
            {
                _logger.Error(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", _clientSession.ClientId);
            }
            finally
            {
                _logger.Verbose("Client {0}: Stopped checking keep alive timeout.", _clientSession.ClientId);
            }
        }
Ejemplo n.º 9
0
        private void PublishQueuedMessages(CancellationToken cancellationToken)
        {
            try
            {
                while (!cancellationToken.IsCancellationRequested && _mqttClient.IsConnected)
                {
                    var message = _messageQueue.Take(cancellationToken);
                    if (message == null)
                    {
                        continue;
                    }

                    cancellationToken.ThrowIfCancellationRequested();

                    TryPublishQueuedMessage(message);
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception exception)
            {
                _logger.Error(exception, "Unhandled exception while publishing queued application messages.");
            }
            finally
            {
                _logger.Verbose("Stopped publishing messages.");
            }
        }
        private async Task HandleMessageInternalAsync(string clientId, MqttApplicationMessage applicationMessage)
        {
            var saveIsRequired = false;

            lock (_messages)
            {
                if (applicationMessage.Payload?.Length == 0)
                {
                    saveIsRequired = _messages.Remove(applicationMessage.Topic);
                    _logger.Verbose("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic);
                }
                else
                {
                    if (!_messages.TryGetValue(applicationMessage.Topic, out var existingMessage))
                    {
                        _messages[applicationMessage.Topic] = applicationMessage;
                        saveIsRequired = true;
                    }
                    else
                    {
                        if (existingMessage.QualityOfServiceLevel != applicationMessage.QualityOfServiceLevel || !existingMessage.Payload.SequenceEqual(applicationMessage.Payload ?? new byte[0]))
                        {
                            _messages[applicationMessage.Topic] = applicationMessage;
                            saveIsRequired = true;
                        }
                    }

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

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

            if (saveIsRequired && _options.Storage != null)
            {
                List <MqttApplicationMessage> messages;
                lock (_messages)
                {
                    messages = _messages.Values.ToList();
                }

                await _options.Storage.SaveRetainedMessagesAsync(messages).ConfigureAwait(false);
            }
        }
Ejemplo n.º 11
0
        public async Task PublishAsync(MqttManagedMessage applicationMessage)
        {
            if (applicationMessage == null)
            {
                throw new ArgumentNullException(nameof(applicationMessage));
            }

            MqttManagedMessage removedMessage = null;

            lock (_messageQueue)
            {
                if (Options != null)
                {
                    if (_messageQueue.Count >= Options.MaxPendingMessages)
                    {
                        if (Options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropNewMessage)
                        {
                            _logger.Verbose("Skipping publish of new application message because internal queue is full.");
                            ApplicationMessageSkipped?.Invoke(this, new MqttMessageSkippedEventArgs(applicationMessage));
                            return;
                        }

                        if (Options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage)
                        {
                            removedMessage = _messageQueue.RemoveFirst();
                            _logger.Verbose("Removed oldest application message from internal queue because it is full.");
                            ApplicationMessageSkipped?.Invoke(this, new MqttMessageSkippedEventArgs(removedMessage));
                        }
                    }
                }

                _messageQueue.Enqueue(applicationMessage);
            }

            if (_storageManager != null)
            {
                if (removedMessage != null)
                {
                    await _storageManager.RemoveAsync(removedMessage).ConfigureAwait(false);
                }

                await _storageManager.AddAsync(applicationMessage).ConfigureAwait(false);
            }
        }
Ejemplo n.º 12
0
        public async Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
        {
            ThrowIfDisposed();

            try
            {
                _logger.Verbose("Connecting [Timeout={0}]", timeout);

                await Common.TaskExtensions
                .TimeoutAfterAsync(ct => _channel.ConnectAsync(), timeout, cancellationToken)
                .ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                if (IsWrappedException(exception))
                {
                    throw;
                }

                WrapException(exception);
            }
        }
Ejemplo n.º 13
0
        public void EnqueueApplicationMessage(MqttApplicationMessage applicationMessage, string senderClientId, bool isRetainedApplicationMessage)
        {
            var checkSubscriptionsResult = SubscriptionsManager.CheckSubscriptions(applicationMessage.Topic, applicationMessage.QualityOfServiceLevel);

            if (!checkSubscriptionsResult.IsSubscribed)
            {
                return;
            }

            _logger.Verbose("Queued application message with topic '{0}' (ClientId: {1}).", applicationMessage.Topic, ClientId);

            ApplicationMessagesQueue.Enqueue(applicationMessage, senderClientId, checkSubscriptionsResult.QualityOfServiceLevel, isRetainedApplicationMessage);
        }
Ejemplo n.º 14
0
        public async Task SendPacketAsync(MqttBasePacket packet, TimeSpan timeout, CancellationToken cancellationToken)
        {
            await _writerSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);

            try
            {
                var packetData = PacketFormatterAdapter.Encode(packet);

                if (timeout == TimeSpan.Zero)
                {
                    await _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    await MqttTaskTimeout.WaitAsync(
                        t => _channel.WriteAsync(packetData.Array, packetData.Offset, packetData.Count, t), timeout, cancellationToken).ConfigureAwait(false);
                }

                Interlocked.Add(ref _bytesReceived, packetData.Count);

                PacketFormatterAdapter.FreeBuffer();

                _logger.Verbose("TX ({0} bytes) >>> {1}", packetData.Count, packet);
            }
            catch (Exception exception)
            {
                if (IsWrappedException(exception))
                {
                    throw;
                }

                WrapException(exception);
            }
            finally
            {
                _writerSemaphore.Release();
            }
        }
Ejemplo n.º 15
0
        private async Task AcceptClientConnectionsAsync()
        {
            while (!_cancellationToken.IsCancellationRequested)
            {
                try
                {
#if NET452 || NET461
                    var clientSocket = await Task.Factory.FromAsync(_socket.BeginAccept, _socket.EndAccept, null).ConfigureAwait(false);
#else
                    var clientSocket = await _socket.AcceptAsync().ConfigureAwait(false);
#endif
                    clientSocket.NoDelay = true;

                    SslStream sslStream = null;

                    if (_tlsCertificate != null)
                    {
                        sslStream = new SslStream(new NetworkStream(clientSocket), false);
                        await sslStream.AuthenticateAsServerAsync(_tlsCertificate, false, _tlsOptions.SslProtocol, false).ConfigureAwait(false);
                    }

                    _logger.Verbose("Client '{0}' accepted by TCP listener '{1}, {2}'.",
                                    clientSocket.RemoteEndPoint,
                                    _socket.LocalEndPoint,
                                    _addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6");

                    var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, sslStream), new MqttPacketSerializer(), _logger);
                    ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
                }
                catch (ObjectDisposedException)
                {
                    // It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed.
                }
                catch (Exception exception)
                {
                    if (exception is SocketException s && s.SocketErrorCode == SocketError.OperationAborted)
                    {
                        return;
                    }

                    _logger.Error(exception, $"Error while accepting connection at TCP listener {_socket.LocalEndPoint} TLS={_tlsCertificate != null}.");
                    await Task.Delay(TimeSpan.FromSeconds(1), _cancellationToken).ConfigureAwait(false);
                }
            }
        }
Ejemplo n.º 16
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 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.
                    if (!_isPaused && _lastPacketReceivedTracker.Elapsed.TotalSeconds >= keepAlivePeriod * 1.5D)
                    {
                        _logger.Warning(null, "Client '{0}': Did not receive any packet or keep alive signal.", _clientSession.ClientId);
                        _clientSession.Stop(MqttClientDisconnectType.NotClean);

                        return;
                    }

                    // The server checks the keep alive timeout every 50 % of the overall keep alive timeout
                    // because the server allows 1.5 times the keep alive value. This means that a value of 5 allows
                    // up to 7.5 seconds. With an interval of 2.5 (5 / 2) the 7.5 is also affected. Waiting the whole
                    // keep alive time will hit at 10 instead of 7.5 (but only one time instead of two times).
                    await Task.Delay(TimeSpan.FromSeconds(keepAlivePeriod * 0.5D), cancellationToken).ConfigureAwait(false);
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception exception)
            {
                _logger.Error(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", _clientSession.ClientId);
            }
            finally
            {
                _logger.Verbose("Client '{0}': Stopped checking keep alive timeout.", _clientSession.ClientId);
            }
        }
        private async Task RunInternalAsync(MqttConnectPacket connectPacket, IMqttChannelAdapter adapter)
        {
            if (connectPacket == null)
            {
                throw new ArgumentNullException(nameof(connectPacket));
            }
            if (adapter == null)
            {
                throw new ArgumentNullException(nameof(adapter));
            }

            try
            {
                if (_cancellationTokenSource != null)
                {
                    Stop(MqttClientDisconnectType.Clean, true);
                }

                adapter.ReadingPacketStarted   += OnAdapterReadingPacketStarted;
                adapter.ReadingPacketCompleted += OnAdapterReadingPacketCompleted;

                _cancellationTokenSource = new CancellationTokenSource();

                //workaround for https://github.com/dotnet/corefx/issues/24430
#pragma warning disable 4014
                _cleanupHandle = _cancellationTokenSource.Token.Register(async() =>
                {
                    await TryDisconnectAdapterAsync(adapter).ConfigureAwait(false);
                    TryDisposeAdapter(adapter);
                });
#pragma warning restore 4014
                //end workaround

                _wasCleanDisconnect = false;
                _willMessage        = connectPacket.WillMessage;

                _pendingPacketsQueue.Start(adapter, _cancellationTokenSource.Token);
                _keepAliveMonitor.Start(connectPacket.KeepAlivePeriod, _cancellationTokenSource.Token);

                _adapterEndpoint        = adapter.Endpoint;
                _adapterProtocolVersion = adapter.PacketSerializer.ProtocolVersion;

                while (!_cancellationTokenSource.IsCancellationRequested)
                {
                    var packet = await adapter.ReceivePacketAsync(TimeSpan.Zero, _cancellationTokenSource.Token).ConfigureAwait(false);

                    if (packet != null)
                    {
                        _keepAliveMonitor.PacketReceived(packet);
                        ProcessReceivedPacket(adapter, packet, _cancellationTokenSource.Token);
                    }
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception exception)
            {
                if (exception is MqttCommunicationException)
                {
                    if (exception is MqttCommunicationClosedGracefullyException)
                    {
                        _logger.Verbose("Client '{0}': Connection closed gracefully.", ClientId);
                    }
                    else
                    {
                        _logger.Warning(exception, "Client '{0}': Communication exception while receiving client packets.", ClientId);
                    }
                }
                else
                {
                    _logger.Error(exception, "Client '{0}': Unhandled exception while receiving client packets.", ClientId);
                }

                Stop(MqttClientDisconnectType.NotClean, true);
            }
            finally
            {
                _adapterEndpoint        = null;
                _adapterProtocolVersion = null;

                // Uncomment as soon as the workaround above is no longer needed.
                //await TryDisconnectAdapterAsync(adapter).ConfigureAwait(false);
                //TryDisposeAdapter(adapter);

                _cleanupHandle?.Dispose();
                _cleanupHandle = null;

                _cancellationTokenSource?.Cancel(false);
                _cancellationTokenSource?.Dispose();
                _cancellationTokenSource = null;
            }
        }
Ejemplo n.º 18
0
        private async Task TryHandleClientConnectionAsync(Socket clientSocket)
        {
            var socketIndex = Interlocked.Increment(ref latestSocketIndex);

            string    clientPrefix  = null;
            string    serverEndPont = null;
            SslStream sslStream     = null;
            var       stopwatch     = new Stopwatch();

            try
            {
                stopwatch.Start();

                clientPrefix  = $"Socket[{socketIndex}, {clientSocket.RemoteEndPoint}]";
                serverEndPont = string.Format("{0}, {1}, {2}",
                                              _socket.LocalEndPoint,
                                              _addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6",
                                              _tlsCertificate == null ? "tcp" : "tls");

                _logger.Verbose($"{clientPrefix} > Accepted by TCP listener '{serverEndPont}'. Time:{stopwatch.Elapsed.TotalMilliseconds}ms");

                clientSocket.NoDelay = true;

                if (_tlsCertificate != null)
                {//如果不设置超时,AuthenticateAsServerAsync 可能会一直阻塞下去
                    clientSocket.ReceiveTimeout = (int)_communicationTimeout.TotalMilliseconds;
                    clientSocket.SendTimeout    = (int)_communicationTimeout.TotalMilliseconds;

                    var stream = new NetworkStream(clientSocket, true);
                    sslStream = new SslStream(stream, false);

                    var cancellationTokenDisposeSslStream = new CancellationTokenSource();
                    var taskDisposeSslStream = Task.Delay(_communicationTimeout, cancellationTokenDisposeSslStream.Token)
                                               .ContinueWith((task) =>
                    {
                        if (task.IsCanceled)
                        {
                            return;
                        }
                        if (cancellationTokenDisposeSslStream.IsCancellationRequested)
                        {
                            return;
                        }

                        //超时,则清理掉
                        Cleanup(clientSocket, sslStream);
                    });

                    await sslStream.AuthenticateAsServerAsync(_tlsCertificate, false, _tlsOptions.SslProtocol, false).ConfigureAwait(false);

                    cancellationTokenDisposeSslStream.Cancel();

                    _logger.Verbose($"{clientPrefix} > SslStream created. Time:{stopwatch.Elapsed.TotalMilliseconds}ms");
                }

                _logger.Verbose($"{clientPrefix} > Processed. Time:{stopwatch.Elapsed.TotalMilliseconds}ms");

                if (ClientAccepted != null)
                {
                    using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, sslStream), new MqttPacketSerializer(), _logger))
                    {
                        var args = new MqttServerAdapterClientAcceptedEventArgs(clientAdapter);
                        ClientAccepted.Invoke(this, args);
                        await args.SessionTask.ConfigureAwait(false);
                    }
                }
            }
            catch (ObjectDisposedException exception)
            {
                // It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed.
                _logger.Error(exception, $"{clientPrefix} > Error while handling client connection. Listener:'{serverEndPont}' Time:{stopwatch.Elapsed.TotalMilliseconds}ms Disposed");
            }
            catch (Exception exception)
            {
                Cleanup(clientSocket, sslStream);

                if (exception is SocketException s && s.SocketErrorCode == SocketError.OperationAborted)
                {
                    _logger.Error(exception, $"{clientPrefix} > Error while handling client connection. Listener:'{serverEndPont}' Time:{stopwatch.Elapsed.TotalMilliseconds}ms OperationAborted");
                    return;
                }
                if (exception is System.IO.IOException ioException)
                {
                    _logger.Error(exception, $"{clientPrefix} > Error while handling client connection. Listener:'{serverEndPont}' Time:{stopwatch.Elapsed.TotalMilliseconds}ms IOException");
                    return;
                }

                _logger.Error(exception, $"{clientPrefix} > Error while handling client connection. Listener:'{serverEndPont}' Time:{stopwatch.Elapsed.TotalMilliseconds}ms Unknown");
            }
            finally
            {
                try
                {
                    Cleanup(clientSocket, sslStream);

                    _logger.Verbose($"{clientPrefix} > Disconnected at TCP listener '{serverEndPont}'. Time:{stopwatch.Elapsed.TotalMilliseconds}ms");
                }
                catch (Exception disposeException)
                {
                    _logger.Error(disposeException, $"{clientPrefix} > Error while cleaning up client connection. Listener:'{serverEndPont}' Time:{stopwatch.Elapsed.TotalMilliseconds}ms");
                }

                stopwatch.Stop();
            }
        }
Ejemplo n.º 19
0
        public async Task <MqttClientAuthenticateResult> ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken)
        {
            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.");

            ThrowIfDisposed();

            MqttClientAuthenticateResult authenticateResult = null;

            try
            {
                Options = options;

                _packetIdentifierProvider.Reset();
                _packetDispatcher.Reset();

                _backgroundCancellationTokenSource = new CancellationTokenSource();
                var backgroundCancellationToken = _backgroundCancellationTokenSource.Token;

                _disconnectGate = 0;
                var adapter = _adapterFactory.CreateClientAdapter(options, _logger);
                _adapter = adapter;

                using (var combined = CancellationTokenSource.CreateLinkedTokenSource(backgroundCancellationToken, cancellationToken))
                {
                    _logger.Verbose($"Trying to connect with server '{options.ChannelOptions}' (Timeout={options.CommunicationTimeout}).");
                    await _adapter.ConnectAsync(options.CommunicationTimeout, combined.Token).ConfigureAwait(false);

                    _logger.Verbose("Connection with server established.");

                    _packetReceiverTask = Task.Run(() => TryReceivePacketsAsync(backgroundCancellationToken), backgroundCancellationToken);

                    authenticateResult = await AuthenticateAsync(adapter, options.WillMessage, combined.Token).ConfigureAwait(false);
                }

                _sendTracker.Restart();
                _receiveTracker.Restart();

                if (Options.KeepAlivePeriod != TimeSpan.Zero)
                {
                    _keepAlivePacketsSenderTask = Task.Run(() => TrySendKeepAliveMessagesAsync(backgroundCancellationToken), backgroundCancellationToken);
                }

                IsConnected = true;

                _logger.Info("Connected.");

                var connectedHandler = ConnectedHandler;
                if (connectedHandler != null)
                {
                    await connectedHandler.HandleConnectedAsync(new MqttClientConnectedEventArgs(authenticateResult)).ConfigureAwait(false);
                }

                return(authenticateResult);
            }
            catch (Exception exception)
            {
                _logger.Error(exception, "Error while connecting with server.");

                if (!DisconnectIsPending())
                {
                    await DisconnectInternalAsync(null, exception, authenticateResult).ConfigureAwait(false);
                }

                throw;
            }
        }
Ejemplo n.º 20
0
        public async Task <bool> RunAsync(MqttConnectPacket connectPacket, IMqttChannelAdapter adapter)
        {
            if (connectPacket == null)
            {
                throw new ArgumentNullException(nameof(connectPacket));
            }
            if (adapter == null)
            {
                throw new ArgumentNullException(nameof(adapter));
            }

            try
            {
                _adapter = adapter;
                adapter.ReadingPacketStarted   += OnAdapterReadingPacketStarted;
                adapter.ReadingPacketCompleted += OnAdapterReadingPacketCompleted;

                _cancellationTokenSource = new CancellationTokenSource();
                _wasCleanDisconnect      = false;
                _willMessage             = connectPacket.WillMessage;

                _pendingPacketsQueue.Start(adapter, _cancellationTokenSource.Token);
                _keepAliveMonitor.Start(connectPacket.KeepAlivePeriod, _cancellationTokenSource.Token);

                while (!_cancellationTokenSource.IsCancellationRequested)
                {
                    var packet = await adapter.ReceivePacketAsync(TimeSpan.Zero, _cancellationTokenSource.Token).ConfigureAwait(false);

                    if (packet != null)
                    {
                        _keepAliveMonitor.PacketReceived(packet);
                        ProcessReceivedPacket(adapter, packet, _cancellationTokenSource.Token);
                    }
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception exception)
            {
                if (exception is MqttCommunicationException)
                {
                    if (exception is MqttCommunicationClosedGracefullyException)
                    {
                        _logger.Verbose("Client '{0}': Connection closed gracefully.", ClientId);
                    }
                    else
                    {
                        _logger.Warning(exception, "Client '{0}': Communication exception while receiving client packets.", ClientId);
                    }
                }
                else
                {
                    _logger.Error(exception, "Client '{0}': Unhandled exception while receiving client packets.", ClientId);
                }

                Stop(MqttClientDisconnectType.NotClean);
            }
            finally
            {
                if (_adapter != null)
                {
                    _adapter.ReadingPacketStarted   -= OnAdapterReadingPacketStarted;
                    _adapter.ReadingPacketCompleted -= OnAdapterReadingPacketCompleted;
                }

                _adapter = null;

                _cancellationTokenSource?.Dispose();
                _cancellationTokenSource = null;
            }

            return(_wasCleanDisconnect);
        }
Ejemplo n.º 21
0
        private async Task TryHandleClientConnectionAsync(Socket clientSocket)
        {
            Stream stream         = null;
            string remoteEndPoint = null;

            try
            {
                remoteEndPoint = clientSocket.RemoteEndPoint.ToString();

                _logger.Verbose("Client '{0}' accepted by TCP listener '{1}, {2}'.",
                                remoteEndPoint,
                                _socket.LocalEndPoint,
                                _addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6");

                clientSocket.NoDelay = _options.NoDelay;

                stream = new NetworkStream(clientSocket, true);

                if (_tlsCertificate != null)
                {
                    var sslStream = new SslStream(stream, false);
                    await sslStream.AuthenticateAsServerAsync(_tlsCertificate, false, _tlsOptions.SslProtocol, false).ConfigureAwait(false);

                    stream = sslStream;
                }

                var clientHandler = ClientHandler;
                if (clientHandler != null)
                {
                    using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(stream, remoteEndPoint), new MqttPacketFormatterAdapter(), _logger))
                    {
                        await clientHandler(clientAdapter).ConfigureAwait(false);
                    }
                }
            }
            catch (Exception exception)
            {
                if (exception is ObjectDisposedException)
                {
                    // It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed.
                    return;
                }

                if (exception is SocketException socketException &&
                    socketException.SocketErrorCode == SocketError.OperationAborted)
                {
                    return;
                }

                _logger.Error(exception, "Error while handling client connection.");
            }
            finally
            {
                try
                {
                    stream?.Dispose();
                    clientSocket?.Dispose();

                    _logger.Verbose("Client '{0}' disconnected at TCP listener '{1}, {2}'.",
                                    remoteEndPoint,
                                    _socket.LocalEndPoint,
                                    _addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6");
                }
                catch (Exception disposeException)
                {
                    _logger.Error(disposeException, "Error while cleaning up client connection");
                }
            }
        }
Ejemplo n.º 22
0
        private async Task SendPendingPacketsAsync(CancellationToken cancellationToken)
        {
            MqttQueuedApplicationMessage queuedApplicationMessage = null;
            MqttPublishPacket            publishPacket            = null;

            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    queuedApplicationMessage = await Session.ApplicationMessagesQueue.TakeAsync(cancellationToken).ConfigureAwait(false);

                    if (queuedApplicationMessage == null)
                    {
                        return;
                    }

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    publishPacket = _dataConverter.CreatePublishPacket(queuedApplicationMessage.ApplicationMessage);
                    publishPacket.QualityOfServiceLevel = queuedApplicationMessage.QualityOfServiceLevel;

                    // Set the retain flag to true according to [MQTT-3.3.1-8] and [MQTT-3.3.1-9].
                    publishPacket.Retain = queuedApplicationMessage.IsRetainedMessage;

                    if (publishPacket.QualityOfServiceLevel > 0)
                    {
                        publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
                    }

                    if (_serverOptions.ClientMessageQueueInterceptor != null)
                    {
                        var context = new MqttClientMessageQueueInterceptorContext(
                            queuedApplicationMessage.SenderClientId,
                            ClientId,
                            queuedApplicationMessage.ApplicationMessage);

                        if (_serverOptions.ClientMessageQueueInterceptor != null)
                        {
                            await _serverOptions.ClientMessageQueueInterceptor.InterceptClientMessageQueueEnqueueAsync(context).ConfigureAwait(false);
                        }

                        if (!context.AcceptEnqueue || context.ApplicationMessage == null)
                        {
                            return;
                        }

                        publishPacket.Topic   = context.ApplicationMessage.Topic;
                        publishPacket.Payload = context.ApplicationMessage.Payload;
                        publishPacket.QualityOfServiceLevel = context.ApplicationMessage.QualityOfServiceLevel;
                    }

                    if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
                    {
                        await SendAsync(publishPacket).ConfigureAwait(false);
                    }
                    else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
                    {
                        var awaiter = _packetDispatcher.AddPacketAwaiter <MqttPubAckPacket>(publishPacket.PacketIdentifier);
                        await SendAsync(publishPacket).ConfigureAwait(false);

                        await awaiter.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
                    }
                    else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
                    {
                        using (var awaiter1 = _packetDispatcher.AddPacketAwaiter <MqttPubRecPacket>(publishPacket.PacketIdentifier))
                            using (var awaiter2 = _packetDispatcher.AddPacketAwaiter <MqttPubCompPacket>(publishPacket.PacketIdentifier))
                            {
                                await SendAsync(publishPacket).ConfigureAwait(false);

                                await awaiter1.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);

                                await SendAsync(new MqttPubRelPacket { PacketIdentifier = publishPacket.PacketIdentifier }).ConfigureAwait(false);

                                await awaiter2.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
                            }
                    }

                    _logger.Verbose("Queued application message sent (ClientId: {0}).", ClientId);

                    // TODO:
                    //Interlocked.Increment(ref _sentPacketsCount);
                }
            }
            catch (Exception exception)
            {
                if (exception is MqttCommunicationTimedOutException)
                {
                    _logger.Warning(exception, "Sending publish packet failed: Timeout (ClientId: {0}).", ClientId);
                }
                else if (exception is MqttCommunicationException)
                {
                    _logger.Warning(exception, "Sending publish packet failed: Communication exception (ClientId: {0}).", ClientId);
                }
                else if (exception is OperationCanceledException && _cancellationToken.Token.IsCancellationRequested)
                {
                    // The cancellation was triggered externally.
                }
                else
                {
                    _logger.Error(exception, "Sending publish packet failed (ClientId: {0}).", ClientId);
                }

                if (publishPacket?.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
                {
                    queuedApplicationMessage.IsDuplicate = true;

                    Session.ApplicationMessagesQueue.Enqueue(queuedApplicationMessage);
                }

                if (!_cancellationToken.Token.IsCancellationRequested)
                {
                    await StopAsync().ConfigureAwait(false);
                }
            }
        }