cast: don't drop the io loop on a single bad message, and don't let a scopeless link-local IPv6 clobber a working host

The receiver-status io loop treated any read error as a dead connection,
so one malformed/unexpected message (e.g. a MEDIA_STATUS missing a field
the struct requires) tore down the whole control channel for the rest of
the session even though the RTP stream was fine. Only end the loop on
Io/Tls/Dns errors now; log and keep going on Serialization/Parsing/etc.

mDNS resolves a single physical Cast device once per local address it
has, so the same device id can show up with a private IPv4 host and
again with a link-local IPv6 host. A bare fe80:: address has no zone id
attached, so connecting to it fails outright -- don't let it replace an
already-usable host in the device map just because it resolved more
recently.
This commit is contained in:
Breadway 2026-08-06 08:47:20 +08:00
parent 696e3f540f
commit 7fb1934d52
2 changed files with 32 additions and 3 deletions

View file

@ -326,10 +326,20 @@ fn run_io_loop(
// doc comment for why that's fine for this project's usage.
}
Ok(_) => {}
Err(e) => {
tracing::debug!(error = %e, "cast session io loop ending: receive error");
// Only end the loop on an error that means the connection
// itself is gone -- a single malformed/unexpected message (e.g.
// a MEDIA_STATUS missing a field this crate's struct treats as
// required) is a `Serialization`/`Parsing` error, not a dead
// socket, and used to take the whole receiver-status/control
// channel down with it for the rest of the session even though
// the RTP stream itself was unaffected.
Err(e @ (rust_cast::errors::Error::Io(_) | rust_cast::errors::Error::Tls(_) | rust_cast::errors::Error::Dns(_))) => {
tracing::debug!(error = %e, "cast session io loop ending: connection error");
return;
}
Err(e) => {
tracing::warn!(error = %e, "cast session: ignoring unparseable/unexpected message");
}
}
}
}