private async Task ProcessConnAckAsync(IChannelHandlerContext context, ConnAckPacket packet)
        {
            if (packet.SessionPresent)
            {
                await FailWithExceptionAsync(
                    context,
                    new ProvisioningTransportException(
                        $"{ExceptionPrefix} Unexpected CONNACK with SessionPresent.")).ConfigureAwait(false);
            }

            switch (packet.ReturnCode)
            {
            case ConnectReturnCode.Accepted:
                try
                {
                    await SubscribeAsync(context).ConfigureAwait(false);

                    ChangeState(State.WaitForConnack, State.WaitForSuback);
                }
                catch (Exception ex)
                {
                    await FailWithExceptionAsync(context, ex).ConfigureAwait(false);
                }

                break;

            case ConnectReturnCode.RefusedUnacceptableProtocolVersion:
            case ConnectReturnCode.RefusedIdentifierRejected:
            case ConnectReturnCode.RefusedBadUsernameOrPassword:
            case ConnectReturnCode.RefusedNotAuthorized:
                await FailWithExceptionAsync(
                    context,
                    new ProvisioningTransportException(
                        $"{ExceptionPrefix} CONNACK failed with {packet.ReturnCode}")).ConfigureAwait(false);

                break;

            case ConnectReturnCode.RefusedServerUnavailable:
                await FailWithExceptionAsync(
                    context,
                    new ProvisioningTransportException(
                        $"{ExceptionPrefix} CONNACK failed with {packet.ReturnCode}. Try again later.",
                        null,
                        true)).ConfigureAwait(false);

                break;

            default:
                await FailWithExceptionAsync(
                    context,
                    new ProvisioningTransportException(
                        $"{ExceptionPrefix} CONNACK failed unknown return code: {packet.ReturnCode}")).ConfigureAwait(false);

                break;
            }
        }
示例#2
0
        public void TestConnAckMessage(bool sessionPresent, ConnectReturnCode returnCode)
        {
            var packet = new ConnAckPacket();

            packet.SessionPresent = sessionPresent;
            packet.ReturnCode     = returnCode;

            ConnAckPacket recoded = this.RecodePacket(packet, false, true);

            this.contextMock.Verify(x => x.FireChannelRead(It.IsAny <ConnAckPacket>()), Times.Once);
            Assert.Equal(packet.SessionPresent, recoded.SessionPresent);
            Assert.Equal(packet.ReturnCode, recoded.ReturnCode);
        }
示例#3
0
        public void ConnAckMessageTest(bool sessionPresent, ConnectReturnCode returnCode)
        {
            var packet = new ConnAckPacket();

            packet.VariableHeader.SessionPresent    = sessionPresent;
            packet.VariableHeader.ConnectReturnCode = returnCode;

            var recoded = RecodePacket(packet, false, false);

            contextMock.Verify(x => x.FireChannelRead(It.IsAny <ConnAckPacket>()), Times.Once);
            Assert.Equal(packet.VariableHeader.SessionPresent, recoded.VariableHeader.SessionPresent);
            Assert.Equal(packet.VariableHeader.ConnectReturnCode, recoded.VariableHeader.ConnectReturnCode);
        }
示例#4
0
        protected override async Task <MqttMessage> ProcessAsync(MqttClientSession clientSession, ConnectPacket packet)
        {
            var ack       = new ConnAckPacket();
            var resultMsg = new MqttMessage {
                Packet = ack
            };

            _logger.LogInformation("receive connect packet ,clientId={0}", packet.ClientId);
            IMqttResult validResult = await _mqttAuthorize.Validate(packet);

            ack.ReturnCode = validResult.Code == 0 ? ConnectReturnCode.Accepted : ConnectReturnCode.RefusedNotAuthorized;

            return(resultMsg);
        }
 static void EncodeConnAckMessage(DataWriter writer, ConnAckPacket message)
 {
     writer.WriteByte(CalculateFirstByteOfFixedHeader(message));
     writer.WriteByte(2); // remaining length
     if (message.SessionPresent)
     {
         writer.WriteByte(1); // 7 reserved 0-bits and SP = 1
     }
     else
     {
         writer.WriteByte(0); // 7 reserved 0-bits and SP = 0
     }
     writer.WriteByte((byte)message.ReturnCode);
 }
