Skip to content

Commit db68372

Browse files
fix: harden traffic capture limits
1 parent de1cfa6 commit db68372

3 files changed

Lines changed: 27 additions & 10 deletions

File tree

‎Cargo.lock‎

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎crates/wsrx/Cargo.toml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ binary = [
1717
"dep:chrono",
1818
"dep:clap",
1919
"dep:once_cell",
20+
"dep:rand",
2021
"dep:serde",
2122
"dep:serde_json",
2223
"dep:subprocess",
@@ -54,6 +55,7 @@ tokio-tungstenite = { workspace = true, optional = true }
5455
chrono = { workspace = true, optional = true }
5556
clap = { workspace = true, optional = true }
5657
once_cell = { workspace = true, optional = true }
58+
rand = { workspace = true, optional = true }
5759
serde = { workspace = true, optional = true }
5860
serde_json = { workspace = true, optional = true }
5961
subprocess = { workspace = true, optional = true }

‎crates/wsrx/src/cli/capture.rs‎

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,23 @@ pub struct CaptureObserver {
3030

3131
impl TrafficObserver for CaptureObserver {
3232
fn observe(&self, direction: TrafficDirection, data: &[u8]) {
33-
let already = self.captured.load(Ordering::Relaxed);
34-
if already >= self.max_bytes {
35-
self.truncated.store(true, Ordering::Relaxed);
36-
return;
37-
}
38-
let remaining = (self.max_bytes - already) as usize;
39-
let length = remaining.min(data.len());
33+
let mut already = self.captured.load(Ordering::Relaxed);
34+
let length = loop {
35+
if already >= self.max_bytes {
36+
self.truncated.store(true, Ordering::Relaxed);
37+
return;
38+
}
39+
let length = ((self.max_bytes - already) as usize).min(data.len());
40+
match self.captured.compare_exchange_weak(
41+
already,
42+
already + length as u64,
43+
Ordering::Relaxed,
44+
Ordering::Relaxed,
45+
) {
46+
Ok(_) => break length,
47+
Err(current) => already = current,
48+
}
49+
};
4050
if length < data.len() {
4151
self.truncated.store(true, Ordering::Relaxed);
4252
}
@@ -46,8 +56,9 @@ impl TrafficObserver for CaptureObserver {
4656
.try_send(CaptureMessage::Packet(direction, packet, SystemTime::now()))
4757
.is_ok()
4858
{
49-
self.captured.fetch_add(length as u64, Ordering::Relaxed);
59+
// The byte reservation above is now committed.
5060
} else {
61+
self.captured.fetch_sub(length as u64, Ordering::Relaxed);
5162
self.truncated.store(true, Ordering::Relaxed);
5263
}
5364
}
@@ -266,12 +277,14 @@ pub fn spawn_retention_cleanup(root: PathBuf, retention_days: u64, max_total_byt
266277
loop {
267278
interval.tick().await;
268279
let root = root.clone();
269-
if let Err(err) = tokio::task::spawn_blocking(move || {
280+
match tokio::task::spawn_blocking(move || {
270281
cleanup_capture_files(&root, retention_days, max_total_bytes)
271282
})
272283
.await
273284
{
274-
error!("capture retention worker failed: {err}");
285+
Ok(Ok(())) => {}
286+
Ok(Err(err)) => error!("capture retention cleanup failed: {err}"),
287+
Err(err) => error!("capture retention worker failed: {err}"),
275288
}
276289
}
277290
});

0 commit comments

Comments
 (0)