예제 #1
0
        private async Task ReceivePackets(CancellationToken cancellationToken)
        {
            MqttTrace.Information(nameof(MqttClient), "Start receiving packets.");
            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    var mqttPacket = await _adapter.ReceivePacketAsync(TimeSpan.Zero);

                    MqttTrace.Information(nameof(MqttClient), $"Received <<< {mqttPacket}");

                    Task.Run(() => ProcessReceivedPacket(mqttPacket), cancellationToken).Forget();
                }
            }
            catch (MqttCommunicationException exception)
            {
                MqttTrace.Warning(nameof(MqttClient), exception, "MQTT communication error while receiving packets.");
            }
            catch (Exception exception)
            {
                MqttTrace.Error(nameof(MqttClient), exception, "Error while receiving packets.");
            }
            finally
            {
                MqttTrace.Information(nameof(MqttClient), "Stopped receiving packets.");
                await DisconnectInternalAsync();
            }
        }
예제 #2
0
        private async Task ReceivePackets(CancellationToken cancellationToken)
        {
            MqttTrace.Information(nameof(MqttClient), "Start receiving packets.");
            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    var mqttPacket = await _adapter.ReceivePacketAsync(TimeSpan.Zero);

                    MqttTrace.Information(nameof(MqttClient), $"Received <<< {mqttPacket}");

#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                    Task.Run(() => ProcessReceivedPacketAsync(mqttPacket), cancellationToken);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                }
            }
            catch (MqttCommunicationException exception)
            {
                MqttTrace.Warning(nameof(MqttClient), exception, "MQTT communication error while receiving packets.");
            }
            catch (Exception exception)
            {
                MqttTrace.Error(nameof(MqttClient), exception, "Error while receiving packets.");
            }
            finally
            {
                MqttTrace.Information(nameof(MqttClient), "Stopped receiving packets.");
                await DisconnectInternalAsync();
            }
        }
예제 #3
0
        private async Task SendKeepAliveMessagesAsync(CancellationToken cancellationToken)
        {
            MqttTrace.Information(nameof(MqttClient), "Start sending keep alive packets.");

            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    await Task.Delay(_options.KeepAlivePeriod, cancellationToken);
                    await SendAndReceiveAsync <MqttPingRespPacket>(new MqttPingReqPacket());
                }
            }
            catch (MqttCommunicationException exception)
            {
                MqttTrace.Warning(nameof(MqttClient), exception, "MQTT communication error while receiving packets.");
            }
            catch (Exception exception)
            {
                MqttTrace.Warning(nameof(MqttClient), exception, "Error while sending/receiving keep alive packets.");
            }
            finally
            {
                MqttTrace.Information(nameof(MqttClient), "Stopped sending keep alive packets.");
                await DisconnectInternalAsync();
            }
        }
예제 #4
0
        private async Task DisconnectInternalAsync()
        {
            var cts = _cancellationTokenSource;

            if (cts == null || cts.IsCancellationRequested)
            {
                return;
            }

            cts.Cancel(false);
            cts.Dispose();
            _cancellationTokenSource = null;

            try
            {
                await _adapter.DisconnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false);

                MqttTrace.Information(nameof(MqttClient), "Disconnected from adapter.");
            }
            catch (Exception exception)
            {
                MqttTrace.Warning(nameof(MqttClient), exception, "Error while disconnecting from adapter.");
            }
            finally
            {
                Disconnected?.Invoke(this, EventArgs.Empty);
            }
        }
예제 #5
0
        private async Task TrySendPendingPublishPacketAsync(MqttClientPublishPacketContext publishPacketContext)
        {
            try
            {
                if (_adapter == null)
                {
                    return;
                }

                publishPacketContext.PublishPacket.Dup = publishPacketContext.SendTries > 0;
                await _adapter.SendPacketAsync(publishPacketContext.PublishPacket, _options.DefaultCommunicationTimeout);

                publishPacketContext.IsSent = true;
            }
            catch (MqttCommunicationException exception)
            {
                MqttTrace.Warning(nameof(MqttClientMessageQueue), exception, "Sending publish packet failed.");
            }
            catch (Exception exception)
            {
                MqttTrace.Error(nameof(MqttClientMessageQueue), exception, "Sending publish packet failed.");
            }
            finally
            {
                publishPacketContext.SendTries++;
            }
        }
