Compare commits

...

1 Commits

Author SHA1 Message Date
DuProcess bae0d0ed56 Harden stream queues and hostile network tests
ci / test (push) Has been cancelled
ci / fuzz-smoke (push) Has been cancelled
ci / windows-client (push) Has been cancelled
ci / package-release (linux-x86_64, ubuntu-latest) (push) Has been cancelled
ci / package-release (macos-aarch64, macos-14) (push) Has been cancelled
ci / package-release (macos-x86_64, macos-13) (push) Has been cancelled
ci / package-release (windows-x86_64, windows-latest) (push) Has been cancelled
ci / remote-bench (push) Has been cancelled
2026-07-11 17:33:49 -04:00
6 changed files with 33 additions and 12 deletions
Generated
+1 -1
View File
@@ -436,7 +436,7 @@ dependencies = [
[[package]] [[package]]
name = "dosh" name = "dosh"
version = "1.0.0-rc23" version = "1.0.0-rc24"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64", "base64",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "dosh" name = "dosh"
version = "1.0.0-rc23" version = "1.0.0-rc24"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
+3 -1
View File
@@ -6253,7 +6253,9 @@ async fn flush_stream_pending_data(
if credit < bytes.len() { if credit < bytes.len() {
break; break;
} }
let bytes = pending.pop_front().expect("pending front exists"); let Some(bytes) = pending.pop_front() else {
break;
};
*stream_send_credit.entry(stream_id).or_default() -= bytes.len(); *stream_send_credit.entry(stream_id).or_default() -= bytes.len();
let offset = *stream_next_send_offset.entry(stream_id).or_default(); let offset = *stream_next_send_offset.entry(stream_id).or_default();
stream_next_send_offset.insert(stream_id, offset.saturating_add(bytes.len() as u64)); stream_next_send_offset.insert(stream_id, offset.saturating_add(bytes.len() as u64));
+10 -4
View File
@@ -2752,10 +2752,13 @@ async fn handle_file_request(
atomic, atomic,
}); });
if let Some(mode) = mode { if let Some(mode) = mode {
let target = upload let Some(active_upload) = upload.as_ref() else {
return Err(anyhow!("upload state missing after start"));
};
let target = active_upload
.temp_path
.as_ref() .as_ref()
.and_then(|state| state.temp_path.as_ref()) .unwrap_or(&active_upload.final_path)
.unwrap_or_else(|| &upload.as_ref().unwrap().final_path)
.clone(); .clone();
set_mode(&target, mode)?; set_mode(&target, mode)?;
} }
@@ -3243,7 +3246,10 @@ async fn flush_stream_pending_data_to_client(
if credit < bytes.len() { if credit < bytes.len() {
return Ok(()); return Ok(());
} }
let bytes = pending.pop_front().expect("pending front exists"); let Some(bytes) = pending.pop_front() else {
client.stream_pending_data.remove(&stream_id);
return Ok(());
};
if pending.is_empty() { if pending.is_empty() {
client.stream_pending_data.remove(&stream_id); client.stream_pending_data.remove(&stream_id);
} }
+4 -2
View File
@@ -596,11 +596,13 @@ impl StreamMux {
if self.send_credit.get(&stream_id).copied().unwrap_or(0) < front_len { if self.send_credit.get(&stream_id).copied().unwrap_or(0) < front_len {
break; break;
} }
let bytes = self let Some(bytes) = self
.pending_data .pending_data
.get_mut(&stream_id) .get_mut(&stream_id)
.and_then(VecDeque::pop_front) .and_then(VecDeque::pop_front)
.expect("pending front exists"); else {
break;
};
if self if self
.pending_data .pending_data
.get(&stream_id) .get(&stream_id)
+14 -3
View File
@@ -29,7 +29,7 @@ use std::io::{Read, Write};
use std::net::{SocketAddr, TcpListener, UdpSocket}; use std::net::{SocketAddr, TcpListener, UdpSocket};
use std::process::{Child, Command, Stdio}; use std::process::{Child, Command, Stdio};
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering};
use std::sync::mpsc::{Receiver, Sender, channel}; use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread; use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@@ -49,9 +49,20 @@ use ed25519_dalek::{SigningKey, VerifyingKey};
use rand::rngs::StdRng; use rand::rngs::StdRng;
use rand::{Rng, SeedableRng}; use rand::{Rng, SeedableRng};
const TEST_UDP_PORT_START: u16 = 31_000;
const TEST_UDP_PORT_END: u16 = 60_999;
static NEXT_UDP_PORT: AtomicU32 = AtomicU32::new(TEST_UDP_PORT_START as u32);
fn free_udp_port() -> u16 { fn free_udp_port() -> u16 {
let socket = UdpSocket::bind("127.0.0.1:0").unwrap(); let span = u32::from(TEST_UDP_PORT_END - TEST_UDP_PORT_START) + 1;
socket.local_addr().unwrap().port() for _ in TEST_UDP_PORT_START..=TEST_UDP_PORT_END {
let offset = NEXT_UDP_PORT.fetch_add(1, Ordering::SeqCst) % span;
let port = TEST_UDP_PORT_START + offset as u16;
if UdpSocket::bind(("127.0.0.1", port)).is_ok() {
return port;
}
}
panic!("no free UDP test port in {TEST_UDP_PORT_START}-{TEST_UDP_PORT_END}");
} }
fn write_server_config(dir: &tempfile::TempDir, port: u16) -> std::path::PathBuf { fn write_server_config(dir: &tempfile::TempDir, port: u16) -> std::path::PathBuf {