async Task HandleConnectionExceptionAsync(Exception exception)
        {
            if (exception is TimeoutException)
            {
                await NotifyErrorAsync(ServerProperties.Resources.ServerPacketListener_NoConnectReceived, exception)
                .ConfigureAwait(continueOnCapturedContext: false);
            }
            else if (exception is MqttConnectionException)
            {
                tracer.Error(exception, ServerProperties.Resources.ServerPacketListener_ConnectionError, clientId ?? "N/A");

                var connectEx = exception as MqttConnectionException;
                var errorAck  = new ConnectAck(connectEx.ReturnCode, existingSession: false);

                try {
                    await channel.SendAsync(errorAck)
                    .ConfigureAwait(continueOnCapturedContext: false);
                } catch (Exception ex) {
                    await NotifyErrorAsync(ex).ConfigureAwait(continueOnCapturedContext: false);
                }
            }
            else
            {
                await NotifyErrorAsync(exception).ConfigureAwait(continueOnCapturedContext: false);
            }
        }
Example #2
0
        public async Task ExecuteAsync(string clientId, IPacket input, IMqttChannel <IPacket> channel)
        {
            if (input.Type != MqttPacketType.Unsubscribe)
            {
                return;
            }

            var unsubscribe = input as Unsubscribe;
            var session     = sessionRepository.Read(clientId);

            if (session == null)
            {
                throw new MqttException(string.Format(Properties.Resources.SessionRepository_ClientSessionNotFound, clientId));
            }

            foreach (var topic in unsubscribe.Topics)
            {
                var subscription = session.GetSubscriptions().FirstOrDefault(s => s.TopicFilter == topic);

                if (subscription != null)
                {
                    session.RemoveSubscription(subscription);
                }
            }

            sessionRepository.Update(session);

            await channel.SendAsync(new UnsubscribeAck (unsubscribe.PacketId))
            .ConfigureAwait(continueOnCapturedContext: false);
        }
Example #3
0
        protected async Task MonitorAckAsync <T> (Publish sentMessage, string clientId, IMqttChannel <IPacket> channel)
            where T : IFlowPacket
        {
            var intervalSubscription = Observable
                                       .Interval(TimeSpan.FromSeconds(configuration.WaitTimeoutSecs), NewThreadScheduler.Default)
                                       .Subscribe(async _ => {
                if (channel.IsConnected)
                {
                    tracer.Warn(Properties.Resources.PublishFlow_RetryingQoSFlow, sentMessage.Type, clientId);

                    var duplicated = new Publish(sentMessage.Topic, sentMessage.QualityOfService,
                                                 sentMessage.Retain, duplicated: true, packetId: sentMessage.PacketId)
                    {
                        Payload = sentMessage.Payload
                    };

                    await channel.SendAsync(duplicated);
                }
            });

            await channel
            .ReceiverStream
            .ObserveOn(NewThreadScheduler.Default)
            .OfType <T> ()
            .FirstOrDefaultAsync(x => x.PacketId == sentMessage.PacketId.Value);

            intervalSubscription.Dispose();
        }
