diff --git a/src/common/tunnel.rs b/src/common/tunnel.rs index ee4174f..bfd7ed9 100644 --- a/src/common/tunnel.rs +++ b/src/common/tunnel.rs @@ -5,30 +5,27 @@ use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; /// Bridge an iroh bi-stream and a generic AsyncRead+AsyncWrite (typically a TCP /// socket) by copying bytes in both directions concurrently. /// -/// Returns once either direction finishes or errors. The peer-side socket -/// halves are owned and dropped here on exit, ensuring FIN propagates. +/// The data direction (peer → quic on the host, quic → peer on the viewer) +/// is the only one whose completion ends the bridge. The reverse direction +/// carries the initial HTTP request and then nothing for a one-way streaming +/// workload; if its `io::copy` finishes (e.g. mpv half-closes its send side), +/// we must not tear down the data direction with it. pub async fn bridge(quic_send: SendStream, quic_recv: RecvStream, peer: T) -> Result<()> where - T: AsyncRead + AsyncWrite + Unpin, + T: AsyncRead + AsyncWrite + Unpin + Send + 'static, { let (mut peer_r, mut peer_w) = tokio::io::split(peer); let mut quic_send = quic_send; let mut quic_recv = quic_recv; - let to_quic = async { - let n = tokio::io::copy(&mut peer_r, &mut quic_send).await; - let _ = quic_send.finish(); - n - }; - let to_peer = async { - let n = tokio::io::copy(&mut quic_recv, &mut peer_w).await; + let reverse = tokio::spawn(async move { + let _ = tokio::io::copy(&mut quic_recv, &mut peer_w).await; let _ = peer_w.shutdown().await; - n - }; + }); - tokio::select! { - res = to_quic => { res?; } - res = to_peer => { res?; } - } + let res = tokio::io::copy(&mut peer_r, &mut quic_send).await; + let _ = quic_send.finish(); + reverse.abort(); + res?; Ok(()) }