Exemplo n.º 1
0
        public async Task <SessionState> ConnectAsync(MqttClientCredentials credentials, MqttLastWill will = null, bool cleanSession = false)
        {
            if (disposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }

            try {
                if (IsConnected)
                {
                    throw new MqttClientException(string.Format(Properties.Resources.Client_AlreadyConnected, Id));
                }

                if (string.IsNullOrEmpty(credentials.ClientId) && !cleanSession)
                {
                    throw new MqttClientException(Properties.Resources.Client_AnonymousClientWithoutCleanSession);
                }

                Id = string.IsNullOrEmpty(credentials.ClientId) ?
                     MqttClient.GetAnonymousClientId() :
                     credentials.ClientId;

                OpenClientSession(cleanSession);

                await InitializeChannelAsync().ConfigureAwait(continueOnCapturedContext: false);

                var connect = new Connect(Id, cleanSession)
                {
                    UserName  = credentials.UserName,
                    Password  = credentials.Password,
                    Will      = will,
                    KeepAlive = configuration.KeepAliveSecs
                };

                await SendPacketAsync(connect)
                .ConfigureAwait(continueOnCapturedContext: false);

                var connectTimeout = TimeSpan.FromSeconds(configuration.WaitTimeoutSecs);
                var ack            = await packetListener
                                     .PacketStream
                                     .ObserveOn(NewThreadScheduler.Default)
                                     .OfType <ConnectAck> ()
                                     .FirstOrDefaultAsync()
                                     .Timeout(connectTimeout);

                if (ack == null)
                {
                    var message = string.Format(Properties.Resources.Client_ConnectionDisconnected, Id);

                    throw new MqttClientException(message);
                }

                if (ack.Status != MqttConnectionStatus.Accepted)
                {
                    throw new MqttConnectionException(ack.Status);
                }

                IsConnected = true;

                return(ack.SessionPresent ? SessionState.SessionPresent : SessionState.CleanSession);
            } catch (TimeoutException timeEx) {
                Close(timeEx);
                throw new MqttClientException(string.Format(Properties.Resources.Client_ConnectionTimeout, Id), timeEx);
            } catch (MqttConnectionException connectionEx) {
                Close(connectionEx);

                var message = string.Format(Properties.Resources.Client_ConnectNotAccepted, Id, connectionEx.ReturnCode);

                throw new MqttClientException(message, connectionEx);
            } catch (MqttClientException clientEx) {
                Close(clientEx);
                throw;
            } catch (Exception ex) {
                Close(ex);
                throw new MqttClientException(string.Format(Properties.Resources.Client_ConnectionError, Id), ex);
            }
        }
        protected override Connect Read(byte[] bytes)
        {
            ValidateHeaderFlag(bytes, t => t == MqttPacketType.Connect, 0x00);

            var remainingLengthBytesLength = 0;

            MqttProtocol.Encoding.DecodeRemainingLength(bytes, out remainingLengthBytesLength);

            var protocolName = bytes.GetString(MqttProtocol.PacketTypeLength + remainingLengthBytesLength);

            if (protocolName != MqttProtocol.Name)
            {
                var error = string.Format(Properties.Resources.ConnectFormatter_InvalidProtocolName, protocolName);

                throw new MqttException(error);
            }

            var protocolLevelIndex = MqttProtocol.PacketTypeLength + remainingLengthBytesLength + MqttProtocol.NameLength;
            var protocolLevel      = bytes.Byte(protocolLevelIndex);

            if (protocolLevel < MqttProtocol.SupportedLevel)
            {
                var error = string.Format(Properties.Resources.ConnectFormatter_UnsupportedLevel, protocolLevel);

                throw new MqttConnectionException(MqttConnectionStatus.UnacceptableProtocolVersion, error);
            }

            var protocolLevelLength = 1;
            var connectFlagsIndex   = protocolLevelIndex + protocolLevelLength;
            var connectFlags        = bytes.Byte(connectFlagsIndex);

            if (connectFlags.IsSet(0))
            {
                throw new MqttException(Properties.Resources.ConnectFormatter_InvalidReservedFlag);
            }

            if (connectFlags.Bits(4, 2) == 0x03)
            {
                throw new MqttException(Properties.Resources.Formatter_InvalidQualityOfService);
            }

            var willFlag   = connectFlags.IsSet(2);
            var willRetain = connectFlags.IsSet(5);

            if (!willFlag && willRetain)
            {
                throw new MqttException(Properties.Resources.ConnectFormatter_InvalidWillRetainFlag);
            }

            var userNameFlag = connectFlags.IsSet(7);
            var passwordFlag = connectFlags.IsSet(6);

            if (!userNameFlag && passwordFlag)
            {
                throw new MqttException(Properties.Resources.ConnectFormatter_InvalidPasswordFlag);
            }

            var willQos      = (MqttQualityOfService)connectFlags.Bits(4, 2);
            var cleanSession = connectFlags.IsSet(1);

            var keepAliveLength = 2;
            var keepAliveBytes  = bytes.Bytes(connectFlagsIndex + 1, keepAliveLength);
            var keepAlive       = keepAliveBytes.ToUInt16();

            var payloadStartIndex = connectFlagsIndex + keepAliveLength + 1;
            var nextIndex         = 0;
            var clientId          = bytes.GetString(payloadStartIndex, out nextIndex);

            if (clientId.Length > MqttProtocol.ClientIdMaxLength)
            {
                throw new MqttConnectionException(MqttConnectionStatus.IdentifierRejected, Properties.Resources.ConnectFormatter_ClientIdMaxLengthExceeded);
            }

            if (!IsValidClientId(clientId))
            {
                var error = string.Format(Properties.Resources.ConnectFormatter_InvalidClientIdFormat, clientId);

                throw new MqttConnectionException(MqttConnectionStatus.IdentifierRejected, error);
            }

            if (string.IsNullOrEmpty(clientId) && !cleanSession)
            {
                throw new MqttConnectionException(MqttConnectionStatus.IdentifierRejected, Properties.Resources.ConnectFormatter_ClientIdEmptyRequiresCleanSession);
            }

            if (string.IsNullOrEmpty(clientId))
            {
                clientId = MqttClient.GetAnonymousClientId();
            }

            var connect = new Connect(clientId, cleanSession);

            connect.KeepAlive = keepAlive;

            if (willFlag)
            {
                var willTopic = bytes.GetString(nextIndex, out int willMessageIndex);
                var willMessageLengthBytes = bytes.Bytes(willMessageIndex, count: 2);
                var willMessageLenght      = willMessageLengthBytes.ToUInt16();

                var willMessage = bytes.Bytes(willMessageIndex + 2, willMessageLenght);

                connect.Will = new MqttLastWill(willTopic, willQos, willRetain, willMessage);
                nextIndex    = willMessageIndex + 2 + willMessageLenght;
            }

            if (userNameFlag)
            {
                var userName = bytes.GetString(nextIndex, out nextIndex);

                connect.UserName = userName;
            }

            if (passwordFlag)
            {
                var password = bytes.GetString(nextIndex);

                connect.Password = password;
            }

            return(connect);
        }