head	1.12;
access;
symbols
	pkgsrc-2026Q1:1.6.0.2
	pkgsrc-2026Q1-base:1.6;
locks; strict;
comment	@# @;


1.12
date	2026.05.05.10.05.00;	author pin;	state Exp;
branches;
next	1.11;
commitid	gwiJTBL3JsRCTBEG;

1.11
date	2026.05.03.14.59.11;	author pin;	state Exp;
branches;
next	1.10;
commitid	oeGCH5KNXL7yAnEG;

1.10
date	2026.05.01.15.45.09;	author pin;	state Exp;
branches;
next	1.9;
commitid	eAihdUNwomTiU7EG;

1.9
date	2026.04.23.13.14.25;	author pin;	state Exp;
branches;
next	1.8;
commitid	64wdscaF2spxk5DG;

1.8
date	2026.04.20.12.25.25;	author pin;	state Exp;
branches;
next	1.7;
commitid	8t7ijDryjJBH9HCG;

1.7
date	2026.03.26.17.53.31;	author pin;	state Exp;
branches;
next	1.6;
commitid	YycrEd8Nm0n5MvzG;

1.6
date	2026.03.12.12.13.41;	author pin;	state Exp;
branches;
next	1.5;
commitid	bSiCpFYehxZolGxG;

1.5
date	2026.03.10.19.28.24;	author pin;	state Exp;
branches;
next	1.4;
commitid	51G5InpQn0zwOsxG;

1.4
date	2026.03.07.17.37.20;	author pin;	state Exp;
branches;
next	1.3;
commitid	nDs4wItU0Smoi4xG;

1.3
date	2026.02.17.14.00.16;	author pin;	state Exp;
branches;
next	1.2;
commitid	tXXAzSQerqtNFJuG;

1.2
date	2026.02.09.20.36.29;	author abs;	state Exp;
branches;
next	1.1;
commitid	AtR09vuoL6IF7KtG;

1.1
date	2026.02.04.13.59.40;	author wiz;	state Exp;
branches;
next	;
commitid	XTS85I4UQJxw54tG;


desc
@@


1.12
log
@net/xfr: update to 0.9.14

## [0.9.14] - 2026-05-03

