fix: deliver the displacement to an authorized port forward

An authorized port forward leaves the main select loop as soon as its tunnel
is up (`port_forward_socket.is_some()` right after the logon response) and
spends the rest of its life in `try_port_forward_loop`, which only received
`rx_from_cm`. So the `Displaced` its replacement sent over `tx_from_authed`
was queued and never read, and the stale tunnel kept running - while the test
below asserts a port forward displaces its own kind.

Registration happens inside the logon response, before that break, so the
connection is in `AUTHED_CONNS` and does get selected; only the delivery was
missing. Every other kind stays in the main loop and was unaffected, the mux
port forward included: the break tests `port_forward_socket`, which a mux
tunnel does not set.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019aokqJuhjvB3kijXtAg5Ns
This commit is contained in:
rustdesk
2026-09-09 08:03:22 +08:00
parent 36a6cb0c5a
commit 070085a001

View File

@@ -1109,7 +1109,10 @@ impl Connection {
if conn.authorized {
password::update_temporary_password();
}
if let Err(err) = conn.try_port_forward_loop(&mut rx_from_cm).await {
if let Err(err) = conn
.try_port_forward_loop(&mut rx_from_cm, &mut rx_from_authed)
.await
{
conn.on_close(&err.to_string(), false).await;
raii::AuthedConnID::check_remove_session(conn.inner.id(), conn.session_key());
}
@@ -1215,6 +1218,7 @@ impl Connection {
async fn try_port_forward_loop(
&mut self,
rx_from_cm: &mut mpsc::UnboundedReceiver<Data>,
rx_from_authed: &mut mpsc::UnboundedReceiver<Data>,
) -> ResultType<()> {
let mut last_recv_time = Instant::now();
if let Some(mut forward) = self.port_forward_socket.take() {
@@ -1242,6 +1246,14 @@ impl Connection {
_ => {}
}
}
// An authorized port forward leaves the main select loop the moment its
// tunnel is up, so this is where it spends the rest of its life and the only
// place a displacement can still reach it.
Some(data) = rx_from_authed.recv() => {
if let ipc::Data::Displaced = data {
bail!("displaced by a newer connection");
}
}
res = forward.next() => {
if let Some(res) = res {
last_recv_time = Instant::now();