diff --git a/crates/lanspread-peer/src/peer.rs b/crates/lanspread-peer/src/peer.rs index 4d7a53b..6005fe9 100644 --- a/crates/lanspread-peer/src/peer.rs +++ b/crates/lanspread-peer/src/peer.rs @@ -4,6 +4,7 @@ use bytes::Bytes; use lanspread_db::db::GameFileDescription; use lanspread_utils::maybe_addr; use s2n_quic::{ + application, connection, stream::{Error as StreamError, SendStream}, }; @@ -14,6 +15,16 @@ use tokio::{ use crate::{config::FILE_TRANSFER_BUFFER_SIZE, path_validation::validate_game_file_path}; +fn cancel_send_stream(tx: &mut SendStream, remote_addr: impl std::fmt::Display, path: &Path) { + // Reset instead of finishing so truncated whole-file transfers cannot look like EOF. + if let Err(err) = tx.reset(application::Error::UNKNOWN) { + log::debug!( + "{remote_addr} failed to reset cancelled transfer for {}: {err}", + path.display() + ); + } +} + #[allow(clippy::too_many_lines)] async fn stream_file_bytes( tx: &mut SendStream, @@ -52,6 +63,7 @@ async fn stream_file_bytes( "{remote_addr} transfer cancelled for {}", validated_path.display() ); + cancel_send_stream(tx, remote_addr, &validated_path); return Err(eyre::eyre!("File transfer cancelled by user")); } @@ -67,6 +79,7 @@ async fn stream_file_bytes( "{remote_addr} transfer cancelled for {}", validated_path.display() ); + cancel_send_stream(tx, remote_addr, &validated_path); return Err(eyre::eyre!("File transfer cancelled by user")); } res = file.read(&mut buf[..read_len]) => { @@ -86,6 +99,7 @@ async fn stream_file_bytes( "{remote_addr} transfer cancelled for {}", validated_path.display() ); + cancel_send_stream(tx, remote_addr, &validated_path); return Err(eyre::eyre!("File transfer cancelled by user")); } res = tx.send(Bytes::copy_from_slice(&buf[..bytes_read])) => { @@ -132,6 +146,7 @@ async fn stream_file_bytes( tokio::select! { () = cancel_token.cancelled() => { log::info!("{remote_addr} transfer cancelled while closing stream"); + cancel_send_stream(tx, remote_addr, &validated_path); return Err(eyre::eyre!("File transfer cancelled by user")); } res = tx.close() => {