### Fixed
- **Live UDP loss counter no longer stalls under upload-mode saturation** (issue #70 final fix) — v0.9.13's `TCP_NODELAY` partially addressed the bug but brettowe's retest showed 8 subsequent intervals still bunched at one end-of-test client-side timestamp. Root cause was `tokio::time::interval` defaulting to `MissedTickBehavior::Burst` on the server's stats sampling timer: when `writer.write_all()` stalled under the back-pressure that the saturated UDP uplink induces on TCP control, missed ticks accumulated and fired as a burst when the writer unblocked, producing stale interval samples with fresh client-side arrival timestamps and misleading throughput numbers. `Skip` now drops the stale ticks; cumulative state in `StreamStats` atomics still surfaces correctly on the next live tick and at end-of-test. Applied unconditionally on both `run_test` interval-loop sites; benefits even pre-v0.9.14 clients pairing with a v0.9.14 server.
- **`--omit` no longer folds hidden UDP loss into the first visible interval** — the new cumulative-loss tracker added below was advancing its cache on every progress arrival, but the printed-line baseline only advanced when a line printed. With `--omit 3`, the first visible interval would report all loss accumulated during seconds 0-3 as one jumbo delta, defeating the purpose of `--omit`. The baseline now advances during the omit window so visible lines reflect only loss observed during printed intervals.

### Added
- **UDP receiver feedback (`udp_feedback_v1` capability)** (issue #70 final fix) — when both peers advertise the capability, the server now emits a 36-byte cumulative `(packets_received, packets_lost)` UDP packet back to the client at 2 Hz on the same data socket, sidestepping the TCP control channel for live UDP loss reporting. Wire format: `b"XFRF"` magic + version + kind + flags + `stream_id` + reserved + `elapsed_ms` + cumulative `packets_received` + cumulative `packets_lost`, all big-endian, fixed 36 bytes. Length-first demux at receive sites distinguishes feedback from data packets without inspecting sequence-number bits. Cumulative-not-delta semantics let the client recover from any dropped feedback packet without needing the lost intermediate state. Capability negotiation gates emission so older clients (which wouldn't know to listen) never see a packet they don't understand.
- **Producer-side monotonic-denominator filter on the client** — both the TCP control `udp_progress` decode site and the UDP feedback aggregator funnel updates through `UdpProgressFilter::apply`, which admits only readings whose `(received + lost)` denominator is at-least-as-fresh as anything we've seen before. Atomic CAS via `fetch_update` so two producers cannot race a stale store after a fresh one. Applies in addition to TUI display: plain text, CSV, and JSON-stream output use the cached cumulative as the source of truth for the per-line `lost` field, so the freshest reading from either source flows through to scripted consumers, not just the TUI live counter.
- **Live UDP loss in non-TUI output paths** — `--no-tui --json-stream` / `--csv` / plain interval output now reflects the freshest `udp_progress` from either TCP control or UDP feedback. Previously these consumers used per-stream `streams[].lost` from the most recent TCP `Interval` only, which under control-channel stalls could be several seconds stale. Falls back to the per-stream sum for sessions where `udp_progress` is never sent (paired with a pre-0.9.11 server, or non-UDP tests).
- **Docker repro harness for issue #70** (`docker/Dockerfile.repro`, `docker/repro-issue-70.sh`, `docker/README.md`) — multi-stage build with the current branch and the released v0.9.13 baseline side-by-side. `docker run --rm --cap-add=NET_ADMIN xfr-repro` runs hard assertions on the new build (max bunch ≤ 2, time-to-first-loss < 5s, live mid-run loss observed); `--baseline` prints diagnostics for narrative comparison without gating on a threshold. Stays out of CI — the existing 2× oversubscription `control-channel-skew` job remains the regression floor; the harness is for human-driven A/B at brettowe's 10× recipe before publishing.

### Changed
- **`TestProgress` schema (pre-1.0 break)** — adds `udp_feedback_only: bool` so consumers can distinguish a feedback-only update (only `udp_progress` carries truth; everything else is sentinel/None) from a full TCP `Interval` update. Three consumers handle the partial variant: `App::on_progress` early-returns after updating UDP loss state and preserves all other field values; `main.rs` print loop skips feedback-only entries entirely (the cumulative cache picks up the freshness for the next full interval); cross-version compat test path adopts the new field.
- **Server bidir mode no longer emits UDP feedback** — feedback is upload-mode-only by design. Bidir's server-side recv half was passing `client_supports_udp_feedback` through to `receive_udp` even though the client's bidir recv has no consumer for those packets; emission was pure overhead on the return path. Bidir always passes `false` now.
- **`receive_udp` skips feedback packets in `bytes_received` accounting** — the length-first demux previously rejected feedback before the data path but bumped `bytes_received` first. With server bidir gating that's a moot path post-fix, but defense-in-depth: feedback bytes never count toward `bytes_received`, which tracks test-data wire bandwidth.
- **Capability list factored into a single `SUPPORTED_CAPABILITIES` const** — `client_hello`, `server_hello`, and `server_hello_with_auth` previously each had a duplicated `Vec<String>` literal. Future capability additions now touch one line. New `capability_advertised(&capabilities, name)` helper centralizes the matcher used at both negotiation sites.

### Library API (pre-1.0 break)
- `client::TestProgress` gains `udp_feedback_only: bool`. Constructors must supply it.
- `client::UdpProgressFilter` and `client::UdpFeedbackAggregator` are new public types backing the producer-side filter and aggregator.
- `udp::receive_udp` signature gains a trailing `feedback_enabled: bool` parameter.
- `udp::receive_udp_feedback_only(socket, aggregator, stream_index, cancel)` is new; spawned per-stream on the client in upload mode.
- `udp::UdpFeedbackPacket` and `UDP_FEEDBACK_SIZE` / `UDP_FEEDBACK_MAGIC` / `UDP_FEEDBACK_VERSION` / `UDP_FEEDBACK_KIND_RECEIVER_PROGRESS` constants exported.
- `protocol::SUPPORTED_CAPABILITIES` and `protocol::capability_advertised` exported.
- `stats::StreamStats::udp_progress_snapshot()` exported for callers that need a coherent `(received, lost)` pair.

### Maintenance
- Bump `Cargo.toml` to `0.9.14`.

## [0.9.13] - 2026-05-03

### Fixed
- **Live UDP loss counter no longer stuck at 0% under saturated links** (issue #70 follow-up) — `TCP_NODELAY` was not being set on the control connection. With Nagle still active, the periodic `Interval` messages (~150-byte 1 Hz writes) coalesced waiting for an MSS-sized payload (which never arrives — they're tiny) or a delayed ACK from the peer. Under heavy parallel UDP data load on a saturated path (Wi-Fi, rate-limited links, anything where ACK turnaround stretches), the kernel held every queued segment for the duration of the test and flushed the entire backlog in a single burst when data traffic stopped. The TUI live counter appeared permanently stuck at 0% during the run, then jumped to the final value at quit. iperf3 sets `TCP_NODELAY` on its control channel for exactly this reason. New `tcp::configure_control_stream` helper applies it before splitting the stream into reader/writer halves; called at three sites (server's accepted control connection, client's connecting control connection, server's auth-handshake fallback path). Reproduced and verified with a `tc netem` 50 Mbps + 50ms-delay simulation: the pre-fix binary collapses 3+ interval lines to a single end-of-test timestamp; the post-fix binary spreads them across the run with at most a 2-line tail collision.

### Added
- **CI regression test for the bunching pattern** (`test-control-channel-skew.sh`, runs as the `Control-channel skew (#70 regression)` job). Applies a 50 Mbps shaper + 50ms each-way delay to `lo`, runs an 8-second UDP test at 100 Mbps target (2× oversubscription), and asserts no 3-or-more interval lines share a client-side timestamp. Catches future regressions where the `TCP_NODELAY` plumbing is dropped from any of the three control-stream sites or a new code path forgets to call the helper.

### Maintenance
- Rust dependency group bump (PR #76): `clap_complete` 4.6.2 → 4.6.3, `rustls` 0.23.39 → 0.23.40. Patch-version updates only, no source changes required.
@
text
@# $NetBSD: Makefile,v 1.11 2026/05/03 14:59:11 pin Exp $

DISTNAME=	xfr-0.9.14
CATEGORIES=	net
MASTER_SITES=	${MASTER_SITE_GITHUB:=lance0/}
GITHUB_TAG=	v${PKGVERSION_NOREV}

MAINTAINER=	pkgsrc-users@@NetBSD.org
HOMEPAGE=	https://github.com/lance0/xfr/
COMMENT=	Modern network bandwidth testing with TUI
LICENSE=	apache-2.0 OR mit

# See, https://github.com/briansmith/ring/issues/1999
.include "../../mk/compiler/i386-sse2.mk"

TOOL_DEPENDS+=	cmake-[0-9]*:../../devel/cmake

.include "cargo-depends.mk"

RUST_REQ=	1.88.0

INSTALLATION_DIRS=	${PKGMANDIR}/man1 share/examples/xfr

post-install:
	${INSTALL_MAN} ${WRKSRC}/docs/xfr.1 \
		${DESTDIR}${PREFIX}/${PKGMANDIR}/man1/xfr.1
	${INSTALL_DATA} ${WRKSRC}/examples/config.toml \
		${DESTDIR}${PREFIX}/share/examples/xfr/config.toml

.include "../../lang/rust/cargo.mk"
.include "../../mk/bsd.pkg.mk"
@


1.11
log
@net/xfr: update to 0.9.12

What's Changed

    Add pre-commit hooks for fmt/clippy/test by @@lance0 in #74
    Bump the rust-dependencies group with 15 updates by @@dependabot[bot] in #71
    Apply -w to UDP SO_SNDBUF / SO_RCVBUF on both ends by @@lance0 in #75
@
text
@d1 1
a1 1
# $NetBSD: Makefile,v 1.10 2026/05/01 15:45:09 pin Exp $
d3 1
a3 1
DISTNAME=	xfr-0.9.12
@


1.10
log
@net/xfr: update to 0.9.11

UDP TUI clarity. Two issues from real users — @@brettowe (#70) and @@pythonwood (#72) — pointed at the same weakness: the running TUI was confusing about what its UDP numbers meant. This release rewires the live data path so the values you see during a test match what the test actually saw.
Fixed

    Live UDP packet-loss counter during the run (#70) — the Packet Loss line was stuck at 0.0% for the entire test and only updated to the real value at completion. With -t 0 (infinite mode) the real value was never visible. Server now ships cumulative UdpIntervalProgress { packets_received, packets_lost } on every Interval message; client derives the percent locally and the TUI updates it live. Reported by @@brettowe.
    Final UDP loss accounting only counts valid xfr packets — UdpStats.packets_received and packets_sent now exclude short, malformed, or foreign datagrams that can't be header-decoded. Previously such datagrams inflated packets_received and silently understated the final loss percent.

Added

    Throughput sparkline tints by per-interval loss severity (#70) — clean intervals stay the graph color, light loss (<1% per-interval rate) tints warning, heavy loss (≥1%) tints error. A single-packet hiccup and a heavy drop burst no longer collapse to the same flat tint. Magnitude unknown stays the graph color — honest "no signal."
    Freshness signal for the Packet Loss line — renders dimmed --% when paired against a pre-0.9.11 server or before any UDP traffic has been observed, so unknown is visually distinct from a fresh 0.0% reading.

Changed

    Jitter rolling-window label (#72) — the running display now reads Jitter: 0.86 ms (10s avg: 0.03 ms). The previous (10s: …) form read like a stuck timer; @@pythonwood opened an issue thinking the display was broken on a v0.9.10-client → v0.9.6-server pairing.

Wire-protocol note

AggregateInterval gains an optional udp_progress field (raw counts, not a derived percent — the client owns the math). Cross-version compatibility preserved with serde(default, skip_serializing_if = "Option::is_none"). Verified for both 0.9.10 ↔ 0.9.11 directions in tests; pythonwood's mismatched-version pairing in #72 is a deliberate compat target.
@
text
@d1 1
a1 1
# $NetBSD: Makefile,v 1.9 2026/04/23 13:14:25 pin Exp $
d3 1
a3 1
DISTNAME=	xfr-0.9.11
@


1.9
log
@net/xfr: update to 0.9.10

v0.9.10
Fixed

    TCP teardown no longer hangs under rate-limited paths (#54) — the v0.9.8 SO_LINGER=0 fix didn't take effect when the send loop was parked in stream.write().await under heavy backpressure (tc rate limiting, slow peers, MPTCP subflows filling). send_data and send_data_half now race the pending write() against cancel and deadline in a biased tokio::select!, so either signal breaks the loop and lets SO_LINGER=0 do its job. Confirmed by @@matttbe against his MPTCP + tc reproducer.
    TUI elapsed time stays live during data gaps (#62) — app.elapsed was only updated when the server's Interval progress message arrived. On lossy paths that starved the control channel, the elapsed counter could freeze for several seconds, creating the impression of a "stall" even though the TUI was still redrawing at 20 Hz. The loop now refreshes elapsed from the wall clock every iteration. Pause handling shifts start_time forward by the paused duration on resume, so the counter excludes paused time. Reported by @@brettowe.
    Infinite-duration (-t 0) TUI now shows a live elapsed counter — same fix covers this.

Added

    Client/server version in the Configuration panel (#62) — the TUI now shows xfr/<client> ↔ <server> so cross-version test pairings are obvious at a glance.

Changed

    TUI jitter line shows latest + smoothed together (#48 follow-up) — running display now reads Jitter: 0.02 ms (10s: 0.03 ms) so the instantaneous per-interval value and the 10-second rolling mean are side-by-side. Resolves the confusion where the rolling mean could stay above any single sample's value, making the live display look inconsistent with the final. Completed state still shows just the authoritative final.

Security

    Sanitize server-advertised version before rendering — the Hello.server field crosses a network trust boundary and was being rendered verbatim into the TUI. A hostile or compromised server could send ANSI escape sequences or an oversized string and have the user's terminal act on them. Control characters are now stripped, length is capped at 32, and empty/all-control inputs fall back to (unknown).
    Bump rustls-webpki 0.103.12 → 0.103.13 (RUSTSEC-2026-0104) — reachable panic in CRL parsing.

v0.9.9
Added

    Max jitter and packet size in UDP summary (#48 follow-up) — final UDP summary now reports Jitter Max (peak of the RFC 3550 running estimate) alongside the average, plus Packet Size (UDP payload bytes). Surfaced in plain text and JSON. Requested by @@brettowe for NFS UDP packet-size tuning context.
    -w short alias for --window (#60) — matches iperf3 muscle memory.

Changed

    Bare-integer duration arguments mean seconds (#61) — -t 10, --max-duration 60, --rate-limit-window 30, and discover --timeout 5 now accept plain integers as seconds. Unit-suffixed forms (10s, 1min, 500ms) continue to work unchanged.
        Side effect: --rate-limit-window now rejects zero (0, 0s, 0ms) — 0s was previously accepted and would later panic in the rate-limiter cleanup task because tokio::time::interval requires a non-zero duration. Other duration flags still accept 0 for their existing meanings (-t 0 is infinite).
    Smoothed TUI jitter reading (#48) — the UDP stats panel shows jitter averaged over a 10-second rolling window rather than raw per-second samples. Server data pipeline is unchanged; display is smoothed. While running, the label reads Jitter (10s):; on completion it reverts to Jitter: with the authoritative final value from the server.

Fixed

    Duplicate receive-error log on the server (#54) — tcp::receive_data/receive_data_half each warned at the read-error site, and the caller warned again on the returned Err. The inner warn! is removed so receive errors log exactly once. Reported by @@matttbe.

    Default to kernel TCP autotuning (#60) — xfr no longer forces SO_SNDBUF/SO_RCVBUF to 4 MB on either side by default. Both ends let the kernel autotune unless the user passes -w/--window. When set, the client's value propagates to the server over the control protocol so both sides apply the socket option symmetrically (matching iperf3). Reported by @@matttbe.

    Caveats:
        Loopback / intra-host benchmark numbers may decrease by roughly 10% — this is expected; the previous numbers were inflated by the oversized app-applied buffer.
        On high-RTT paths, very short tests (e.g. -t 1s at high bitrate) may now show ramp-up-limited throughput in the final summary because kernel autotune takes a handful of RTTs to grow the window. Use a longer -t or pass an explicit -w to skip autotune. Note that -O/--omit only hides early intervals from output — the server's final summary is computed over the full test duration.
        Explicit window sizes above c_int::MAX (≈2.1 GB on 64-bit) are now rejected with InvalidInput instead of silently wrapping before setsockopt.

Removed

    Library API: pre-1.0 break — TcpConfig::high_speed() and TcpConfig::with_auto_detect() are gone; construct TcpConfig directly with the fields you want set. The HIGH_SPEED_BUFFER and HIGH_SPEED_WINDOW_THRESHOLD constants (which were private) are also removed. Downstream code that constructs ControlMessage::TestStart, protocol::UdpStats, or tui::app::App by name now needs to supply the new fields (window_size, jitter_max_ms, packet_size, jitter_history); all are additive with sensible defaults.
@
text
@d1 1
a1 1
# $NetBSD: Makefile,v 1.8 2026/04/20 12:25:25 pin Exp $
d3 1
a3 1
DISTNAME=	xfr-0.9.10
@


1.8
log
@net/xfr: update to 0.9.8

[0.9.8] - 2026-04-17
Added

    Separate send/recv reporting in bidir tests (issue #56) — --bidir now reports per-direction bytes and throughput in the summary instead of just the combined total, which was useless on asymmetric links. Plain text shows Send: X  Recv: Y  (Total: Z); JSON adds bytes_sent, bytes_received, throughput_send_mbps, throughput_recv_mbps; CSV gets four new columns; TUI shows ↑ X / ↓ Y in the throughput panel. Unidirectional tests are unchanged (the existing bytes_total/throughput_mbps is already the single-direction number).

Fixed

    Fast, accurate TCP teardown (issue #54) — replaced the blocking shutdown() drain on the send path with SO_LINGER=0 on Linux, so cancel and natural end-of-test no longer wait for bufferbloated send buffers to ACK through rate-limited paths. Fixes the "Timed out waiting 2s for N data streams to stop" warning matttbe reported with -P 4 --mptcp -t 1sec.
    Sender-side byte-count accuracy — stats.bytes_sent is now clamped to tcpi_bytes_acked before abortive close, removing a quiet ~5-10% overcount where the send-buffer tail discarded by RST was being reported as transferred. Download and bidir tests are the primary beneficiaries.
    macOS preserves graceful shutdown — non-Linux platforms lack tcpi_bytes_acked, so the Linux abortive-close path is cfg-gated; other platforms still use shutdown() for accurate accounting.

[0.9.7] - 2026-04-16
Added

    Early exit summary (issue #35) — Ctrl+C now displays a test summary with accumulated stats instead of silently exiting. Works in both plain text and TUI modes. Double Ctrl+C force-exits immediately.
    DSCP server-side propagation — --dscp flag is now sent to the server and applied to server-side TCP/UDP sockets for download and bidirectional tests. Previously only client-side sockets were marked.
    Non-Unix --dscp warning — platforms without socket TOS support now show a visible warning before the test starts, instead of silently no-oping.

Fixed

    Cancel flow waits for server result — client Cancelled handler now waits for the server's Result message instead of immediately erroring, providing accurate final stats after cancel.
    Server result ordering — server sends Result before slow post-processing (push gateway, metrics hooks), preventing false cancel timeouts.
    Rust 1.95 clippy compatibility — fixed manual_checked_ops and collapsible_match_arms lints.

Changed

    Bump softprops/action-gh-release from 2 to 3 in CI release workflow.
@
text
@d1 1
a1 1
# $NetBSD: Makefile,v 1.7 2026/03/26 17:53:31 pin Exp $
d3 1
a3 1
DISTNAME=	xfr-0.9.8
@


1.7
log
@net/xfr: update to 0.9.6

[0.9.6] - 2026-03-18
Added

    --dscp flag — set DSCP/TOS marking on TCP and UDP client sockets for QoS policy testing. Accepts numeric values (0-255) or standard DSCP names (EF, AF11-AF43, CS0-CS7). QUIC warns and ignores the flag; non-Unix platforms warn instead of applying socket marking.
    omit_secs config support (issue #43) — [client] omit_secs = N in config file sets default --omit value.

[0.9.5] - 2026-03-17
Added

    TCP --cport support (issue #44) — --cport now pins client-side TCP data-stream source ports. Multi-stream TCP uses sequential ports (cport, cport+1, ...), matching UDP behavior.

Changed

    TCP --cport semantics — TCP control remains on an ephemeral source port while data streams use the requested source port or range. TCP data binds now match the remote address family the same way UDP/QUIC already do, so dual-stack clients can use --cport against IPv6 targets.
@
text
@d1 1
a1 1
# $NetBSD: Makefile,v 1.6 2026/03/12 12:13:41 pin Exp $
d3 1
a3 1
DISTNAME=	xfr-0.9.6
d13 3
@


1.6
log
@net/xfr: update to 0.9.4

Added

    --no-mdns flag (#41) — xfr serve --no-mdns disables mDNS service registration for environments where multicast is unwanted or another service already uses mDNS.
    server.no_mdns config support — also configurable via [server] no_mdns = true in ~/.config/xfr/config.toml.

Changed

    Delta retransmits in interval reports (#36) — plain text interval lines now show per-interval retransmit deltas instead of cumulative totals, making it easier to spot when retransmits actually occur. Hidden intervals from --omit, --quiet, or larger --interval settings no longer get folded into the next visible rtx: value. Final summary still shows cumulative totals.
@
text
@d1 1
a1 1
# $NetBSD: Makefile,v 1.5 2026/03/10 19:28:24 pin Exp $
d3 1
a3 1
DISTNAME=	xfr-0.9.4
@


1.5
log
@net/xfr: update to 0.9.3

Added

 - Server --bind flag (#38) — xfr serve --bind <IP> binds TCP, QUIC, and UDP data listeners to a specific address.
   Validates against -4/-6 flags and rejects unspecified addresses (::, 0.0.0.0).

Changed

 - Server sends random payloads (#34) — server-side TCP and UDP send paths now use random bytes by default in
   reverse and bidirectional modes, matching the client's default-on behavior.

Fixed

 - QUIC dual-stack on Windows (#39) — QUIC server endpoint now creates its UDP socket via socket2 with explicit
   IPV6_V6ONLY handling instead of relying on Quinn's Endpoint::server(). On Windows/macOS where IPV6_V6ONLY defaults
   to true, binding to [::] would only accept IPv6 connections.
 - Server random payload on single-port TCP reverse (#34) — the single-port TCP handler (DataHello path used by all
   modern clients) was missing random_payload = true, causing reverse-mode downloads to still send zeros.

Security

 - quinn-proto DoS fix — updated quinn-proto 0.11.13 → 0.11.14 (RUSTSEC-2026-0037, severity 8.7)
@
text
@d1 1
a1 1
# $NetBSD: Makefile,v 1.4 2026/03/07 17:37:20 pin Exp $
d3 1
a3 1
DISTNAME=	xfr-0.9.3
@


1.4
log
@net/xfr: update to 0.9.2

0.9.2 - 2026-03-06
Changed

    Random payloads by default (issue #34) — TCP/UDP client-sent payloads now use random bytes by default to avoid silently inflated results on WAN-optimized or compressing paths. --random remains as an explicit no-op for clarity, and new --zeros forces zero-filled payloads for compression/dedup testing. Reverse mode sender remains server-side zeros until protocol negotiation is added.

Fixed

    Windows build regression (issue #37) — pacing_rate_bytes_per_sec() used libc::c_ulong without a #[cfg(target_os = "linux")] guard, breaking compilation on Windows. The function is only called from the linux-gated SO_MAX_PACING_RATE path.
    MPTCP namespace test realism (issue #32) — test-mptcp-ns.sh now combines netem shaping with fq_codel on the shaped transit links, matching common Linux defaults more closely and reducing false-positive high-stream failures caused by shallow unfair queues in the test harness.

0.9.1 - 2026-03-05
Added

    MPTCP support (--mptcp) - Multi-Path TCP on Linux 5.6+ (issue #24). Uses IPPROTO_MPTCP at socket creation via socket2 — all TCP features (nodelay, congestion control, window size, bidir, multi-stream, single-port mode) work transparently. The server automatically creates MPTCP listeners when available (no flag needed) — MPTCP listeners accept both MPTCP and regular TCP clients transparently, with silent fallback to TCP if the kernel lacks MPTCP support. Client uses --mptcp to opt in. Clear error message on non-Linux clients or kernels without CONFIG_MPTCP=y.
    Kernel TCP pacing via SO_MAX_PACING_RATE (issue #30) - On Linux, TCP bitrate pacing (-b) now uses the kernel's FQ scheduler with EDT (Earliest Departure Time) for precise per-packet timing, eliminating burst behavior from userspace sleep/wake cycles. Falls back to userspace pacing on non-Linux, MPTCP sockets (not yet supported in kernel, see mptcp_net-next#578), or if the setsockopt fails. Note: -b sets a global bitrate shared across all parallel streams (unlike iperf3 where -b is per-stream). Suggested by the kernel MPTCP maintainer.
    Random payload mode (--random, issue #34) — client can fill TCP/UDP send buffers with random bytes (once at allocation) to reduce compression/dedup artifacts on shaped/WAN links. Current scope is client-sent payloads only: reverse mode sender remains server-side zeros until protocol negotiation is added.

Changed

    Library API — create_tcp_listener(), connect_tcp(), and connect_tcp_with_bind() now take a mptcp: bool parameter. Library consumers should pass false to preserve existing behavior.

Fixed

    High stream-count TCP robustness (issues #25, #32) — client now stops local data streams at local duration expiry instead of waiting for server Result, scales stream join timeout with stream count (max(2s, streams*50ms)), and TCP receivers drain briefly after cancel to reduce reset-on-close bursts. For single-port TCP setup, client also limits concurrent connect + DataHello handshakes (max 16 in flight) and server initial first-line read timeout is now adaptive to active stream counts (capped at 20s), reducing mid-test handshake-loss failures on constrained links.
    Best-effort send shutdown — send_data() shutdown no longer propagates errors during normal teardown races, matching send_data_half() behavior.
    Kernel pacing rate width — SO_MAX_PACING_RATE now uses native c_ulong instead of u32, removing an unintended ~34 Gbps ceiling on 64-bit Linux.
    JoinHandle panic with many parallel streams (issue #24) — removed second join_all after aborting timed-out stream tasks, which polled already-completed handles
    Final summary showing 0 retransmits/RTT/cwnd (issue #26) — each stream task now captures a final sender-side TCP_INFO snapshot before the socket closes; the Result handler overlays these saved snapshots deterministically instead of racing live fd polls
    Broken pipe / connection reset at teardown (issue #25) — client now joins stream task handles with timeout before returning, preventing writes to already-closed sockets
    MPTCP label in server log — server now displays "MPTCP" instead of "TCP" in the test info log when client uses --mptcp; adds backward-compatible mptcp field to TestStart control message
@
text
@d1 1
a1 1
# $NetBSD: Makefile,v 1.3 2026/02/17 14:00:16 pin Exp $
d3 1
a3 1
DISTNAME=	xfr-0.9.2
@


1.3
log
@net/xfr: update to 0.8.0

## [0.8.0] - 2026-02-12

### Added
- **Client source port pinning** (`--cport`) - pin the client's local port for firewall traversal (issue #16). Works with UDP and QUIC. Multi-stream UDP (`-P N`) assigns sequential ports starting from the specified port (e.g., `--cport 5300 -P 4` uses ports 5300-5303). QUIC multiplexes all streams on the single specified port. TCP rejects `--cport` since single-port mode already handles firewall traversal. Combines with `--bind` for full control (`--bind 10.0.0.1 --cport 5300`). Automatically matches the remote's address family so `--cport` works transparently with both IPv4 and IPv6 targets.

### Fixed
- **`--bind` with IPv6 targets** — `--bind` with an unspecified IP (e.g., `0.0.0.0:0`) now auto-matches the remote's address family at socket creation time across TCP, UDP, and QUIC. Previously failed when connecting to IPv6 targets from dual-stack clients.
- **UDP data_ports length validation** — server returning mismatched port count could panic on `stats.streams[i]`; now validates length before iterating, matching the existing TCP guard

## [0.7.1] - 2026-02-12

### Fixed
- **Server TUI `-0.0 Mbps` after test ends** (issue #20) - IEEE 754 negative zero now normalized via precision-aware `normalize_for_display()` helper across all throughput display paths
- **TCP RTT/retransmits not updating live** (issue #13) - per-interval retransmits now computed from TCP_INFO deltas instead of a dead atomic counter; client stores socket fds for local TCP_INFO polling so sender-side metrics (upload/bidir) update live; download mode correctly uses server-reported metrics
- **Plain-text zero retransmits dropped** - `rtx: 0` was omitted in plain/JSON/CSV interval output when all streams reported zero retransmits; now preserved
- **`mbps_to_human()` unit-switch boundary** - `999.95 Mbps` displayed as `1000.0 Mbps` instead of `1.00 Gbps`; unit branch now uses rounded value

### Changed
- **Consolidated throughput formatting** - server TUI now uses shared `mbps_to_human()` instead of inline formatting; Gbps display changes from 1 to 2 decimal places for consistency

## [0.7.0] - 2026-02-11

### Added
- **Real pause/resume** (`p` key) - pressing `p` now pauses actual data transfer, not just the TUI display. Uses `Pause`/`Resume` protocol messages and a dedicated `watch` channel to stop/resume data loops across TCP, UDP, and QUIC. Capability-gated via `pause_resume` in Hello messages: older servers without support fall back to display-only pause. TCP bitrate pacing resets its baseline on resume to prevent catch-up bursts. UDP receiver resets its inactivity timer during pause to prevent false timeouts. Resolves issue #19.

## [0.6.1] - 2026-02-10

### Added
- **TCP bitrate pacing** (`-b` for TCP) - `-b` flag now works for TCP, not just UDP. Uses byte-budget sleep pacing with interruptible sleeps for responsive cancellation. Buffer size auto-caps to prevent first-write burst at low bitrates. Resolves issue #14.
@
text
@d1 1
a1 1
# $NetBSD: Makefile,v 1.2 2026/02/09 20:36:29 abs Exp $
d3 1
a3 1
DISTNAME=	xfr-0.8.0
@


1.2
log
@Updated net/xfr to 0.6.0

v0.6.0

What's New
Congestion Control Selection (--congestion)

Choose your TCP congestion control algorithm per-test:

xfr <host> --congestion bbr -   # Compare BBR vs default CUBIC
xfr <host> --congestion reno -  # Classic Reno

Works on both client and server sockets. Invalid algorithms are caught early with a helpful error listing what's available on your kernel.
Live TCP_INFO Polling

RTT and cwnd are now reported every interval during tests, not just in the final result. This enables:

 - Real-time TCP metrics in the TUI
 - Per-interval rtt_us and cwnd in --json-stream and --csv output
 - Useful for -t 0 (infinite) tests where final results are never sent

Resolves #13.
Bug Fixes

 - Congestion errors surfaced - Invalid --congestion now fails immediately (non-zero exit) instead of silently producing a zero-byte result
 - Stale fd cleanup - TCP_INFO file descriptors are cleared on all exit paths, preventing reads from unrelated sockets after fd reuse
 - Update banner double "v" - No longer shows vv0.5.0 in update notifications
 - PSK unwrap panics - Server returns an error instead of panicking on misconfigured PSK
 - UDP encode bounds check - UdpPacketHeader::encode() validates buffer length before writing
 - Timestamp clock skew - ISO8601/Unix timestamps now derived from monotonic elapsed time

Code Quality

 - Replaced 12 hardcoded magic numbers with 6 named constants




v0.5.0
Changed

 - Single-port TCP mode (#16) - TCP tests now use only port 5201 for all connections, making them firewall-friendly. Data connections identify themselves via DataHello message instead of using ephemeral ports.
 - Protocol version bump to 1.1 - Signals DataHello support; adds single_port_tcp capability for backward compatibility detection
 - Client capabilities in Hello - Client now advertises supported capabilities (tcp, udp, quic, multistream, single_port_tcp); server falls back to multi-port TCP for legacy clients without single_port_tcp
 - Numeric version comparison - versions_compatible() now parses major version as integer instead of string comparison

Fixed

 - QUIC IPv6 support (#17) - QUIC clients can now connect to IPv6 addresses without requiring -6 flag; endpoint now binds to matching address family
 - mDNS discovery (#15) - Server now advertises addresses via enable_addr_auto(); client uses non-blocking receive with proper timeout handling
 - TCP RTT and retransmits display (#13) - TUI now shows correct retransmit count from stream results (captured after transfer); TCP_INFO captured after transfer for accurate RTT/cwnd
 - Data connections no longer consume rate-limit/semaphore slots - Only control (Hello) connections acquire permits; DataHello connections route directly without resource consumption
 - Cancel messages processed during TCP stream collection - Interval loop now starts immediately; stream collection runs concurrently in background
 - Client OOB panic on port mismatch - Added bounds check when server returns fewer ports than requested streams
 - DoS guard on oversized lines - read_first_line_unbuffered() now returns error instead of truncating
 - DataHello serialization panic - Replaced unwrap() with proper error handling in spawned task
 - One-off mode deadlock - --one-off no longer blocks the accept loop waiting for test completion; uses shutdown channel to signal exit after test finishes
 - QUIC one-off mode - QUIC accept loop now responds to shutdown signal for proper --one-off exit
 - cancel.changed() busy-loop - Handle sender-dropped error in stream collection select! to prevent CPU spin
 - IPv4-mapped IPv6 comparison - DataHello IP validation now normalizes ::ffff:x.x.x.x addresses for correct matching on dual-stack systems

Security

 - DataHello IP validation - Server validates DataHello connections come from same IP as control connection to prevent connection hijacking
 - Slow-loris protection - Accept loop now spawns per-connection tasks with 5-second initial read timeout; slow clients can no longer block the listener
 - DataHello flood protection - Server validates test_id exists in active_tests before processing DataHello connections; unknown test_ids are dropped immediately
 - Pre-handshake connection gate - Limits concurrent unclassified connections (4x max_concurrent) to prevent connection-flood DoS before Hello/DataHello routing
 - Multi-port TCP fallback IP validation - Per-stream listeners validate connecting peer IP against control connection, preventing unauthorized data stream injection
 - One-off mode hardened - Failed handshakes and auth failures no longer trigger server shutdown in --one-off mode; only successful test completion exits

Testing

 - Added regression test for QUIC IPv6 connectivity
 - Added test_tcp_one_off_multi_stream - verifies 4-stream TCP in --one-off mode with stream count assertion
 - Added test_quic_one_off - verifies 2-stream QUIC in --one-off mode with stream count assertion

Code Quality

 - Log panics from join_all in QUIC, UDP, and TCP stream handlers instead of silently discarding JoinErrors
 - Multi-port fallback listener tasks cleaned up via cancel signal (no leaked tasks on partial connections)
@
text
@d1 1
a1 1
# $NetBSD: Makefile,v 1.1 2026/02/04 13:59:40 wiz Exp $
d3 1
a3 1
DISTNAME=	xfr-0.6.0
d17 2
@


1.1
log
@net/xfr: import xfr-0.3.0

Packaged for wip by pin@@

A fast, modern network bandwidth testing tool with TUI. Built in Rust as an
iperf replacement.

Features:
 - Live TUI with real-time throughput graphs and per-stream stats
 - Server dashboard - xfr serve --tui for monitoring active tests
 - Multi-client server - handle multiple simultaneous tests
 - TCP and UDP with configurable bitrate and parallel streams
 - Bidirectional testing - measure upload and download simultaneously
 - Multiple output formats - plain text, JSON, JSON streaming, CSV
 - Result comparison - xfr diff to detect performance regressions
 - LAN discovery - find xfr servers with mDNS (xfr discover)
 - Prometheus metrics - export stats for monitoring dashboards
 - Config file - save defaults in ~/.config/xfr/config.toml
 - Environment variables - XFR_PORT, XFR_DURATION overrides
@
text
@d1 1
a1 1
# $NetBSD$
d3 1
a3 1
DISTNAME=	xfr-0.3.0
d20 1
a20 1
	${INSTALL_MAN} ${WRKSRC}/doc/xfr.1 \
@

