From 1d469d437b7173ed0cc9131e7e22d0854617292c Mon Sep 17 00:00:00 2001 From: ddidderr Date: Fri, 22 May 2026 06:31:39 +0200 Subject: [PATCH] fix(relay): seed peers before join welcome The gateway authorizes remote-to-LAN frames from the relay lifecycle table. A new client can start sending Ethernet datagrams as soon as it receives its welcome, so the relay should notify already-present peers before returning that welcome to the joining peer. Register the accepted peer, send the PeerJoined event to existing peers, and then send the welcome to the joining peer. If the welcome write fails after the pre-notification, remove the accepted peer and send PeerLeft so existing peers do not retain stale client MAC state. This still is not a cross-connection delivery proof, but it puts the relay-side ordering in the right direction for first DHCP/ARP frames after a client joins. Test Plan: - cargo test -p lanparty-relay - cargo fmt --check - cargo test --workspace - cargo clippy --workspace --all-targets -- -D warnings - git diff --check - git diff --cached --check Refs: PLAN.md MVP relay lifecycle and gateway MAC learning --- README.md | 4 +++- crates/lanparty-relay/src/server.rs | 13 +++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 449c579..0cc579f 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,9 @@ Unknown unicast from a client is forwarded only to the gateway port; unknown unicast from the gateway is dropped instead of flooded to every remote client. When a peer joins or leaves, the relay sends a reliable lifecycle control event to peers that are still present in the room. Newly joined peers also receive -`PeerJoined` events for peers that were already present. +`PeerJoined` events for peers that were already present. Accepted joins notify +existing peers before the joining peer receives its welcome, so gateways can +seed client MAC state before a freshly accepted client starts sending frames. ### MVP Trust Model diff --git a/crates/lanparty-relay/src/server.rs b/crates/lanparty-relay/src/server.rs index 9aa9ca3..964a4b6 100644 --- a/crates/lanparty-relay/src/server.rs +++ b/crates/lanparty-relay/src/server.rs @@ -275,18 +275,27 @@ async fn accept_control_handshake( let (accepted, response) = build_handshake_response(rooms, connection, frame.as_slice()).await; if let Some(accepted) = &accepted { register_peer(sessions, accepted, connection.clone()).await; + // Seed existing peers before the joining peer can send Ethernet datagrams. + notify_peer_joined(sessions, accepted).await; } if let Err(error) = send_control_message(&mut send, &response).await { if let Some(accepted) = &accepted { - leave_peer(rooms, sessions, &accepted.room, accepted.peer.peer_id()).await?; + let leave = + leave_peer(rooms, sessions, &accepted.room, accepted.peer.peer_id()).await?; + notify_peer_left( + sessions, + &accepted.room, + leave.peer().peer_id(), + DisconnectReason::Normal, + ) + .await; } return Err(error); } if let Some(accepted) = &accepted { - notify_peer_joined(sessions, accepted).await; notify_existing_peers_to_joined_peer(rooms, connection, accepted).await; }