mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-06-28 03:04:50 +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];
|
||||
while conn.recv(&mut buf).await.is_ok() {
|
||||
if let Ok(event) = buf.try_into() {
|
||||
log::trace!("{addr} <==<==<== {event}");
|
||||
match event {
|
||||
ProtoEvent::Pong(b) => {
|
||||
client_manager.set_active_addr(handle, Some(addr));
|
||||
client_manager.set_alive(handle, b);
|
||||
ping_response.borrow_mut().insert(addr);
|
||||
match buf.try_into() {
|
||||
Ok(event) => {
|
||||
log::trace!("{addr} <==<==<== {event}");
|
||||
match event {
|
||||
ProtoEvent::Pong(b) => {
|
||||
client_manager.set_active_addr(handle, Some(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");
|
||||
|
||||
@@ -259,8 +259,16 @@ async fn read_loop(
|
||||
.send(ListenEvent::Msg { event, addr })
|
||||
.expect("channel closed"),
|
||||
Err(e) => {
|
||||
log::warn!("error receiving event: {e}");
|
||||
break;
|
||||
// Skip the malformed/unknown datagram and keep
|
||||
// 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