Example #4
0
        void StartKeepAliveMonitor()
        {
            var interval = configuration.KeepAliveSecs * 1000;

            keepAliveTimer = new Timer();

            keepAliveTimer.AutoReset         = true;
            keepAliveTimer.IntervalMillisecs = interval;
            keepAliveTimer.Elapsed          += async(sender, e) => {
                try {
                    tracer.Warn(Properties.Resources.ClientPacketListener_SendingKeepAlive, clientId, configuration.KeepAliveSecs);

                    var ping = new PingRequest();

                    await channel.SendAsync(ping)
                    .ConfigureAwait(continueOnCapturedContext: false);
                } catch (Exception ex) {
                    NotifyError(ex);
                }
            };
            keepAliveTimer.Start();

            channel.SenderStream.Subscribe(p => {
                keepAliveTimer.IntervalMillisecs = interval;
            });
        }
        void StartKeepAliveMonitor()
        {
            int interval = _configuration.KeepAliveSecs * 1000;

            _keepAliveTimer = new Timer
            {
                AutoReset         = true,
                IntervalMillisecs = interval
            };
            _keepAliveTimer.Elapsed += async(sender, e) =>
            {
                try
                {
                    _tracer.Warn(ClientProperties.ClientPacketListener_SendingKeepAlive(_clientId, _configuration.KeepAliveSecs));

                    PingRequest ping = new PingRequest();

                    await _channel.SendAsync(ping);
                }
                catch (Exception ex)
                {
                    NotifyError(ex);
                }
            };
            _keepAliveTimer.Start();

            _channel.SenderStream.Subscribe(p =>
            {
                _keepAliveTimer.IntervalMillisecs = interval;
            });
        }
Example #6
0
        public async Task SendPublishAsync(string clientId, Publish message, IMqttChannel <IPacket> channel, PendingMessageStatus status = PendingMessageStatus.PendingToSend)
        {
            if (channel == null || !channel.IsConnected)
            {
                SaveMessage(message, clientId, PendingMessageStatus.PendingToSend);
                return;
            }

            var qos = configuration.GetSupportedQos(message.QualityOfService);

            if (qos != MqttQualityOfService.AtMostOnce && status == PendingMessageStatus.PendingToSend)
            {
                SaveMessage(message, clientId, PendingMessageStatus.PendingToAcknowledge);
            }

            await channel.SendAsync(message)
            .ConfigureAwait(continueOnCapturedContext: false);

            if (qos == MqttQualityOfService.AtLeastOnce)
            {
                await MonitorAckAsync <PublishAck> (message, clientId, channel)
                .ConfigureAwait(continueOnCapturedContext: false);
            }
            else if (qos == MqttQualityOfService.ExactlyOnce)
            {
                await MonitorAckAsync <PublishReceived> (message, clientId, channel).ConfigureAwait(continueOnCapturedContext: false);

                await channel
                .ReceiverStream
                .ObserveOn(NewThreadScheduler.Default)
                .OfType <PublishComplete> ()
                .FirstOrDefaultAsync(x => x.PacketId == message.PacketId.Value);
            }
        }
Example #7
0
        async Task HandleConnectionExceptionAsync(Exception exception)
        {
            if (exception is TimeoutException)
            {
                await NotifyErrorAsync(ServerProperties.ServerPacketListener_NoConnectReceived, exception);
            }
            else if (exception is MqttConnectionException)
            {
                _tracer.Error(exception, ServerProperties.ServerPacketListener_ConnectionError(_clientId ?? "N/A"));

                MqttConnectionException connectEx = exception as MqttConnectionException;
                ConnectAck errorAck = new ConnectAck(connectEx.ReturnCode, existingSession: false);

                try
                {
                    await _channel.SendAsync(errorAck);
                }
                catch (Exception ex)
                {
                    await NotifyErrorAsync(ex);
                }
            }
            else
            {
                await NotifyErrorAsync(exception);
            }
        }
Example #8
0
        public async Task ExecuteAsync(string clientId, IPacket input, IMqttChannel <IPacket> channel)
        {
            if (input.Type != MqttPacketType.Unsubscribe)
            {
                return;
            }

            Unsubscribe   unsubscribe = input as Unsubscribe;
            ClientSession session     = _sessionRepository.Read(clientId);

            if (session == null)
            {
                throw new MqttException(ServerProperties.SessionRepository_ClientSessionNotFound(clientId));
            }

            foreach (string topic in unsubscribe.Topics)
            {
                ClientSubscription subscription = session.GetSubscriptions().FirstOrDefault(s => s.TopicFilter == topic);

                if (subscription != null)
                {
                    session.RemoveSubscription(subscription);
                }
            }

            _sessionRepository.Update(session);

            await channel.SendAsync(new UnsubscribeAck( unsubscribe.PacketId ));
        }
