Commit Graph
109 Commits
Author SHA1 Message Date
Nils Andreas Svee e7de8bdb30 refactor(client): split managed task into coherent internal modules
Group control and construction, target lifecycle, target-set transactions,
send pacing and commitment, and bounded timeout processing into private
children of the existing task owner. Keep durable status, outcome history,
top-level polling, sealing, and abandonment in task.rs.

Preserve phase-owned resources, stop/update synchronization, publication
ordering, pacing, and timeout fairness. Move the existing private gate and
timeout tests with their implementation without adding coverage or hooks.
2026-10-05 00:24:15 +07:00
Nils Andreas Svee bc9ea0fe99 fix(client): baseline status subscriptions at the current snapshot 2026-10-04 23:51:19 +07:00
Nils Andreas Svee 2a2dd47e38 refactor(client): make task phases and durable status authoritative 2026-10-04 23:17:38 +07:00
Nils Andreas Svee 2cd8a7d60d refactor(client): make terminal target outcomes authoritative 2026-10-04 21:48:20 +07:00
Nils Andreas Svee 6ebecaec85 refactor(client): make managed target phases own runtime resources 2026-10-04 21:23:57 +07:00
Nils Andreas Svee a6ba335302 feat(client): expose probe send commitment through typed receipts 2026-10-04 19:14:06 +07:00
Nils Andreas Svee d467211f41 refactor(client): separate accepted negotiation state from peer evidence 2026-10-04 18:19:28 +07:00
Nils Andreas Svee 20960e1b8d refactor(client): make configuration reusable across endpoints 2026-10-04 17:30:18 +07:00
Nils Andreas Svee 156db4c720 refactor(client): make authentication explicit and redact HMAC keys 2026-10-04 16:58:44 +07:00
Nils Andreas Svee 798efaf360 fix(client): wake finite managed schedules under backpressure
Expose the negotiated schedule end only while the schedule is unfinished,
and include it among Active targets' non-send deadlines. This keeps finite
expiry independent of socket writability and of Burst/Staggered pacing.
Staggered release gating continues to apply only to send opportunities.

The existing expiry path marks the schedule finished, removing its lifetime
deadline before pending probes continue draining. No new state, readiness
handling, cadence, or drain/close policy is introduced. Continuous schedules
have no lifetime deadline.

The prior public-API Linux namespace/veth/TBF investigation observed genuine
EAGAIN with Burst pacing, 500 ms duration, 1 ms interval, 1400-byte probes,
and 20 ms probe timeout. Polling stopped around 327 ms after pending probes
disappeared, remained stalled beyond 1.5 s, and resumed on queue release.
Staggered applicability follows from the shared deadline selection; it was
not separately reproduced under TBF.

Retain two deterministic owning-layer tests for schedule deadline lifetime
and managed selection under send_waiting and stagger gating, using ordinary
Instant values and a production socket. Keep the privileged networking
harness as investigation evidence rather than adding bespoke test machinery.