示例#6
0
        public void OnConnAck(IChannelHandlerContext context, ConnAckPacket packet)
        {
            switch (packet.ReturnCode)
            {
            case ConnectReturnCode.Accepted:
                connectFuture.SetResult(new ConnectResult(true, ConnectReturnCode.Accepted, context.Channel.CloseCompletion));
                foreach (var value in pendingSubscribes.Values)
                {
                    if (!value.Sent)
                    {
                        context.WriteAsync(value.Packet).Wait();
                        value.Sent = true;
                    }
                }
                foreach (var value in pendingPublishes.Values)
                {
                    if (value.Sent)
                    {
                        continue;
                    }

                    context.WriteAsync(value.Packet).Wait();
                    value.Sent = true;
                    if (value.Packet.QualityOfService == QualityOfService.AtMostOnce)
                    {
                        value.Promise.SetResult(null);    //We don't get an ACK for QOS 0
                        pendingPublishes.TryRemove(value.Packet.PacketId, out _);
                    }
                }
                context.Flush();
                if (reconnecting)
                {
                    if (OnConnectionChange != null)
                    {
                        OnConnectionChange.OnReconnect();
                    }
                }
                break;

            default:
                connectFuture.SetResult(new ConnectResult(false, packet.ReturnCode, context.Channel.CloseCompletion));
                context.CloseAsync();
                break;
            }
        }
示例#7
0
        static void EncodeConnAckMessage(IByteBufferAllocator bufferAllocator, ConnAckPacket message, List <object> output)
        {
            IByteBuffer buffer = bufferAllocator.Buffer(4);

            buffer.WriteByte(CalculateFirstByteOfFixedHeader(message));
            buffer.WriteByte(2); // remaining length
            if (message.SessionPresent)
            {
                buffer.WriteByte(1); // 7 reserved 0-bits and SP = 1
            }
            else
            {
                buffer.WriteByte(0); // 7 reserved 0-bits and SP = 0
            }
            buffer.WriteByte((byte)message.ReturnCode);

            output.Add(buffer);
        }
示例#8
0
        Packet DecodePacketInternal(IByteBuffer buffer, byte packetSignature, ref int remainingLength)
        {
            Packet packet;
            var    fixedHeader = new FixedHeader(packetSignature, remainingLength);

            switch (fixedHeader.PacketType)
            {
            case PacketType.CONNECT: packet = new ConnectPacket(); break;

            case PacketType.CONNACK: packet = new ConnAckPacket(); break;

            case PacketType.DISCONNECT: packet = new DisconnectPacket(); break;

            case PacketType.PINGREQ: packet = new PingReqPacket(); break;

            case PacketType.PINGRESP: packet = new PingRespPacket(); break;

            case PacketType.PUBACK: packet = new PubAckPacket(); break;

            case PacketType.PUBCOMP: packet = new PubCompPacket(); break;

            case PacketType.PUBLISH: packet = new PublishPacket(); break;

            case PacketType.PUBREC: packet = new PubRecPacket(); break;

            case PacketType.PUBREL: packet = new PubRelPacket(); break;

            case PacketType.SUBSCRIBE: packet = new SubscribePacket(); break;

            case PacketType.SUBACK: packet = new SubAckPacket(); break;

            case PacketType.UNSUBSCRIBE: packet = new UnsubscribePacket(); break;

            case PacketType.UNSUBACK: packet = new UnsubscribePacket(); break;

            default:
                throw new DecoderException("Unsupported Message Type");
            }
            packet.FixedHeader = fixedHeader;
            packet.Decode(buffer);
            remainingLength = packet.RemaingLength;
            return(packet);
        }