예제 #6
0
        private Task HandleIncomingPacketAsync(MqttBasePacket packet)
        {
            var subscribePacket = packet as MqttSubscribePacket;

            if (subscribePacket != null)
            {
                return(_adapter.SendPacketAsync(_subscriptionsManager.Subscribe(subscribePacket), _options.DefaultCommunicationTimeout));
            }

            var unsubscribePacket = packet as MqttUnsubscribePacket;

            if (unsubscribePacket != null)
            {
                return(_adapter.SendPacketAsync(_subscriptionsManager.Unsubscribe(unsubscribePacket), _options.DefaultCommunicationTimeout));
            }

            var publishPacket = packet as MqttPublishPacket;

            if (publishPacket != null)
            {
                return(HandleIncomingPublishPacketAsync(publishPacket));
            }

            var pubRelPacket = packet as MqttPubRelPacket;

            if (pubRelPacket != null)
            {
                return(HandleIncomingPubRelPacketAsync(pubRelPacket));
            }

            var pubAckPacket = packet as MqttPubAckPacket;

            if (pubAckPacket != null)
            {
                return(HandleIncomingPubAckPacketAsync(pubAckPacket));
            }

            if (packet is MqttPingReqPacket)
            {
                return(_adapter.SendPacketAsync(new MqttPingRespPacket(), _options.DefaultCommunicationTimeout));
            }

            if (packet is MqttDisconnectPacket || packet is MqttConnectPacket)
            {
                _cancellationTokenSource.Cancel();
                return(Task.FromResult((object)null));
            }

            MqttTrace.Warning(nameof(MqttClientSession), $"Client '{_identifier}': Received not supported packet ({packet}). Closing connection.");
            _cancellationTokenSource.Cancel();

            return(Task.FromResult((object)null));
        }
예제 #7
0
        private Task HandleIncomingPacketAsync(MqttBasePacket packet)
        {
            if (packet is MqttSubscribePacket subscribePacket)
            {
                return(Adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, _cancellationTokenSource.Token, _subscriptionsManager.Subscribe(subscribePacket)));
            }

            if (packet is MqttUnsubscribePacket unsubscribePacket)
            {
                return(Adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, _cancellationTokenSource.Token, _subscriptionsManager.Unsubscribe(unsubscribePacket)));
            }

            if (packet is MqttPublishPacket publishPacket)
            {
                return(HandleIncomingPublishPacketAsync(publishPacket));
            }

            if (packet is MqttPubRelPacket pubRelPacket)
            {
                return(HandleIncomingPubRelPacketAsync(pubRelPacket));
            }

            if (packet is MqttPubRecPacket pubRecPacket)
            {
                return(Adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, _cancellationTokenSource.Token, pubRecPacket.CreateResponse <MqttPubRelPacket>()));
            }

            if (packet is MqttPubAckPacket || packet is MqttPubCompPacket)
            {
                // Discard message.
                return(Task.FromResult((object)null));
            }

            if (packet is MqttPingReqPacket)
            {
                return(Adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, _cancellationTokenSource.Token, new MqttPingRespPacket()));
            }

            if (packet is MqttDisconnectPacket || packet is MqttConnectPacket)
            {
                _cancellationTokenSource.Cancel();
                return(Task.FromResult((object)null));
            }

            MqttTrace.Warning(nameof(MqttClientSession), "Client '{0}': Received not supported packet ({1}). Closing connection.", _identifier, packet);
            _cancellationTokenSource.Cancel();

            return(Task.FromResult((object)null));
        }
예제 #8
0
        private async Task ReceivePackets(CancellationToken cancellationToken)
        {
            MqttTrace.Information(nameof(MqttClient), "Start receiving packets.");

            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    var packet = await _adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(false);

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    StartProcessReceivedPacket(packet, cancellationToken);
                }
            }
            catch (TaskCanceledException)
            {
            }
            catch (MqttCommunicationException exception)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                MqttTrace.Warning(nameof(MqttClient), exception, "MQTT communication exception while receiving packets.");
                await DisconnectInternalAsync().ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                MqttTrace.Error(nameof(MqttClient), exception, "Unhandled exception while receiving packets.");
                await DisconnectInternalAsync().ConfigureAwait(false);
            }
            finally
            {
                MqttTrace.Information(nameof(MqttClient), "Stopped receiving packets.");
            }
        }