Example #9
0
        async Task SendPacketAsync(IPacket packet)
        {
            sender.OnNext(packet);

            await clientSender.Run(async() => await packetChannel.SendAsync (packet).ConfigureAwait(continueOnCapturedContext: false))
            .ConfigureAwait(continueOnCapturedContext: false);
        }
Example #10
0
        public async Task SendAckAsync(string clientId, IFlowPacket ack, IMqttChannel <IPacket> channel, PendingMessageStatus status = PendingMessageStatus.PendingToSend)
        {
            if ((ack.Type == MqttPacketType.PublishReceived || ack.Type == MqttPacketType.PublishRelease) &&
                status == PendingMessageStatus.PendingToSend)
            {
                SavePendingAcknowledgement(ack, clientId);
            }

            if (!channel.IsConnected)
            {
                return;
            }

            await channel.SendAsync(ack)
            .ConfigureAwait(continueOnCapturedContext: false);

            if (ack.Type == MqttPacketType.PublishReceived)
            {
                await MonitorAckAsync <PublishRelease> (ack, clientId, channel)
                .ConfigureAwait(continueOnCapturedContext: false);
            }
            else if (ack.Type == MqttPacketType.PublishRelease)
            {
                await MonitorAckAsync <PublishComplete> (ack, clientId, channel)
                .ConfigureAwait(continueOnCapturedContext: false);
            }
        }
Example #11
0
        public async Task ExecuteAsync(string clientId, IPacket input, IMqttChannel <IPacket> channel)
        {
            if (input.Type != MqttPacketType.Connect)
            {
                return;
            }

            var connect = input as Connect;

            if (!authenticationProvider.Authenticate(clientId, connect.UserName, connect.Password))
            {
                throw new MqttConnectionException(MqttConnectionStatus.BadUserNameOrPassword);
            }

            var session        = sessionRepository.Read(clientId);
            var sessionPresent = connect.CleanSession ? false : session != null;

            if (connect.CleanSession && session != null)
            {
                sessionRepository.Delete(session.Id);
                session = null;

                tracer.Info(Server.Properties.Resources.Server_CleanedOldSession, clientId);
            }

            var sendPendingMessages = false;

            if (session == null)
            {
                session = new ClientSession(clientId, connect.CleanSession);

                sessionRepository.Create(session);

                tracer.Info(Server.Properties.Resources.Server_CreatedSession, clientId);
            }
            else
            {
                sendPendingMessages = true;
            }

            if (connect.Will != null)
            {
                var connectionWill = new ConnectionWill(clientId, connect.Will);

                willRepository.Create(connectionWill);
            }

            await channel.SendAsync(new ConnectAck (MqttConnectionStatus.Accepted, sessionPresent))
            .ConfigureAwait(continueOnCapturedContext: false);

            if (sendPendingMessages)
            {
                await SendPendingMessagesAsync(session, channel)
                .ConfigureAwait(continueOnCapturedContext: false);
                await SendPendingAcknowledgementsAsync(session, channel)
                .ConfigureAwait(continueOnCapturedContext: false);
            }
        }
        public async Task ExecuteAsync(string clientId, IPacket input, IMqttChannel <IPacket> channel)
        {
            if (input.Type != MqttPacketType.PingRequest)
            {
                return;
            }

            await channel.SendAsync(new PingResponse());
        }
        public async Task ExecuteAsync(string clientId, IPacket input, IMqttChannel <IPacket> channel)
        {
            if (input.Type != MqttPacketType.Connect)
            {
                return;
            }

            Connect connect = input as Connect;

            if (!_authenticationProvider.Authenticate(clientId, connect.UserName, connect.Password))
            {
                throw new MqttConnectionException(MqttConnectionStatus.BadUserNameOrPassword);
            }

            ClientSession session        = _sessionRepository.Read(clientId);
            bool          sessionPresent = connect.CleanSession ? false : session != null;

            _tracer.Info($"Client connecting with protocol level {connect.ProtocolLelvel}.");

            if (connect.CleanSession && session != null)
            {
                _sessionRepository.Delete(session.Id);
                session = null;

                _tracer.Info(ServerProperties.Server_CleanedOldSession(clientId));
            }

            bool sendPendingMessages = false;

            if (session == null)
            {
                session = new ClientSession(clientId, connect.CleanSession);

                _sessionRepository.Create(session);

                _tracer.Info(ServerProperties.Server_CreatedSession(clientId));
            }
            else
            {
                sendPendingMessages = true;
            }

            if (connect.Will != null)
            {
                ConnectionWill connectionWill = new ConnectionWill(clientId, connect.Will);

                _willRepository.Create(connectionWill);
            }

            await channel.SendAsync(new ConnectAck( MqttConnectionStatus.Accepted, sessionPresent ));

            if (sendPendingMessages)
            {
                await SendPendingMessagesAsync(session, channel);
                await SendPendingAcknowledgementsAsync(session, channel);
            }
        }
