mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-07-13 18:54:55 +03:00
fix(proto): tolerate undecodable peer datagrams instead of disconnecting
The DTLS recv loops in src/listen.rs and src/connect.rs each read one full datagram per call. A failed `try_into::<ProtoEvent>()` means the datagram's leading EventType byte didn't match any known variant — a misalignment is impossible because DTLS is message-framed, not stream-framed. Previously, src/listen.rs would `break` out of the loop on parse failure (tearing down the connection) and src/connect.rs would silently swallow the error with no log. Both are wrong as forward-compat behavior: any future protocol addition (e.g. a new event variant) would force every existing peer to disconnect rather than gracefully ignoring the unknown event. Skip-and-continue on both sides, with a debug-level log so the behavior is observable. Pre-requisite for any future ProtoEvent variant to land without forcing a coordinated upgrade across every peer in a deployment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
Ferdinand Schober
parent
dbeaea03ad
commit
82766cdc87
@@ -255,16 +255,23 @@ async fn receive_loop(
|
|||||||
) {
|
) {
|
||||||
let mut buf = [0u8; MAX_EVENT_SIZE];
|
let mut buf = [0u8; MAX_EVENT_SIZE];
|
||||||
while conn.recv(&mut buf).await.is_ok() {
|
while conn.recv(&mut buf).await.is_ok() {
|
||||||
if let Ok(event) = buf.try_into() {
|
match buf.try_into() {
|
||||||
log::trace!("{addr} <==<==<== {event}");
|
Ok(event) => {
|
||||||
match event {
|
log::trace!("{addr} <==<==<== {event}");
|
||||||
ProtoEvent::Pong(b) => {
|
match event {
|
||||||
client_manager.set_active_addr(handle, Some(addr));
|
ProtoEvent::Pong(b) => {
|
||||||
client_manager.set_alive(handle, b);
|
client_manager.set_active_addr(handle, Some(addr));
|
||||||
ping_response.borrow_mut().insert(addr);
|
client_manager.set_alive(handle, b);
|
||||||
|
ping_response.borrow_mut().insert(addr);
|
||||||
|
}
|
||||||
|
event => tx.send((handle, event)).expect("channel closed"),
|
||||||
}
|
}
|
||||||
event => tx.send((handle, event)).expect("channel closed"),
|
|
||||||
}
|
}
|
||||||
|
// Skip undecodable datagrams without dropping the
|
||||||
|
// connection. Each DTLS recv is one framed message, so
|
||||||
|
// skipping is safe and keeps us forward-compatible with
|
||||||
|
// peers that send event types we don't yet know about.
|
||||||
|
Err(e) => log::debug!("ignoring undecodable event from {addr}: {e}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log::warn!("recv error");
|
log::warn!("recv error");
|
||||||
|
|||||||
@@ -259,8 +259,16 @@ async fn read_loop(
|
|||||||
.send(ListenEvent::Msg { event, addr })
|
.send(ListenEvent::Msg { event, addr })
|
||||||
.expect("channel closed"),
|
.expect("channel closed"),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("error receiving event: {e}");
|
// Skip the malformed/unknown datagram and keep
|
||||||
break;
|
// listening. Each DTLS recv returns one full
|
||||||
|
// datagram, so a parse error here can't desync a
|
||||||
|
// stream; the next call gets a fresh, framed
|
||||||
|
// message. This makes the protocol forward-
|
||||||
|
// compatible: a peer running a newer Lan Mouse
|
||||||
|
// version can introduce additional event types
|
||||||
|
// and old peers will simply ignore them rather
|
||||||
|
// than dropping the connection.
|
||||||
|
log::debug!("ignoring undecodable event from {addr}: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user