示例#9
0
        public async Task <MqttMessage> ProcessAsync(MqttClientSession clientSession, Packet packet)
        {
            var ack       = new ConnAckPacket();
            var resultMsg = new MqttMessage {
                Packet = ack
            };

            if (!(packet is ConnectPacket cntPacket))
            {
                this.logger.LogWarning("bad data format");
                ack.ReturnCode = ConnectReturnCode.RefusedNotAuthorized;
                return(resultMsg);
            }
            this.logger.LogWarning("receive connect packet ,clientId={0}", cntPacket.ClientId);
            IMqttResult validResult = await this.mqttAuthorize.Validate(cntPacket);

            ack.ReturnCode = validResult.Code == 0 ? ConnectReturnCode.Accepted : ConnectReturnCode.RefusedNotAuthorized;

            return(resultMsg);
        }
示例#10
0
        private void ProcessMessage(IChannel channel, ConnAckPacket message)
        {
            switch (message.VariableHeader.ConnectReturnCode)
            {
            case ConnectReturnCode.CONNECTION_ACCEPTED:
                connectFuture.TrySetResult(new MqttConnectResult(ConnectReturnCode.CONNECTION_ACCEPTED));

                if (client.ConnectedHandler != null)
                {
                    client.ConnectedHandler.OnConnected();
                }
                break;

            case ConnectReturnCode.CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD:
            case ConnectReturnCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED:
            case ConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE:
            case ConnectReturnCode.CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION:
                connectFuture.TrySetResult(new MqttConnectResult(message.VariableHeader.ConnectReturnCode));
                channel.CloseAsync();
                break;
            }
        }
示例#11
0
        async Task ProcessConnectAckAsync(IChannelHandlerContext context, ConnAckPacket packet)
        {
            if (Logging.IsEnabled)
            {
                Logging.Enter(this, context.Name, packet, nameof(ProcessConnectAckAsync));
            }

            if (packet.ReturnCode != ConnectReturnCode.Accepted)
            {
                string reason          = "CONNECT failed: " + packet.ReturnCode;
                var    iotHubException = new UnauthorizedException(reason);
                ShutdownOnError(context, iotHubException);
                return;
            }

            if (!this.IsInState(StateFlags.Connecting))
            {
                string reason          = "CONNECT has been received, however a session has already been established. Only one CONNECT/CONNACK pair is expected per session.";
                var    iotHubException = new IotHubException(reason);
                ShutdownOnError(context, iotHubException);
                return;
            }

            this.stateFlags = StateFlags.Connected;

            this.mqttIotHubEventHandler.OnConnected();

            this.ResumeReadingIfNecessary(context);

            if (packet.SessionPresent)
            {
                await this.SubscribeAsync(context, null).ConfigureAwait(true);
            }

            if (Logging.IsEnabled)
            {
                Logging.Exit(this, context.Name, packet, nameof(ProcessConnectAckAsync));
            }
        }
示例#12
0
        private void HandleConack(IChannel channel, ConnAckPacket message)
        {
            switch (message.ConnectReturnCode)
            {
            case ConnectReturnCode.ConnectionAccepted:
                connectFuture.TrySetResult(new MqttConnectResult(ConnectReturnCode.ConnectionAccepted));

                if (client.ConnectedHandler != null)
                {
                    client.ConnectedHandler.OnConnected();
                }
                break;

            case ConnectReturnCode.BadUsernameOrPassword:
            case ConnectReturnCode.IdentifierRejected:
            case ConnectReturnCode.RefusedNotAuthorized:
            case ConnectReturnCode.BrokerUnavailable:
            case ConnectReturnCode.UnacceptableProtocolVersion:
                connectFuture.TrySetResult(new MqttConnectResult(message.ConnectReturnCode));
                channel.CloseAsync();
                break;
            }
        }