Validation: formatting; focused schedule/managed tests; managed lifecycle,
behavior, and blocking-owner integration tests; workspace all-feature check,
all-target tests, doctests, and strict Clippy; client no-default-features
check/tests/strict Clippy and Tokio-free normal dependency tree; Linux
all-feature client and integration suites, including ancillary transport.
2026-10-04 15:41:06 +07:00
Nils Andreas Svee ccdf4ea39c test(client): simplify staggered deadline regression 2026-10-04 11:55:04 +07:00
Nils Andreas Svee 1d211c81ad fix(client): avoid staggered wakes without a send deadline 2026-10-04 11:37:30 +07:00
Nils Andreas Svee 48a50d7f3a tests: rework the actually useful tests to live in the integration crate
Rust CI / cargo fmt (push) Successful in 17s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Successful in 34s
Rust CI / cargo clippy (push) Successful in 35s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Failing after 8s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Failing after 10s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Successful in 1m14s
Rust CI / cargo doc (push) Successful in 23s
Fuzz Smoke / cargo fuzz smoke (push) Failing after 29s
Supply chain / cargo-deny advisories (push) Successful in 9s
Supply chain / cargo-deny bans licenses sources (push) Successful in 5s
Supply chain / actionlint (push) Successful in 3s
Netem Interop / netem interop (push) Successful in 1m11s
2026-10-03 13:59:38 +07:00
Nils Andreas Svee 74e7532965 tests: clean up more tests across the project
Rust CI / cargo fmt (push) Successful in 17s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Successful in 33s
Rust CI / cargo clippy (push) Successful in 34s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Failing after 33s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Failing after 9s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Failing after 8s
Rust CI / cargo doc (push) Successful in 22s
Fuzz Smoke / cargo fuzz smoke (push) Failing after 27s
Supply chain / cargo-deny advisories (push) Successful in 7s
Supply chain / cargo-deny bans licenses sources (push) Successful in 6s
Supply chain / actionlint (push) Successful in 3s
Netem Interop / netem interop (push) Successful in 1m3s
2026-10-02 12:47:27 +07:00
Nils Andreas Svee dc5b19059e tests(client): cleanup unnecessary tests and hooks
Rust CI / cargo fmt (push) Successful in 14s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Successful in 32s
Rust CI / cargo clippy (push) Successful in 34s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Failing after 34s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Failing after 7s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Failing after 10s
Rust CI / cargo doc (push) Successful in 26s
Fuzz Smoke / cargo fuzz smoke (push) Failing after 32s
Supply chain / cargo-deny advisories (push) Successful in 6s
Supply chain / cargo-deny bans licenses sources (push) Successful in 5s
Supply chain / actionlint (push) Successful in 2s
Netem Interop / netem interop (push) Successful in 1m3s
2026-10-02 08:33:49 +07:00
Nils Andreas Svee f2fce2f330 refactor(irtt-client): move cadence into managed runner 2026-10-02 00:31:17 +07:00
Nils Andreas Svee 0d69255e9e docs(client): add executable API examples 2026-09-24 16:51:03 +07:00
Nils Andreas Svee c426884fd1 fix(client): prevent stagger gate from accumulating wakeup latency 2026-09-14 15:33:56 +07:00
Nils Andreas Svee 9f6ef340f9 docs(managed): fix broken intra-doc link for BlockingManagedClient
Rust CI / cargo fmt (push) Successful in 35s
Rust CI / cargo clippy (push) Successful in 55s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Successful in 50s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Successful in 1m43s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Successful in 59s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Successful in 1m49s
Rust CI / cargo doc (push) Successful in 47s
Proto Fuzz Smoke / cargo fuzz smoke (push) Successful in 2m5s
Supply chain / cargo-deny advisories (push) Canceled after 0s
Supply chain / cargo-deny bans licenses sources (push) Canceled after 0s
Supply chain / actionlint (push) Canceled after 0s
Netem Interop / netem interop (push) Successful in 1m33s
Update the link path to use a crate-relative reference, ensuring the documentation resolves correctly for users.
2026-09-01 12:02:01 +07:00
Nils Andreas Svee 1ba4f61072 feat(app): add stdin-managed client target sets 2026-09-01 01:50:56 +07:00
Nils Andreas Svee 31fd76f78d feat(client): await managed updates from blocking callers 2026-09-01 01:49:59 +07:00
Nils Andreas Svee a0b51032f2 docs: document update_targets() replacement semantics
ManagedClientHandle::update_targets() had a one-line rustdoc that
didn't say targets is a full desired-set replacement, that an
unchanged live target continues undisturbed, or that a changed
config or a terminal-generation resubmission starts a fresh
generation even for byte-identical config.
2026-08-20 14:56:56 +07:00
Nils Andreas Svee 1d799c4ca0 fix(managed): restart resubmitted terminal targets 2026-08-15 22:50:19 +07:00
Nils Andreas Svee a3896376da fix(client): timestamp probes after successful send
Moves the client userspace probe sent_at measurement to immediately
after a successful UDP send, improving raw RTT and the userspace
upstream-OWD fallback by excluding the socket send-call interval and
the small amount of local work preceding it.

All fallible probe-commit preflight (timeout deadline checked_add,
capacity/collision checks) still runs before the send, from a private
pre-send anchor (SessionMachine::finalize_probe_commit). The public
sent_at is now supplied afterward to an infallible
SessionMachine::commit_probe_sent, so DurationOverflow still guarantees
nothing was transmitted and a WouldBlock try_send still commits
nothing.

The operational probe timeout deadline stays anchored to the pre-send
timestamp on purpose, not to the new post-send sent_at, preserving
existing timeout/loss timing. Linux kernel TX_SOFTWARE plausibility
keeps its own pre-send wall-clock lower bound
(PendingProbe::tx_not_before_wall) instead of the post-send sent_at,
since a legitimate TX_SOFTWARE timestamp can be generated while the
send syscall is still in flight and would otherwise be wrongly
rejected.

