diff --git a/crates/ironrdp-connector/src/connection.rs b/crates/ironrdp-connector/src/connection.rs index 95b53bd4a..55ab284bb 100644 --- a/crates/ironrdp-connector/src/connection.rs +++ b/crates/ironrdp-connector/src/connection.rs @@ -558,6 +558,14 @@ impl Sequence for ClientConnector { written, ClientConnectorState::ConnectionFinalization { connection_activation }, ), + // The inner sequence stays in CapabilitiesExchange when it receives a + // Server Deactivate All PDU before the Server Demand Active PDU (sent + // by e.g. Windows Server and gnome-remote-desktop); mirror it here and + // wait for the next input. + ConnectionActivationState::CapabilitiesExchange { .. } => ( + written, + ClientConnectorState::CapabilitiesExchange { connection_activation }, + ), _ => return Err(general_err!("invalid state (this is a bug)")), } } diff --git a/crates/ironrdp-testsuite-core/tests/session/connection_activation.rs b/crates/ironrdp-testsuite-core/tests/session/connection_activation.rs index 79887d371..d865dba60 100644 --- a/crates/ironrdp-testsuite-core/tests/session/connection_activation.rs +++ b/crates/ironrdp-testsuite-core/tests/session/connection_activation.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use ironrdp_connector::connection_activation::{ConnectionActivationSequence, ConnectionActivationState}; -use ironrdp_connector::{Credentials, DesktopSize, Sequence as _, Written}; +use ironrdp_connector::{ClientConnector, ClientConnectorState, Credentials, DesktopSize, Sequence as _, Written}; use ironrdp_core::{WriteBuf, encode_vec}; use ironrdp_pdu::gcc; use ironrdp_pdu::mcs::{McsMessage, SendDataIndication}; @@ -95,6 +95,26 @@ fn deactivate_all_during_capabilities_exchange_stays_in_same_state() { ); } +#[test] +fn client_connector_stays_in_capabilities_exchange_on_deactivate_all() { + let config = test_config(); + let mut connector = ClientConnector::new(config.clone(), "127.0.0.1:3389".parse().unwrap()); + connector.state = ClientConnectorState::CapabilitiesExchange { + connection_activation: ConnectionActivationSequence::new(config, IO_CHANNEL_ID, USER_CHANNEL_ID), + }; + + let frame = encode_server_share_control(ShareControlPdu::ServerDeactivateAll(ServerDeactivateAll)); + let mut output = WriteBuf::new(); + + let written = connector.step(&frame, &mut output).unwrap(); + + assert_eq!(written, Written::Nothing); + assert!( + matches!(connector.state, ClientConnectorState::CapabilitiesExchange { .. }), + "outer connector state should remain CapabilitiesExchange after DeactivateAll" + ); +} + #[test] fn demand_active_after_deactivate_all_transitions_to_connection_finalization() { let config = test_config();