示例#13
0
        void ProcessConnectAck(IChannelHandlerContext context, ConnAckPacket packet)
        {
            if (packet.ReturnCode != ConnectReturnCode.Accepted)
            {
                string reason          = "CONNECT failed: " + packet.ReturnCode;
                var    iotHubException = new IotHubException(reason);
                ShutdownOnError(context, iotHubException);
                return;
            }

            if (!this.IsInState(StateFlags.Connecting))
            {
                string reason          = "CONNECT has been received, however a session has already been established. Only one CONNECT/CONNACK pair is expected per session.";
                var    iotHubException = new IotHubException(reason);
                ShutdownOnError(context, iotHubException);
                return;
            }

            this.stateFlags = StateFlags.Connected;

            this.ResumeReadingIfNecessary(context);

            this.onConnected();
        }
示例#14
0
 public async Task ConnAck(IChannelHandlerContext context, ConnAckPacket packet)
 {
     await context.WriteAndFlushAsync(packet);
 }
 public abstract void ConnAck(IChannelHandlerContext context, ConnAckPacket packet);
示例#16
0
        Packet DecodePacketInternal(IByteBuffer buffer, int packetSignature, ref int remainingLength, IChannelHandlerContext context)
        {
            if (Signatures.IsPublish(packetSignature))
            {
                var qualityOfService = (QualityOfService)((packetSignature >> 1) & 0x3); // take bits #1 and #2 ONLY and convert them into QoS value
                if (qualityOfService == QualityOfService.Reserved)
                {
                    ThrowHelper.ThrowDecoderException_UnexpectedQoSValueForPublish(qualityOfService);
                }

                bool duplicate = (packetSignature & 0x8) == 0x8; // test bit#3
                bool retain    = (packetSignature & 0x1) != 0;   // test bit#0
                var  packet    = new PublishPacket(qualityOfService, duplicate, retain);
                DecodePublishPacket(buffer, packet, ref remainingLength);
                return(packet);
            }

            switch (packetSignature) // strict match checks for valid message type + correct values in flags part
            {
            case Signatures.PubAck:
                var pubAckPacket = new PubAckPacket();
                DecodePacketIdVariableHeader(buffer, pubAckPacket, ref remainingLength);
                return(pubAckPacket);

            case Signatures.PubRec:
                var pubRecPacket = new PubRecPacket();
                DecodePacketIdVariableHeader(buffer, pubRecPacket, ref remainingLength);
                return(pubRecPacket);

            case Signatures.PubRel:
                var pubRelPacket = new PubRelPacket();
                DecodePacketIdVariableHeader(buffer, pubRelPacket, ref remainingLength);
                return(pubRelPacket);

            case Signatures.PubComp:
                var pubCompPacket = new PubCompPacket();
                DecodePacketIdVariableHeader(buffer, pubCompPacket, ref remainingLength);
                return(pubCompPacket);

            case Signatures.PingReq:
                if (!_isServer)
                {
                    ValidateServerPacketExpected(packetSignature);
                }
                return(PingReqPacket.Instance);

            case Signatures.Subscribe:
                if (!_isServer)
                {
                    ValidateServerPacketExpected(packetSignature);
                }
                var subscribePacket = new SubscribePacket();
                DecodePacketIdVariableHeader(buffer, subscribePacket, ref remainingLength);
                DecodeSubscribePayload(buffer, subscribePacket, ref remainingLength);
                return(subscribePacket);

            case Signatures.Unsubscribe:
                if (!_isServer)
                {
                    ValidateServerPacketExpected(packetSignature);
                }
                var unsubscribePacket = new UnsubscribePacket();
                DecodePacketIdVariableHeader(buffer, unsubscribePacket, ref remainingLength);
                DecodeUnsubscribePayload(buffer, unsubscribePacket, ref remainingLength);
                return(unsubscribePacket);

            case Signatures.Connect:
                if (!_isServer)
                {
                    ValidateServerPacketExpected(packetSignature);
                }
                var connectPacket = new ConnectPacket();
                DecodeConnectPacket(buffer, connectPacket, ref remainingLength, context);
                return(connectPacket);

            case Signatures.Disconnect:
                if (!_isServer)
                {
                    ValidateServerPacketExpected(packetSignature);
                }
                return(DisconnectPacket.Instance);

            case Signatures.ConnAck:
                if (_isServer)
                {
                    ValidateClientPacketExpected(packetSignature);
                }
                var connAckPacket = new ConnAckPacket();
                DecodeConnAckPacket(buffer, connAckPacket, ref remainingLength);
                return(connAckPacket);

            case Signatures.SubAck:
                if (_isServer)
                {
                    ValidateClientPacketExpected(packetSignature);
                }
                var subAckPacket = new SubAckPacket();
                DecodePacketIdVariableHeader(buffer, subAckPacket, ref remainingLength);
                DecodeSubAckPayload(buffer, subAckPacket, ref remainingLength);
                return(subAckPacket);

            case Signatures.UnsubAck:
                if (_isServer)
                {
                    ValidateClientPacketExpected(packetSignature);
                }
                var unsubAckPacket = new UnsubAckPacket();
                DecodePacketIdVariableHeader(buffer, unsubAckPacket, ref remainingLength);
                return(unsubAckPacket);

            case Signatures.PingResp:
                if (_isServer)
                {
                    ValidateClientPacketExpected(packetSignature);
                }
                return(PingRespPacket.Instance);

            default:
                return(ThrowHelper.FromDecoderException_FirstPacketByteValueIsInvalid(packetSignature));
            }
        }
