fix(viewer): close the endpoint on all post-connect failure paths
open_bi/bind/local_addr/accept all `?`-propagated straight out of run(), skipping the endpoint.close().await at the end and leaking the iroh Endpoint on any post-connect error. Wrap the post-connect body in one block whose result is captured, then close unconditionally — matching the explicit-close idiom of the connect-phase select arms. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+32
-25
@@ -50,34 +50,41 @@ pub async fn run(ticket: EndpointTicket, opts: ViewerOpts) -> Result<()> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let (quic_send, quic_recv) = conn.open_bi().await?;
|
// Everything past the established connection runs in one block so any error
|
||||||
|
// (open_bi, bind, local_addr, accept) is captured rather than `?`-propagated
|
||||||
|
// straight out of the function — that would skip the close below and leak the
|
||||||
|
// endpoint. The connect-phase arms above close explicitly for the same reason.
|
||||||
|
let result = async {
|
||||||
|
let (quic_send, quic_recv) = conn.open_bi().await?;
|
||||||
|
|
||||||
let listener = TcpListener::bind(("127.0.0.1", opts.port)).await?;
|
let listener = TcpListener::bind(("127.0.0.1", opts.port)).await?;
|
||||||
let port = listener.local_addr()?.port();
|
let port = listener.local_addr()?.port();
|
||||||
let url = format!("http://127.0.0.1:{port}");
|
let url = format!("http://127.0.0.1:{port}");
|
||||||
output::emit(output::Event::Connected { url: &url });
|
output::emit(output::Event::Connected { url: &url });
|
||||||
|
|
||||||
if opts.interactive {
|
if opts.interactive {
|
||||||
let player = crate::interactive::prompt_player()?;
|
let player = crate::interactive::prompt_player()?;
|
||||||
player
|
player
|
||||||
.spawn(&url)
|
.spawn(&url)
|
||||||
.with_context(|| "failed to launch player")?;
|
.with_context(|| "failed to launch player")?;
|
||||||
print_viewer_banner_interactive();
|
print_viewer_banner_interactive();
|
||||||
} else {
|
} else {
|
||||||
print_viewer_banner(&url);
|
print_viewer_banner(&url);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokio::select! {
|
||||||
|
accepted = listener.accept() => {
|
||||||
|
let (tcp, peer) = accepted?;
|
||||||
|
tracing::info!(%peer, "local viewer connected");
|
||||||
|
crate::common::tunnel::bridge(quic_send, quic_recv, tcp).await
|
||||||
|
}
|
||||||
|
_ = cancel.cancelled() => {
|
||||||
|
tracing::info!("ctrl-c received before local viewer connected");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.await;
|
||||||
let result = tokio::select! {
|
|
||||||
accepted = listener.accept() => {
|
|
||||||
let (tcp, peer) = accepted?;
|
|
||||||
tracing::info!(%peer, "local viewer connected");
|
|
||||||
crate::common::tunnel::bridge(quic_send, quic_recv, tcp).await
|
|
||||||
}
|
|
||||||
_ = cancel.cancelled() => {
|
|
||||||
tracing::info!("ctrl-c received before local viewer connected");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
endpoint.close().await;
|
endpoint.close().await;
|
||||||
result
|
result
|
||||||
|
|||||||
Reference in New Issue
Block a user