Phase 8c hotfix: skip probe deadline when no fallback exists #65
@@ -545,6 +545,17 @@ impl QuicClient {
|
|||||||
lan_probe: std::time::Duration,
|
lan_probe: std::time::Duration,
|
||||||
) -> Result<(quinn::Connection, ConnectRoute)> {
|
) -> Result<(quinn::Connection, ConnectRoute)> {
|
||||||
if let Some(lan_addr) = lan {
|
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(
|
match tokio::time::timeout(
|
||||||
lan_probe,
|
lan_probe,
|
||||||
self.connect(lan_addr, expected_server_name),
|
self.connect(lan_addr, expected_server_name),
|
||||||
@@ -840,6 +851,34 @@ mod tests {
|
|||||||
accept_task.abort();
|
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]
|
#[tokio::test]
|
||||||
async fn connect_lan_first_errors_when_both_addrs_absent() {
|
async fn connect_lan_first_errors_when_both_addrs_absent() {
|
||||||
let (id_a, _id_b) = NodeIdentity::generate_test_pair("a", "b").unwrap();
|
let (id_a, _id_b) = NodeIdentity::generate_test_pair("a", "b").unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user