示例#17
0
        Packet DecodePacketInternal(IByteBuffer buffer, int packetSignature, ref int remainingLength, IChannelHandlerContext context)
        {
            if (Signatures.IsPublish(packetSignature))
            {
                var qualityOfService = (QualityOfService)((packetSignature >> 1) & 0x3); // take bits #1 and #2 ONLY and convert them into QoS value
                if (qualityOfService == QualityOfService.Reserved)
                {
                    throw new DecoderException($"Unexpected QoS value of {(int)qualityOfService} for {PacketType.PUBLISH} packet.");
                }

                bool duplicate = (packetSignature & 0x8) == 0x8; // test bit#3
                bool retain    = (packetSignature & 0x1) != 0;   // test bit#0
                var  packet    = new PublishPacket(qualityOfService, duplicate, retain);
                DecodePublishPacket(buffer, packet, ref remainingLength);
                return(packet);
            }

            switch (packetSignature) // strict match checks for valid message type + correct values in flags part
            {
            case Signatures.PubAck:
                var pubAckPacket = new PubAckPacket();
                DecodePacketIdVariableHeader(buffer, pubAckPacket, ref remainingLength);
                return(pubAckPacket);

            case Signatures.PubRec:
                var pubRecPacket = new PubRecPacket();
                DecodePacketIdVariableHeader(buffer, pubRecPacket, ref remainingLength);
                return(pubRecPacket);

            case Signatures.PubRel:
                var pubRelPacket = new PubRelPacket();
                DecodePacketIdVariableHeader(buffer, pubRelPacket, ref remainingLength);
                return(pubRelPacket);

            case Signatures.PubComp:
                var pubCompPacket = new PubCompPacket();
                DecodePacketIdVariableHeader(buffer, pubCompPacket, ref remainingLength);
                return(pubCompPacket);

            case Signatures.PingReq:
                this.ValidateServerPacketExpected(packetSignature);
                return(PingReqPacket.Instance);

            case Signatures.Subscribe:
                this.ValidateServerPacketExpected(packetSignature);
                var subscribePacket = new SubscribePacket();
                DecodePacketIdVariableHeader(buffer, subscribePacket, ref remainingLength);
                DecodeSubscribePayload(buffer, subscribePacket, ref remainingLength);
                return(subscribePacket);

            case Signatures.Unsubscribe:
                this.ValidateServerPacketExpected(packetSignature);
                var unsubscribePacket = new UnsubscribePacket();
                DecodePacketIdVariableHeader(buffer, unsubscribePacket, ref remainingLength);
                DecodeUnsubscribePayload(buffer, unsubscribePacket, ref remainingLength);
                return(unsubscribePacket);

            case Signatures.Connect:
                this.ValidateServerPacketExpected(packetSignature);
                var connectPacket = new ConnectPacket();
                DecodeConnectPacket(buffer, connectPacket, ref remainingLength, context);
                return(connectPacket);

            case Signatures.Disconnect:
                this.ValidateServerPacketExpected(packetSignature);
                return(DisconnectPacket.Instance);

            case Signatures.ConnAck:
                this.ValidateClientPacketExpected(packetSignature);
                var connAckPacket = new ConnAckPacket();
                DecodeConnAckPacket(buffer, connAckPacket, ref remainingLength);
                return(connAckPacket);

            case Signatures.SubAck:
                this.ValidateClientPacketExpected(packetSignature);
                var subAckPacket = new SubAckPacket();
                DecodePacketIdVariableHeader(buffer, subAckPacket, ref remainingLength);
                DecodeSubAckPayload(buffer, subAckPacket, ref remainingLength);
                return(subAckPacket);

            case Signatures.UnsubAck:
                this.ValidateClientPacketExpected(packetSignature);
                var unsubAckPacket = new UnsubAckPacket();
                DecodePacketIdVariableHeader(buffer, unsubAckPacket, ref remainingLength);
                return(unsubAckPacket);

            case Signatures.PingResp:
                this.ValidateClientPacketExpected(packetSignature);
                return(PingRespPacket.Instance);

            default:
                throw new DecoderException($"First packet byte value of `{packetSignature}` is invalid.");
            }
        }
