Phase 8c hotfix: skip probe deadline when no fallback exists #65
@@ -545,6 +545,17 @@ impl QuicClient {
|
||||
lan_probe: std::time::Duration,
|
||||
) -> Result<(quinn::Connection, ConnectRoute)> {
|
||||
if let Some(lan_addr) = lan {
|
||||
// No fallback path → don't apply the probe deadline.
|
||||
// Otherwise a slow-but-fine LAN handshake can spuriously
|
||||
// fail when the operator never opted into a tailnet
|
||||
// fallback in the first place.
|
||||
if tailscale.is_none() {
|
||||
let conn = self
|
||||
.connect(lan_addr, expected_server_name)
|
||||
.await
|
||||
.with_context(|| format!("dialing LAN addr {lan_addr}"))?;
|
||||
return Ok((conn, ConnectRoute::Lan(lan_addr)));
|
||||
}
|
||||
match tokio::time::timeout(
|
||||
lan_probe,
|
||||
self.connect(lan_addr, expected_server_name),
|
||||
@@ -840,6 +851,34 @@ mod tests {
|
||||
accept_task.abort();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn connect_lan_first_lan_only_ignores_probe_deadline() {
|
||||
// Phase 8c hotfix: when no fallback exists, LAN dial gets
|
||||
// unlimited time — otherwise a slow-but-fine handshake
|
||||
// fails a caller that never opted into a fallback path.
|
||||
let (id_a, id_b) = NodeIdentity::generate_test_pair("a", "b").unwrap();
|
||||
let server = QuicServer::bind(loopback(0), id_b).unwrap();
|
||||
let server_addr = server.local_addr().unwrap();
|
||||
let accept_task = tokio::spawn(async move {
|
||||
if let Some(res) = server.accept().await {
|
||||
let conn = res.expect("accept");
|
||||
let _ = ping_handler_loop(conn).await;
|
||||
}
|
||||
server.shutdown().await;
|
||||
});
|
||||
let client = QuicClient::new(loopback(0), id_a).unwrap();
|
||||
// Absurdly short probe. Would fail if the deadline applied.
|
||||
let (conn, route) = client
|
||||
.connect_lan_first("b", Some(server_addr), None, Duration::from_nanos(1))
|
||||
.await
|
||||
.expect("connect_lan_first with no fallback ignores deadline");
|
||||
assert!(matches!(route, ConnectRoute::Lan(a) if a == server_addr));
|
||||
conn.close(VarInt::from_u32(0), b"done");
|
||||
client.shutdown().await;
|
||||
tokio::time::sleep(Duration::from_millis(50)).await;
|
||||
accept_task.abort();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn connect_lan_first_errors_when_both_addrs_absent() {
|
||||
let (id_a, _id_b) = NodeIdentity::generate_test_pair("a", "b").unwrap();
|
||||
|
||||
Reference in New Issue
Block a user