예제 #9
0
        private async Task SendKeepAliveMessagesAsync(CancellationToken cancellationToken)
        {
            MqttTrace.Information(nameof(MqttClient), "Start sending keep alive packets.");

            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    await Task.Delay(_options.KeepAlivePeriod, cancellationToken).ConfigureAwait(false);

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    await SendAndReceiveAsync <MqttPingRespPacket>(new MqttPingReqPacket()).ConfigureAwait(false);
                }
            }
            catch (TaskCanceledException)
            {
            }
            catch (MqttCommunicationException exception)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                MqttTrace.Warning(nameof(MqttClient), exception, "MQTT communication exception while sending/receiving keep alive packets.");
                await DisconnectInternalAsync().ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                MqttTrace.Warning(nameof(MqttClient), exception, "Unhandled exception while sending/receiving keep alive packets.");
                await DisconnectInternalAsync().ConfigureAwait(false);
            }
            finally
            {
                MqttTrace.Information(nameof(MqttClient), "Stopped sending keep alive packets.");
            }
        }
예제 #10
0
        private async Task SendPendingPublishPacketsAsync(CancellationToken cancellationToken, IMqttCommunicationAdapter adapter)
        {
            var consumable = _pendingPublishPackets.GetConsumingEnumerable();

            while (!cancellationToken.IsCancellationRequested)
            {
                if (_pendingPublishPackets.Count == 0)
                {
                    await Task.Delay(TimeSpan.FromMilliseconds(5), cancellationToken).ConfigureAwait(false);

                    continue;
                }

                var packets = consumable.Take(_pendingPublishPackets.Count).ToList();
                try
                {
                    await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, packets).ConfigureAwait(false);
                }
                catch (MqttCommunicationException exception)
                {
                    MqttTrace.Warning(nameof(MqttClientMessageQueue), exception, "Sending publish packet failed.");
                    foreach (var publishPacket in packets)
                    {
                        publishPacket.Dup = true;
                        _pendingPublishPackets.Add(publishPacket, cancellationToken);
                    }
                }
                catch (Exception exception)
                {
                    MqttTrace.Error(nameof(MqttClientMessageQueue), exception, "Sending publish packet failed.");
                    foreach (var publishPacket in packets)
                    {
                        publishPacket.Dup = true;
                        _pendingPublishPackets.Add(publishPacket, cancellationToken);
                    }
                }
            }
        }
예제 #11
0
        public async Task <MqttBasePacket> WaitForPacketAsync(Func <MqttBasePacket, bool> selector, TimeSpan timeout)
        {
            if (selector == null)
            {
                throw new ArgumentNullException(nameof(selector));
            }

            var packetAwaiter = AddPacketAwaiter(selector);

            DispatchPendingPackets();

            var hasTimeout = await Task.WhenAny(Task.Delay(timeout), packetAwaiter.Task) != packetAwaiter.Task;

            RemovePacketAwaiter(packetAwaiter);

            if (hasTimeout)
            {
                MqttTrace.Warning(nameof(MqttPacketDispatcher), "Timeout while waiting for packet.");
                throw new MqttCommunicationTimedOutException();
            }

            return(packetAwaiter.Task.Result);
        }
예제 #12
0
        public async Task <MqttBasePacket> WaitForPacketAsync(MqttBasePacket request, Type responseType, TimeSpan timeout)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var packetAwaiter = AddPacketAwaiter(request, responseType);

            try
            {
                return(await packetAwaiter.Task.TimeoutAfter(timeout));
            }
            catch (MqttCommunicationTimedOutException)
            {
                MqttTrace.Warning(nameof(MqttPacketDispatcher), "Timeout while waiting for packet of type '{0}'.", responseType.Name);
                throw;
            }
            finally
            {
                RemovePacketAwaiter(request, responseType);
            }
        }