mutating func processInboundMessage()

in Sources/NIOSSH/Connection State Machine/SSHConnectionStateMachine.swift [125:683]


    mutating func processInboundMessage(allocator: ByteBufferAllocator,
                                        loop: EventLoop) throws -> StateMachineInboundProcessResult? {
        switch self.state {
        case .idle:
            preconditionFailure("Received messages before sending our first message.")
        case .sentVersion(var state):
            guard let message = try state.parser.nextPacket() else {
                return nil
            }

            switch message {
            case .version(let version):
                try state.receiveVersionMessage(version, role: self.role)
                let newState = KeyExchangeState(sentVersionState: state, allocator: allocator, loop: loop, remoteVersion: version)
                let message = newState.keyExchangeStateMachine.createKeyExchangeMessage()
                self.state = .keyExchange(newState)
                return .emitMessage(SSHMultiMessage(.keyExchange(message)))

            case .disconnect:
                self.state = .receivedDisconnect(state.role)
                return .disconnect

            case .unimplemented(let unimplemented):
                throw NIOSSHError.remotePeerDoesNotSupportMessage(unimplemented)

            default:
                throw NIOSSHError.protocolViolation(protocolName: "transport", violation: "Did not receive version message")
            }
        case .keyExchange(var state):
            guard let message = try state.parser.nextPacket() else {
                return nil
            }

            switch message {
            case .keyExchange(let message):
                let result = try state.receiveKeyExchangeMessage(message)
                self.state = .keyExchange(state)
                return result
            case .keyExchangeInit(let message):
                let result = try state.receiveKeyExchangeInitMessage(message)
                self.state = .keyExchange(state)
                return result
            case .keyExchangeReply(let message):
                let result = try state.receiveKeyExchangeReplyMessage(message)
                self.state = .keyExchange(state)
                return result
            case .newKeys:
                try state.receiveNewKeysMessage()
                self.state = .receivedNewKeys(.init(keyExchangeState: state, loop: loop))
                return .noMessage
            case .disconnect:
                self.state = .receivedDisconnect(state.role)
                return .disconnect
            case .ignore, .debug:
                // Ignore these
                self.state = .keyExchange(state)
                return .noMessage
            case .unimplemented(let unimplemented):
                throw NIOSSHError.remotePeerDoesNotSupportMessage(unimplemented)
            default:
                // TODO: enforce RFC 4253:
                //
                // > Once a party has sent a SSH_MSG_KEXINIT message for key exchange or
                // > re-exchange, until it has sent a SSH_MSG_NEWKEYS message (Section
                // > 7.3), it MUST NOT send any messages other than:
                // >
                // > o  Transport layer generic messages (1 to 19) (but
                // >    SSH_MSG_SERVICE_REQUEST and SSH_MSG_SERVICE_ACCEPT MUST NOT be
                // >    sent);
                // >
                // > o  Algorithm negotiation messages (20 to 29) (but further
                // >    SSH_MSG_KEXINIT messages MUST NOT be sent);
                // >
                // > o  Specific key exchange method messages (30 to 49).
                //
                // We should enforce that, but right now we don't have a good mechanism by which to do so.
                throw NIOSSHError.protocolViolation(protocolName: "user auth", violation: "Unexpected user auth message: \(message)")
            }
        case .sentNewKeys(var state):
            guard let message = try state.parser.nextPacket() else {
                return nil
            }

            switch message {
            case .keyExchange(let message):
                let result = try state.receiveKeyExchangeMessage(message)
                self.state = .sentNewKeys(state)
                return result
            case .keyExchangeInit(let message):
                let result = try state.receiveKeyExchangeInitMessage(message)
                self.state = .sentNewKeys(state)
                return result
            case .keyExchangeReply(let message):
                let result = try state.receiveKeyExchangeReplyMessage(message)
                self.state = .sentNewKeys(state)
                return result
            case .newKeys:
                try state.receiveNewKeysMessage()
                self.state = .userAuthentication(.init(sentNewKeysState: state))
                return .noMessage
            case .disconnect:
                self.state = .receivedDisconnect(state.role)
                return .disconnect
            case .ignore, .debug:
                // Ignore these
                self.state = .sentNewKeys(state)
                return .noMessage
            case .unimplemented(let unimplemented):
                throw NIOSSHError.remotePeerDoesNotSupportMessage(unimplemented)

            default:
                // TODO: enforce RFC 4253:
                //
                // > Once a party has sent a SSH_MSG_KEXINIT message for key exchange or
                // > re-exchange, until it has sent a SSH_MSG_NEWKEYS message (Section
                // > 7.3), it MUST NOT send any messages other than:
                // >
                // > o  Transport layer generic messages (1 to 19) (but
                // >    SSH_MSG_SERVICE_REQUEST and SSH_MSG_SERVICE_ACCEPT MUST NOT be
                // >    sent);
                // >
                // > o  Algorithm negotiation messages (20 to 29) (but further
                // >    SSH_MSG_KEXINIT messages MUST NOT be sent);
                // >
                // > o  Specific key exchange method messages (30 to 49).
                //
                // We should enforce that, but right now we don't have a good mechanism by which to do so.
                throw NIOSSHError.protocolViolation(protocolName: "key exchange", violation: "Unexpected message: \(message)")
            }

        case .receivedNewKeys(var state):
            // In this state we tolerate receiving service request messages. As we haven't sent newKeys, we cannot
            // send any user auth messages yet, so by definition we can't receive any other user auth message.
            guard let message = try state.parser.nextPacket() else {
                return nil
            }

            switch message {
            case .serviceRequest(let message):
                let result = try state.receiveServiceRequest(message)
                self.state = .receivedNewKeys(state)
                return result

            case .disconnect:
                self.state = .receivedDisconnect(state.role)
                return .disconnect

            case .ignore, .debug:
                // Ignore these
                self.state = .receivedNewKeys(state)
                return .noMessage

            case .serviceAccept, .userAuthRequest, .userAuthSuccess, .userAuthFailure:
                throw NIOSSHError.protocolViolation(protocolName: "user auth", violation: "Unexpected user auth message: \(message)")

            case .unimplemented(let unimplemented):
                throw NIOSSHError.remotePeerDoesNotSupportMessage(unimplemented)

            default:
                throw NIOSSHError.protocolViolation(protocolName: "user auth", violation: "Unexpected inbound message: \(message)")
            }

        case .userAuthentication(var state):
            // In this state we tolerate receiving user auth messages.
            guard let message = try state.parser.nextPacket() else {
                return nil
            }

            switch message {
            case .serviceRequest(let message):
                let result = try state.receiveServiceRequest(message)
                self.state = .userAuthentication(state)
                return result

            case .serviceAccept(let message):
                let result = try state.receiveServiceAccept(message)
                self.state = .userAuthentication(state)
                return result

            case .userAuthRequest(let message):
                let result = try state.receiveUserAuthRequest(message)
                self.state = .userAuthentication(state)
                return result

            case .userAuthSuccess:
                let result = try state.receiveUserAuthSuccess()
                // Hey, auth succeeded!
                self.state = .active(ActiveState(state))
                return result

            case .userAuthFailure(let message):
                let result = try state.receiveUserAuthFailure(message)
                self.state = .userAuthentication(state)
                return result

            case .userAuthBanner(let message):
                let result = try state.receiveUserAuthBanner(message)
                self.state = .userAuthentication(state)
                return result

            case .disconnect:
                self.state = .receivedDisconnect(state.role)
                return .disconnect

            case .ignore, .debug:
                // Ignore these
                self.state = .userAuthentication(state)
                return .noMessage

            case .unimplemented(let unimplemented):
                throw NIOSSHError.remotePeerDoesNotSupportMessage(unimplemented)

            default:
                throw NIOSSHError.protocolViolation(protocolName: "user auth", violation: "Unexpected inbound message: \(message)")
            }

        case .active(var state):
            guard let message = try state.parser.nextPacket() else {
                return nil
            }

            switch message {
            case .channelOpen(let message):
                try state.receiveChannelOpen(message)
            case .channelOpenConfirmation(let message):
                try state.receiveChannelOpenConfirmation(message)
            case .channelOpenFailure(let message):
                try state.receiveChannelOpenFailure(message)
            case .channelEOF(let message):
                try state.receiveChannelEOF(message)
            case .channelClose(let message):
                try state.receiveChannelClose(message)
            case .channelWindowAdjust(let message):
                try state.receiveChannelWindowAdjust(message)
            case .channelData(let message):
                try state.receiveChannelData(message)
            case .channelExtendedData(let message):
                try state.receiveChannelExtendedData(message)
            case .channelRequest(let message):
                try state.receiveChannelRequest(message)
            case .channelSuccess(let message):
                try state.receiveChannelSuccess(message)
            case .channelFailure(let message):
                try state.receiveChannelFailure(message)
            case .globalRequest(let message):
                try state.receiveGlobalRequest(message)
                self.state = .active(state)
                return .globalRequest(message)
            case .requestSuccess(let message):
                try state.receiveRequestSuccess(message)
                self.state = .active(state)
                return .globalRequestResponse(.success(message))
            case .requestFailure:
                try state.receiveRequestFailure()
                self.state = .active(state)
                return .globalRequestResponse(.failure)
            case .keyExchange(let message):
                // Attempting to rekey.
                var newState = ReceivedKexInitWhenActiveState(state, allocator: allocator, loop: loop)
                let result = try newState.receiveKeyExchangeMessage(message)
                self.state = .receivedKexInitWhenActive(newState)
                return result
            case .disconnect:
                self.state = .receivedDisconnect(state.role)
                return .disconnect
            case .ignore, .debug:
                // Ignore these
                self.state = .active(state)
                return .noMessage
            case .unimplemented(let unimplemented):
                throw NIOSSHError.remotePeerDoesNotSupportMessage(unimplemented)

            default:
                throw NIOSSHError.protocolViolation(protocolName: "connection", violation: "Unexpected inbound message: \(message)")
            }

            self.state = .active(state)
            return .forwardToMultiplexer(message)

        case .receivedKexInitWhenActive(var state):
            // We've received a key exchange packet. We only expect the first two messages (key exchange and key exchange init) before
            // we have sent a reply.
            guard let message = try state.parser.nextPacket() else {
                return nil
            }

            switch message {
            case .keyExchange(let message):
                let result = try state.receiveKeyExchangeMessage(message)
                self.state = .receivedKexInitWhenActive(state)
                return result
            case .keyExchangeInit(let message):
                let result = try state.receiveKeyExchangeInitMessage(message)
                self.state = .receivedKexInitWhenActive(state)
                return result
            case .disconnect:
                self.state = .receivedDisconnect(state.role)
                return .disconnect
            case .ignore, .debug:
                // Ignore these
                self.state = .receivedKexInitWhenActive(state)
                return .noMessage
            case .unimplemented(let unimplemented):
                throw NIOSSHError.remotePeerDoesNotSupportMessage(unimplemented)
            default:
                // TODO: enforce RFC 4253:
                //
                // > Once a party has sent a SSH_MSG_KEXINIT message for key exchange or
                // > re-exchange, until it has sent a SSH_MSG_NEWKEYS message (Section
                // > 7.3), it MUST NOT send any messages other than:
                // >
                // > o  Transport layer generic messages (1 to 19) (but
                // >    SSH_MSG_SERVICE_REQUEST and SSH_MSG_SERVICE_ACCEPT MUST NOT be
                // >    sent);
                // >
                // > o  Algorithm negotiation messages (20 to 29) (but further
                // >    SSH_MSG_KEXINIT messages MUST NOT be sent);
                // >
                // > o  Specific key exchange method messages (30 to 49).
                //
                // We should enforce that, but right now we don't have a good mechanism by which to do so.
                throw NIOSSHError.protocolViolation(protocolName: "key exchange", violation: "Unexpected message: \(message)")
            }

        case .sentKexInitWhenActive(var state):
            // We've sent a key exchange packet. We expect channel messages _or_ a kexinit packet.
            guard let message = try state.parser.nextPacket() else {
                return nil
            }

            switch message {
            case .keyExchange(let message):
                let result = try state.receiveKeyExchangeMessage(message)
                self.state = .rekeying(.init(state))
                return result

            case .channelOpen(let message):
                try state.receiveChannelOpen(message)
            case .channelOpenConfirmation(let message):
                try state.receiveChannelOpenConfirmation(message)
            case .channelOpenFailure(let message):
                try state.receiveChannelOpenFailure(message)
            case .channelEOF(let message):
                try state.receiveChannelEOF(message)
            case .channelClose(let message):
                try state.receiveChannelClose(message)
            case .channelWindowAdjust(let message):
                try state.receiveChannelWindowAdjust(message)
            case .channelData(let message):
                try state.receiveChannelData(message)
            case .channelExtendedData(let message):
                try state.receiveChannelExtendedData(message)
            case .channelRequest(let message):
                try state.receiveChannelRequest(message)
            case .channelSuccess(let message):
                try state.receiveChannelSuccess(message)
            case .channelFailure(let message):
                try state.receiveChannelFailure(message)
            case .globalRequest(let message):
                try state.receiveGlobalRequest(message)
                self.state = .sentKexInitWhenActive(state)
                return .globalRequest(message)
            case .requestSuccess(let message):
                try state.receiveRequestSuccess(message)
                self.state = .sentKexInitWhenActive(state)
                return .globalRequestResponse(.success(message))
            case .requestFailure:
                try state.receiveRequestFailure()
                self.state = .sentKexInitWhenActive(state)
                return .globalRequestResponse(.failure)
            case .disconnect:
                self.state = .receivedDisconnect(state.role)
                return .disconnect
            case .ignore, .debug:
                // Ignore these
                self.state = .sentKexInitWhenActive(state)
                return .noMessage
            case .unimplemented(let unimplemented):
                throw NIOSSHError.remotePeerDoesNotSupportMessage(unimplemented)

            default:
                throw NIOSSHError.protocolViolation(protocolName: "connection", violation: "Unexpected inbound message: \(message)")
            }

            self.state = .sentKexInitWhenActive(state)
            return .forwardToMultiplexer(message)

        case .rekeying(var state):
            // This is basically the regular key exchange state.
            guard let message = try state.parser.nextPacket() else {
                return nil
            }

            switch message {
            case .keyExchange(let message):
                let result = try state.receiveKeyExchangeMessage(message)
                self.state = .rekeying(state)
                return result
            case .keyExchangeInit(let message):
                let result = try state.receiveKeyExchangeInitMessage(message)
                self.state = .rekeying(state)
                return result
            case .keyExchangeReply(let message):
                let result = try state.receiveKeyExchangeReplyMessage(message)
                self.state = .rekeying(state)
                return result
            case .newKeys:
                try state.receiveNewKeysMessage()
                let newState = RekeyingReceivedNewKeysState(state)
                self.state = .rekeyingReceivedNewKeysState(newState)
                return .noMessage
            case .disconnect:
                self.state = .receivedDisconnect(state.role)
                return .disconnect
            case .ignore, .debug:
                // Ignore these
                self.state = .rekeying(state)
                return .noMessage
            case .unimplemented(let unimplemented):
                throw NIOSSHError.remotePeerDoesNotSupportMessage(unimplemented)
            default:
                // TODO: enforce RFC 4253:
                //
                // > Once a party has sent a SSH_MSG_KEXINIT message for key exchange or
                // > re-exchange, until it has sent a SSH_MSG_NEWKEYS message (Section
                // > 7.3), it MUST NOT send any messages other than:
                // >
                // > o  Transport layer generic messages (1 to 19) (but
                // >    SSH_MSG_SERVICE_REQUEST and SSH_MSG_SERVICE_ACCEPT MUST NOT be
                // >    sent);
                // >
                // > o  Algorithm negotiation messages (20 to 29) (but further
                // >    SSH_MSG_KEXINIT messages MUST NOT be sent);
                // >
                // > o  Specific key exchange method messages (30 to 49).
                //
                // We should enforce that, but right now we don't have a good mechanism by which to do so.
                throw NIOSSHError.protocolViolation(protocolName: "user auth", violation: "Unexpected user auth message: \(message)")
            }

        case .rekeyingReceivedNewKeysState(var state):
            // This is basically a regular active state.
            guard let message = try state.parser.nextPacket() else {
                return nil
            }

            switch message {
            // TODO(cory): One day soon we'll need to support re-keying in this state.
            // For now we only support channel messages.
            case .channelOpen(let message):
                try state.receiveChannelOpen(message)
            case .channelOpenConfirmation(let message):
                try state.receiveChannelOpenConfirmation(message)
            case .channelOpenFailure(let message):
                try state.receiveChannelOpenFailure(message)
            case .channelEOF(let message):
                try state.receiveChannelEOF(message)
            case .channelClose(let message):
                try state.receiveChannelClose(message)
            case .channelWindowAdjust(let message):
                try state.receiveChannelWindowAdjust(message)
            case .channelData(let message):
                try state.receiveChannelData(message)
            case .channelExtendedData(let message):
                try state.receiveChannelExtendedData(message)
            case .channelRequest(let message):
                try state.receiveChannelRequest(message)
            case .channelSuccess(let message):
                try state.receiveChannelSuccess(message)
            case .channelFailure(let message):
                try state.receiveChannelFailure(message)
            case .globalRequest(let message):
                try state.receiveGlobalRequest(message)
                self.state = .rekeyingReceivedNewKeysState(state)
                return .globalRequest(message)
            case .requestSuccess(let message):
                try state.receiveRequestSuccess(message)
                self.state = .rekeyingReceivedNewKeysState(state)
                return .globalRequestResponse(.success(message))
            case .requestFailure:
                try state.receiveRequestFailure()
                self.state = .rekeyingReceivedNewKeysState(state)
                return .globalRequestResponse(.failure)
            case .disconnect:
                self.state = .receivedDisconnect(state.role)
                return .disconnect
            case .ignore, .debug:
                // Ignore these
                self.state = .rekeyingReceivedNewKeysState(state)
                return .noMessage
            case .unimplemented(let unimplemented):
                throw NIOSSHError.remotePeerDoesNotSupportMessage(unimplemented)

            default:
                throw NIOSSHError.protocolViolation(protocolName: "connection", violation: "Unexpected inbound message: \(message)")
            }

            self.state = .rekeyingReceivedNewKeysState(state)
            return .forwardToMultiplexer(message)

        case .rekeyingSentNewKeysState(var state):
            // This is key exchange state.
            guard let message = try state.parser.nextPacket() else {
                return nil
            }

            switch message {
            case .keyExchange(let message):
                let result = try state.receiveKeyExchangeMessage(message)
                self.state = .rekeyingSentNewKeysState(state)
                return result
            case .keyExchangeInit(let message):
                let result = try state.receiveKeyExchangeInitMessage(message)
                self.state = .rekeyingSentNewKeysState(state)
                return result
            case .keyExchangeReply(let message):
                let result = try state.receiveKeyExchangeReplyMessage(message)
                self.state = .rekeyingSentNewKeysState(state)
                return result
            case .newKeys:
                try state.receiveNewKeysMessage()
                let newState = ActiveState(state)
                self.state = .active(newState)
                return .noMessage
            case .disconnect:
                self.state = .receivedDisconnect(state.role)
                return .disconnect
            case .ignore, .debug:
                // Ignore these
                self.state = .rekeyingSentNewKeysState(state)
                return .noMessage
            case .unimplemented(let unimplemented):
                throw NIOSSHError.remotePeerDoesNotSupportMessage(unimplemented)

            default:
                // TODO: enforce RFC 4253:
                //
                // > Once a party has sent a SSH_MSG_KEXINIT message for key exchange or
                // > re-exchange, until it has sent a SSH_MSG_NEWKEYS message (Section
                // > 7.3), it MUST NOT send any messages other than:
                // >
                // > o  Transport layer generic messages (1 to 19) (but
                // >    SSH_MSG_SERVICE_REQUEST and SSH_MSG_SERVICE_ACCEPT MUST NOT be
                // >    sent);
                // >
                // > o  Algorithm negotiation messages (20 to 29) (but further
                // >    SSH_MSG_KEXINIT messages MUST NOT be sent);
                // >
                // > o  Specific key exchange method messages (30 to 49).
                //
                // We should enforce that, but right now we don't have a good mechanism by which to do so.
                throw NIOSSHError.protocolViolation(protocolName: "key exchange", violation: "Unexpected message: \(message)")
            }

        case .receivedDisconnect, .sentDisconnect:
            // We do no further I/O in these states.
            return nil
        }
    }