示例#18
0
        static void DecodeConnectPacket(IByteBuffer buffer, ConnectPacket packet, ref int remainingLength, IChannelHandlerContext context)
        {
            string protocolName = DecodeString(buffer, ref remainingLength);

            if (!Util.ProtocolName.Equals(protocolName, StringComparison.Ordinal))
            {
                throw new DecoderException($"Unexpected protocol name. Expected: {Util.ProtocolName}. Actual: {protocolName}");
            }
            packet.ProtocolName = Util.ProtocolName;

            DecreaseRemainingLength(ref remainingLength, 1);
            packet.ProtocolLevel = buffer.ReadByte();

            if (packet.ProtocolLevel != Util.ProtocolLevel)
            {
                var connAckPacket = new ConnAckPacket();
                connAckPacket.ReturnCode = ConnectReturnCode.RefusedUnacceptableProtocolVersion;
                context.WriteAndFlushAsync(connAckPacket);
                throw new DecoderException($"Unexpected protocol level. Expected: {Util.ProtocolLevel}. Actual: {packet.ProtocolLevel}");
            }

            DecreaseRemainingLength(ref remainingLength, 1);
            int connectFlags = buffer.ReadByte();

            packet.CleanSession = (connectFlags & 0x02) == 0x02;

            bool hasWill = (connectFlags & 0x04) == 0x04;

            if (hasWill)
            {
                packet.HasWill              = true;
                packet.WillRetain           = (connectFlags & 0x20) == 0x20;
                packet.WillQualityOfService = (QualityOfService)((connectFlags & 0x18) >> 3);
                if (packet.WillQualityOfService == QualityOfService.Reserved)
                {
                    throw new DecoderException($"[MQTT-3.1.2-14] Unexpected Will QoS value of {(int)packet.WillQualityOfService}.");
                }
                packet.WillTopicName = string.Empty;
            }
            else if ((connectFlags & 0x38) != 0) // bits 3,4,5 [MQTT-3.1.2-11]
            {
                throw new DecoderException("[MQTT-3.1.2-11]");
            }

            packet.HasUsername = (connectFlags & 0x80) == 0x80;
            packet.HasPassword = (connectFlags & 0x40) == 0x40;
            if (packet.HasPassword && !packet.HasUsername)
            {
                throw new DecoderException("[MQTT-3.1.2-22]");
            }
            if ((connectFlags & 0x1) != 0) // [MQTT-3.1.2-3]
            {
                throw new DecoderException("[MQTT-3.1.2-3]");
            }

            packet.KeepAliveInSeconds = DecodeUnsignedShort(buffer, ref remainingLength);

            string clientId = DecodeString(buffer, ref remainingLength);

            Util.ValidateClientId(clientId);
            packet.ClientId = clientId;

            if (hasWill)
            {
                packet.WillTopicName = DecodeString(buffer, ref remainingLength);
                int willMessageLength = DecodeUnsignedShort(buffer, ref remainingLength);
                DecreaseRemainingLength(ref remainingLength, willMessageLength);
                packet.WillMessage = buffer.ReadBytes(willMessageLength);
            }

            if (packet.HasUsername)
            {
                packet.Username = DecodeString(buffer, ref remainingLength);
            }

            if (packet.HasPassword)
            {
                packet.Password = DecodeString(buffer, ref remainingLength);
            }
        }
