feat(ctrl): report gateway presence in welcome
ServerWelcome now carries an initial gateway_connected flag with serde defaulting for older welcome payloads. The relay sets it from room admission state so a gateway sees itself as connected, clients joining behind an existing gateway see yes, and clients that arrive first see no. The Windows client prints that handshake fact at startup. This does not replace the later peer-event stream; it gives phase-1 diagnostics an immediate answer for whether the relay already has a LAN gateway in the room. Test Plan: - cargo fmt --check - cargo test -p lanparty-ctrl -p lanparty-relay -p lanparty-client-core \ -p lanparty-client-win - cargo clippy -p lanparty-ctrl -p lanparty-relay -p lanparty-client-core \ -p lanparty-client-win --all-targets -- -D warnings - cargo test --workspace - cargo clippy --workspace --all-targets -- -D warnings - git diff --check Refs: PLAN.md
This commit is contained in:
@@ -674,6 +674,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(client.welcome().room_id(), 7);
|
||||
assert_eq!(client.welcome().peer_id(), 2);
|
||||
assert!(!client.welcome().gateway_connected());
|
||||
assert!(client.quic_max_datagram_size() <= 1400);
|
||||
assert!(client.quic_diagnostics().datagram_supported());
|
||||
assert_eq!(
|
||||
|
||||
@@ -109,10 +109,11 @@ async fn main() -> Result<()> {
|
||||
|
||||
let session = connect_client(config).await?;
|
||||
println!(
|
||||
"lanparty-client-win connected as peer {} in room id {} with TAP MTU {}",
|
||||
"lanparty-client-win connected as peer {} in room id {} with TAP MTU {}; LAN gateway connected {}",
|
||||
session.welcome().peer_id(),
|
||||
session.welcome().room_id(),
|
||||
session.welcome().effective_tap_mtu()
|
||||
session.welcome().effective_tap_mtu(),
|
||||
yes_no(session.welcome().gateway_connected())
|
||||
);
|
||||
#[cfg(windows)]
|
||||
let relay_route_pin = match pin_relay_route_before_tap(session.config().relay_addr().ip()) {
|
||||
|
||||
@@ -189,6 +189,8 @@ pub struct ServerWelcome {
|
||||
room_id: u64,
|
||||
peer_id: u32,
|
||||
effective_tap_mtu: u16,
|
||||
#[serde(default)]
|
||||
gateway_connected: bool,
|
||||
}
|
||||
|
||||
impl ServerWelcome {
|
||||
@@ -209,9 +211,16 @@ impl ServerWelcome {
|
||||
room_id,
|
||||
peer_id,
|
||||
effective_tap_mtu,
|
||||
gateway_connected: false,
|
||||
})
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn with_gateway_connected(mut self, gateway_connected: bool) -> Self {
|
||||
self.gateway_connected = gateway_connected;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> Result<(), ControlError> {
|
||||
if self.protocol_version != CONTROL_PROTOCOL_VERSION {
|
||||
return Err(ControlError::UnsupportedVersion {
|
||||
@@ -253,6 +262,11 @@ impl ServerWelcome {
|
||||
pub const fn effective_tap_mtu(&self) -> u16 {
|
||||
self.effective_tap_mtu
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn gateway_connected(&self) -> bool {
|
||||
self.gateway_connected
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
|
||||
@@ -489,6 +503,14 @@ mod tests {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn server_welcome_reports_gateway_presence() {
|
||||
let welcome = ServerWelcome::new(1, 2, MIN_USEFUL_TAP_MTU as u16).unwrap();
|
||||
|
||||
assert!(!welcome.gateway_connected());
|
||||
assert!(welcome.with_gateway_connected(true).gateway_connected());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn peer_info_enforces_role_mac_rules() {
|
||||
let client = PeerInfo::new(7, Role::Client, Some(client_mac())).unwrap();
|
||||
|
||||
@@ -327,8 +327,10 @@ impl Room {
|
||||
format!("invalid peer: {error}"),
|
||||
)
|
||||
})?;
|
||||
let welcome =
|
||||
ServerWelcome::new(self.room_id, peer_id, effective_tap_mtu).map_err(|error| {
|
||||
let gateway_connected = matches!(peer.role(), Role::Gateway) || self.gateway.is_some();
|
||||
let welcome = ServerWelcome::new(self.room_id, peer_id, effective_tap_mtu)
|
||||
.map(|welcome| welcome.with_gateway_connected(gateway_connected))
|
||||
.map_err(|error| {
|
||||
Reject::new(
|
||||
RejectReason::InternalError,
|
||||
format!("welcome failed: {error}"),
|
||||
@@ -817,13 +819,24 @@ mod tests {
|
||||
assert_eq!(registry.room_count(), 1);
|
||||
assert_eq!(gateway.peer().role(), Role::Gateway);
|
||||
assert_eq!(gateway.welcome().peer_id(), 1);
|
||||
assert!(gateway.welcome().gateway_connected());
|
||||
assert_eq!(client.peer().role(), Role::Client);
|
||||
assert_eq!(client.welcome().peer_id(), 2);
|
||||
assert!(client.welcome().gateway_connected());
|
||||
assert_eq!(snapshot.gateway().unwrap().peer_id(), 1);
|
||||
assert_eq!(snapshot.clients().len(), 1);
|
||||
assert_eq!(snapshot.effective_tap_mtu(), 1200);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reports_missing_gateway_to_client_joining_first() {
|
||||
let mut registry = RoomRegistry::default();
|
||||
|
||||
let client = registry.join(client_hello(1)).unwrap();
|
||||
|
||||
assert!(!client.welcome().gateway_connected());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_second_gateway() {
|
||||
let mut registry = RoomRegistry::default();
|
||||
|
||||
Reference in New Issue
Block a user