Also flags (without touching production code) that irtt-stats'
ReplySample::from_reply_parts feeds the public sent_at directly into
IpdvSample.client_send_mono/client_send_wall_ns, so the upstream/send
IPDV component naturally shifts along with the sent_at semantics
change; per scope this is reported rather than compensated for.
2026-08-15 19:26:57 +07:00
Nils Andreas Svee 9e3477e617 feat(client): capture kernel transmit timestamps
On Linux, best-effort upgrade the socket's SO_TIMESTAMPING flags to
TX_SOFTWARE | OPT_ID | OPT_TSONLY after a successful Open and before the
first Echo probe. Promote the #103 error-queue foundation to production:
MSG_ERRQUEUE is drained opportunistically with a fixed per-call budget at
several natural choke points (after a probe send, before processing a
reply, before evaluating timeouts), and each automatic OPT_ID timestamp is
correlated directly with wire_seq — safe because Linux rolls back its
speculative sk_tskey increment on every send failure, wire_seq and the
kernel counter start together at every Open, and a socket can never be
reopened for a second session. The observed kernel TX wall timestamp is
retained on PendingProbe (surviving pending -> timed-out retention) as
dormant metadata only; RTT, OWD, and IPDV are unchanged and continue to use
the userspace send timestamp exclusively. Capability failure is fully
non-fatal and RX timestamping is unaffected either way. Non-Linux and
non-ancillary builds are unchanged.
2026-08-15 15:58:48 +07:00
Nils Andreas Svee 0c3acce36a Merge pull request #95 from Lochnair/refactor/managed-target-locality
refactor(client): centralize managed target accounting
2026-08-15 10:06:18 +07:00
Nils Andreas Svee dd68608d56 refactor(client): correct late-reply docs and drop private counter tests
The counter tests instantiated the private TargetCounters and mirrored its
match arms, duplicating outcome-level coverage that already asserts
replies_received and late through ManagedTargetOutcome, and coupling a
private refactor to persistent test churn.

The new counter documentation also defined late replies in timeout-only
terms. A reply that arrives behind an already-received sequence is
classified late by process_echo_reply even when its own probe has not timed
out, so both counters are now described in terms of order and timeout.
2026-08-15 01:49:25 +07:00
Nils Andreas Svee 665f839333 test(client): drop the coverage-only classification enumeration
The removed test only checked that every failure kind appeared somewhere in
the same hand-maintained case table the mapping test already walks. It could
not prove exhaustiveness or the absence of a fallback, which the compiler
enforces, and it pinned the incidental fact that each category currently has
an input.
2026-08-15 01:49:22 +07:00
Nils Andreas Svee 5506220f67 refactor(client): centralize managed target accounting
Target-local accounting was spread across the managed driver: the event
counter increments were inline in publish_client_events, the authoritative
packets_sent was copied from the client at fifteen separate call sites, and
ManagedTargetOutcome was constructed twice from the same six fields.

TargetCounters::observe now owns the per-event accounting,
TargetRuntime::sync_packets_sent/record_packets_sent own the authoritative
sent count, and TargetRuntime::outcome owns outcome construction, replacing
the free target_outcome function and the inline copy in finish_target. No
counter is touched outside TargetRuntime any more.

The replies_received semantics are unchanged and now documented on both the
private counter and the public outcome field: on-time unique echo replies
only, with late unique replies counted by late. observe matches ClientEvent
exhaustively, so a new event variant must be classified deliberately.
2026-08-15 01:36:04 +07:00
Nils Andreas Svee e3003c348f refactor(client): make managed failure classification exhaustive
classify_client_error now matches every ClientError variant explicitly, so a
new variant fails to compile here until its real classification is chosen.
NoTokioRuntime classifies as InvalidState and DatagramLengthMismatch as
Socket; ManagedTargetFailureKind::Other survives only as a deliberate
category with no default path into it.

ManagedTargetFailurePhase and ManagedTargetFailureKind gain controlled
Display impls, and the CLI client/TUI failure diagnostics use them instead
of leaking Debug enum spelling into user-facing text.
2026-08-15 01:03:35 +07:00
Nils Andreas Svee 5a4272e7fd refactor(proto): unify request codecs
Replace the three per-kind request encoders and decoders with one
directional pair, ahead of introducing irtt-server.

