fix(relay): honor advertised egress budgets
Peers announce a QUIC datagram budget in their hello, and the relay clamps that value against the transport's negotiated max before room admission. The relay used that clamped value for MTU selection, but stored the raw transport budget in the live peer session. A peer that intentionally advertised a smaller budget could therefore receive egress datagrams larger than it promised to accept. Store the post-clamp hello budget in AcceptedPeer and PeerSession instead. That keeps the existing relay egress skip path tied to the same negotiated size used for room MTU decisions. The handshake regression now advertises a budget below the QUIC transport budget and asserts that the accepted peer records the advertised value. The README decomposition also calls out the per-peer egress-budget invariant. Test Plan: - cargo fmt --check - cargo test -p lanparty-relay - cargo test --workspace - cargo clippy --workspace --all-targets -- -D warnings - git diff --check - git diff --cached --check Refs: PLAN.md No fragmentation for MVP
This commit is contained in:
@@ -98,6 +98,7 @@ Public relay binary and relay-owned room state:
|
|||||||
- one gateway per room, duplicate client MAC rejection, and room limits
|
- one gateway per room, duplicate client MAC rejection, and room limits
|
||||||
- stable effective room MTU chosen before Ethernet datagrams flow
|
- stable effective room MTU chosen before Ethernet datagrams flow
|
||||||
- live Ethernet datagram forwarding with no ingress reflection
|
- live Ethernet datagram forwarding with no ingress reflection
|
||||||
|
- per-peer egress budget checks against the negotiated datagram size
|
||||||
- reliable `PeerJoined`/`PeerLeft` notifications to existing room peers
|
- reliable `PeerJoined`/`PeerLeft` notifications to existing room peers
|
||||||
- L2 safety filters for invalid-source, jumbo, switch-control, DHCP-server,
|
- L2 safety filters for invalid-source, jumbo, switch-control, DHCP-server,
|
||||||
and IPv6-RA frames
|
and IPv6-RA frames
|
||||||
|
|||||||
@@ -762,6 +762,7 @@ async fn build_handshake_response(
|
|||||||
Ok(hello) => hello,
|
Ok(hello) => hello,
|
||||||
Err(reject) => return (None, ControlMessage::Reject(reject)),
|
Err(reject) => return (None, ControlMessage::Reject(reject)),
|
||||||
};
|
};
|
||||||
|
let peer_max_datagram_size = usize::from(hello.max_datagram_size());
|
||||||
let join = rooms.lock().await.join(hello);
|
let join = rooms.lock().await.join(hello);
|
||||||
|
|
||||||
match join {
|
match join {
|
||||||
@@ -771,7 +772,7 @@ async fn build_handshake_response(
|
|||||||
welcome: join.welcome().clone(),
|
welcome: join.welcome().clone(),
|
||||||
peer: join.peer().clone(),
|
peer: join.peer().clone(),
|
||||||
remote_addr: connection.remote_address(),
|
remote_addr: connection.remote_address(),
|
||||||
max_datagram_size: connection_max_datagram_size,
|
max_datagram_size: peer_max_datagram_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
@@ -950,10 +951,15 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let advertised_datagram_size = 1000;
|
||||||
|
assert!(
|
||||||
|
connection.max_datagram_size().unwrap() > usize::from(advertised_datagram_size),
|
||||||
|
"test must advertise less than the QUIC transport budget"
|
||||||
|
);
|
||||||
let hello = EndpointHello::client(
|
let hello = EndpointHello::client(
|
||||||
RoomCode::new("TESTROOM").unwrap(),
|
RoomCode::new("TESTROOM").unwrap(),
|
||||||
MacAddr::new([0x02, 0, 0, 0, 0, 1]),
|
MacAddr::new([0x02, 0, 0, 0, 0, 1]),
|
||||||
1400,
|
advertised_datagram_size,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let response = request_control_message(&connection, ControlMessage::Hello(hello))
|
let response = request_control_message(&connection, ControlMessage::Hello(hello))
|
||||||
@@ -966,7 +972,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(welcome.room_id(), 1);
|
assert_eq!(welcome.room_id(), 1);
|
||||||
assert_eq!(welcome.peer_id(), 1);
|
assert_eq!(welcome.peer_id(), 1);
|
||||||
assert!(welcome.effective_tap_mtu() <= 1400);
|
assert!(welcome.effective_tap_mtu() <= advertised_datagram_size);
|
||||||
|
|
||||||
connection.close(0_u32.into(), b"test complete");
|
connection.close(0_u32.into(), b"test complete");
|
||||||
client.wait_idle().await;
|
client.wait_idle().await;
|
||||||
@@ -978,6 +984,10 @@ mod tests {
|
|||||||
assert_eq!(accepted.room.as_str(), "TESTROOM");
|
assert_eq!(accepted.room.as_str(), "TESTROOM");
|
||||||
assert_eq!(accepted.peer.peer_id(), 1);
|
assert_eq!(accepted.peer.peer_id(), 1);
|
||||||
assert_eq!(accepted.welcome, welcome);
|
assert_eq!(accepted.welcome, welcome);
|
||||||
|
assert_eq!(
|
||||||
|
accepted.max_datagram_size,
|
||||||
|
usize::from(advertised_datagram_size)
|
||||||
|
);
|
||||||
assert_eq!(rooms.lock().await.room_count(), 0);
|
assert_eq!(rooms.lock().await.room_count(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user