Example #14
0
        public async Task ExecuteAsync(string clientId, IPacket input, IMqttChannel <IPacket> channel)
        {
            if (input.Type != MqttPacketType.PingRequest)
            {
                return;
            }

            await channel.SendAsync(new PingResponse())
            .ConfigureAwait(continueOnCapturedContext: false);
        }
Example #15
0
        public async Task SendAsync(IPacket packet)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }

            byte[] bytes = await _manager.GetBytesAsync(packet);

            _sender.OnNext(packet);

            await _innerChannel.SendAsync(bytes);
        }
        public async Task SendAsync(IPacket packet)
        {
            if (disposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }

            var bytes = await manager.GetBytesAsync(packet)
                        .ConfigureAwait(continueOnCapturedContext: false);

            sender.OnNext(packet);

            await innerChannel.SendAsync(bytes)
            .ConfigureAwait(continueOnCapturedContext: false);
        }
        protected async Task MonitorAckAsync <T>(IFlowPacket sentMessage, string clientId, IMqttChannel <IPacket> channel)
            where T : IFlowPacket
        {
            using (IDisposable intervalSubscription = Observable
                                                      .Interval(TimeSpan.FromSeconds(configuration.WaitTimeoutSecs), NewThreadScheduler.Default)
                                                      .Subscribe(async _ =>
            {
                if (channel.IsConnected)
                {
                    _tracer.Warn(ClientProperties.PublishFlow_RetryingQoSFlow(sentMessage.Type, clientId));

                    await channel.SendAsync(sentMessage);
                }
            }))
            {
                await channel
                .ReceiverStream
                .ObserveOn(NewThreadScheduler.Default)
                .OfType <T>()
                .FirstOrDefaultAsync(x => x.PacketId == sentMessage.PacketId);
            }
        }