Sender side: encode_request(RequestToEncode, hmac_key) constructs OPEN,
CLOSE and ECHO requests from borrowed values. Params and the ECHO payload
are borrowed rather than owned, removing a Params clone and a payload Vec
from the client's hot paths. Wire output is byte-identical; all captured
vectors still pass unchanged.

Receiver side: decode_request(packet) structurally classifies an inbound
request with no HMAC key, no negotiated Params, no session state and no
allocation. A server must extract a token before it knows which key
applies, so authentication is a separate step. Classification follows the
verified server spec: reserved bits and FLAG_REPLY are rejected, OPEN
takes precedence over CLOSE and over an echo-shaped body, and only the
structural minimums (4/12/16, plus 16 with FLAG_HMAC) are enforced.
Trailing bytes are tolerated, no negotiated length ceiling is applied, and
a zero token is structurally valid. OPEN parameters stay encoded bytes so
an authenticating receiver can verify before decoding untrusted data, and
everything after an ECHO sequence number is exposed as an opaque tail.

Add verify_packet_hmac(key, packet), which locates the standard field
itself and rejects a packet lacking FLAG_HMAC. hmac_present reports packet
layout, never authentication. The offset-based verify_hmac stays public as
the low-level primitive for hand-built and captured wire vectors, matching
the existing compute_hmac pair.

Refactor the private envelope into structural header decoding, codec flag
rules, HMAC presence policy and verification as separate steps. The reply
codecs compose the same steps in the same order, so decode_open_reply and
decode_echo_reply keep their exact error ordering and the client's
fatal-versus-ignore classification is unchanged. Reply decoding stays
state-specific: the client already knows which reply to expect, and the
two need different semantic context.

Migrate the production client and every fake peer to the new API; the
fake peers now admit requests the way a server does, instead of parsing
packets by hand.
2026-08-11 23:22:20 +07:00
Nils Andreas Svee f0f9277469 test: trim redundant coverage 2026-08-10 21:06:49 +07:00
Nils Andreas Svee 1f69c04274 test(managed): verify sparse timeout backlog progress 2026-08-10 10:30:36 +07:00
Nils Andreas Svee edb634146c fix(managed): retain timeout backlog fairness 2026-08-10 10:25:10 +07:00
Nils Andreas Svee ab9912b3d5 test(managed): cover timeout backlog scheduling 2026-08-10 02:06:41 +07:00
Nils Andreas Svee ec7baebe3a fix(managed): bound timeout discovery 2026-08-10 01:59:13 +07:00
Nils Andreas Svee f65998ff70 refactor(client): make deadline indexing allocation-free 2026-08-10 01:56:49 +07:00
Nils Andreas Svee 4632e310d7 test(managed): verify timeout budget fairness 2026-08-10 01:18:38 +07:00
Nils Andreas Svee a67331a297 fix(managed): bound timeout work per poll 2026-08-10 01:05:41 +07:00
Nils Andreas Svee 8d47dc9c6e test(managed): cover stopping admission overlap 2026-08-10 00:27:18 +07:00
Nils Andreas Svee dd396a8b5a test(managed): verify bounded control progress 2026-08-10 00:06:31 +07:00
Nils Andreas Svee dd1182d24d fix(managed): harden control admission 2026-08-10 00:05:48 +07:00
Nils Andreas Svee c599c84715 refactor(managed): remove legacy runtime 2026-08-09 20:58:36 +07:00
Nils Andreas Svee 9de95b303c feat(managed): support subscribed blocking start 2026-08-09 20:21:12 +07:00
Nils Andreas Svee 93fed6dce6 fix(managed): bound blocking runtime shutdown 2026-08-09 20:02:35 +07:00
Nils Andreas Svee 749306394c test(managed): verify blocking owner lifecycle 2026-08-09 19:18:38 +07:00
Nils Andreas Svee 03ee6e2f28 feat(managed): add blocking managed owner 2026-08-09 19:10:56 +07:00
Nils Andreas Svee de902722e7 test(managed): verify dynamic target generations 2026-08-09 18:52:16 +07:00
Nils Andreas Svee 89ec57d48c feat(managed): add transactional target updates 2026-08-09 18:51:46 +07:00
Nils Andreas Svee 99b6ddfead fix(managed): preserve drain and pacing invariants 2026-08-05 00:09:46 +07:00