示例#19
0
        static void DecodeConnectPacket(IByteBuffer buffer, ConnectPacket packet, ref int remainingLength, IChannelHandlerContext context)
        {
            string protocolName = DecodeString(buffer, ref remainingLength);

            if (!string.Equals(Util.ProtocolName, protocolName
#if NETCOREAPP_3_0_GREATER || NETSTANDARD_2_0_GREATER
                               ))
#else
                               , StringComparison.Ordinal))
#endif
            {
                ThrowHelper.ThrowDecoderException_UnexpectedProtocolName(protocolName);
            }
            packet.ProtocolName = Util.ProtocolName;

            DecreaseRemainingLength(ref remainingLength, 1);
            packet.ProtocolLevel = buffer.ReadByte();

            if (packet.ProtocolLevel != Util.ProtocolLevel)
            {
                var connAckPacket = new ConnAckPacket
                {
                    ReturnCode = ConnectReturnCode.RefusedUnacceptableProtocolVersion
                };
                context.WriteAndFlushAsync(connAckPacket);
                ThrowHelper.ThrowDecoderException_UnexpectedProtocolLevel(packet.ProtocolLevel);
            }

            DecreaseRemainingLength(ref remainingLength, 1);
            int connectFlags = buffer.ReadByte();

            packet.CleanSession = (connectFlags & 0x02) == 0x02;

            bool hasWill = (connectFlags & 0x04) == 0x04;
            if (hasWill)
            {
                packet.HasWill    = true;
                packet.WillRetain = (connectFlags & 0x20) == 0x20;
                var willQualityOfService = packet.WillQualityOfService = (QualityOfService)((connectFlags & 0x18) >> 3);
                if (willQualityOfService == QualityOfService.Reserved)
                {
                    ThrowHelper.ThrowDecoderException_UnexpectedWillQoSValueOf(willQualityOfService);
                }
                packet.WillTopicName = string.Empty;
            }
            else if ((connectFlags & 0x38) != 0) // bits 3,4,5 [MQTT-3.1.2-11]
            {
                ThrowHelper.ThrowDecoderException_MQTT_312_11();
            }

            packet.HasUsername = (connectFlags & 0x80) == 0x80;
            packet.HasPassword = (connectFlags & 0x40) == 0x40;
            if (packet.HasPassword && !packet.HasUsername)
            {
                ThrowHelper.ThrowDecoderException_MQTT_312_22();
            }
            if ((connectFlags & 0x1) != 0) // [MQTT-3.1.2-3]
            {
                ThrowHelper.ThrowDecoderException_MQTT_312_3();
            }

            packet.KeepAliveInSeconds = DecodeUnsignedShort(buffer, ref remainingLength);

            string clientId = DecodeString(buffer, ref remainingLength);
            if (clientId is null)
            {
                Util.ValidateClientId();
            }
            packet.ClientId = clientId;

            if (hasWill)
            {
                packet.WillTopicName = DecodeString(buffer, ref remainingLength);
                int willMessageLength = DecodeUnsignedShort(buffer, ref remainingLength);
                DecreaseRemainingLength(ref remainingLength, willMessageLength);
                packet.WillMessage = buffer.ReadBytes(willMessageLength);
            }

            if (packet.HasUsername)
            {
                packet.Username = DecodeString(buffer, ref remainingLength);
            }

            if (packet.HasPassword)
            {
                packet.Password = DecodeString(buffer, ref remainingLength);
            }
        }