Example #18
0
        public async Task ExecuteAsync(string clientId, IPacket input, IMqttChannel <IPacket> channel)
        {
            if (input.Type != MqttPacketType.Subscribe)
            {
                return;
            }

            var subscribe = input as Subscribe;
            var session   = sessionRepository.Read(clientId);

            if (session == null)
            {
                throw new MqttException(string.Format(Properties.Resources.SessionRepository_ClientSessionNotFound, clientId));
            }

            var returnCodes = new List <SubscribeReturnCode> ();

            foreach (var subscription in subscribe.Subscriptions)
            {
                try {
                    if (!topicEvaluator.IsValidTopicFilter(subscription.TopicFilter))
                    {
                        tracer.Error(Server.Properties.Resources.ServerSubscribeFlow_InvalidTopicSubscription, subscription.TopicFilter, clientId);

                        returnCodes.Add(SubscribeReturnCode.Failure);
                        continue;
                    }

                    var clientSubscription = session
                                             .GetSubscriptions()
                                             .FirstOrDefault(s => s.TopicFilter == subscription.TopicFilter);

                    if (clientSubscription != null)
                    {
                        clientSubscription.MaximumQualityOfService = subscription.MaximumQualityOfService;
                    }
                    else
                    {
                        Console.WriteLine("Client just connected: " + clientId + " " + subscription.TopicFilter);
                        clientSubscription = new ClientSubscription {
                            ClientId                = clientId,
                            TopicFilter             = subscription.TopicFilter,
                            MaximumQualityOfService = subscription.MaximumQualityOfService
                        };

                        session.AddSubscription(clientSubscription);
                    }

                    await SendRetainedMessagesAsync(clientSubscription, channel)
                    .ConfigureAwait(continueOnCapturedContext: false);

                    var supportedQos = configuration.GetSupportedQos(subscription.MaximumQualityOfService);
                    var returnCode   = supportedQos.ToReturnCode();

                    returnCodes.Add(returnCode);
                } catch (RepositoryException repoEx) {
                    tracer.Error(repoEx, Server.Properties.Resources.ServerSubscribeFlow_ErrorOnSubscription, clientId, subscription.TopicFilter);

                    returnCodes.Add(SubscribeReturnCode.Failure);
                }
            }

            sessionRepository.Update(session);

            await channel.SendAsync(new SubscribeAck (subscribe.PacketId, returnCodes.ToArray()))
            .ConfigureAwait(continueOnCapturedContext: false);
        }
Example #19
0
        public async Task ExecuteAsync(string clientId, IPacket input, IMqttChannel <IPacket> channel)
        {
            if (input.Type != MqttPacketType.Subscribe)
            {
                return;
            }

            Subscribe     subscribe = input as Subscribe;
            ClientSession session   = _sessionRepository.Read(clientId);

            if (session == null)
            {
                throw new MqttException(ServerProperties.SessionRepository_ClientSessionNotFound(clientId));
            }

            List <SubscribeReturnCode> returnCodes = new List <SubscribeReturnCode>();

            foreach (Subscription subscription in subscribe.Subscriptions)
            {
                try
                {
                    if (!_topicEvaluator.IsValidTopicFilter(subscription.TopicFilter))
                    {
                        _tracer.Error(ServerProperties.ServerSubscribeFlow_InvalidTopicSubscription(subscription.TopicFilter, clientId));

                        returnCodes.Add(SubscribeReturnCode.Failure);
                        continue;
                    }

                    ClientSubscription clientSubscription = session
                                                            .GetSubscriptions()
                                                            .FirstOrDefault(s => s.TopicFilter == subscription.TopicFilter);

                    if (clientSubscription != null)
                    {
                        clientSubscription.MaximumQualityOfService = subscription.MaximumQualityOfService;
                    }
                    else
                    {
                        clientSubscription = new ClientSubscription
                        {
                            ClientId                = clientId,
                            TopicFilter             = subscription.TopicFilter,
                            MaximumQualityOfService = subscription.MaximumQualityOfService
                        };

                        session.AddSubscription(clientSubscription);
                    }

                    await SendRetainedMessagesAsync(clientSubscription, channel);

                    MqttQualityOfService supportedQos = _configuration.GetSupportedQos(subscription.MaximumQualityOfService);
                    SubscribeReturnCode  returnCode   = supportedQos.ToReturnCode();

                    returnCodes.Add(returnCode);
                }
                catch (RepositoryException repoEx)
                {
                    _tracer.Error(repoEx, ServerProperties.ServerSubscribeFlow_ErrorOnSubscription(clientId, subscription.TopicFilter));

                    returnCodes.Add(SubscribeReturnCode.Failure);
                }
            }

            _sessionRepository.Update(session);

            await channel.SendAsync(new SubscribeAck( subscribe.PacketId, returnCodes.ToArray()));
        }