Files
irtt-rs/crates/irtt-client
Nils Andreas Svee efa1313e95
Rust CI / cargo fmt (push) Successful in 17s
Rust CI / cargo clippy (push) Successful in 32s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Successful in 23s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Successful in 33s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Successful in 1m6s
Rust CI / cargo doc (push) Successful in 26s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Successful in 1m18s
Fuzz Smoke / cargo fuzz smoke (push) Successful in 1m41s
Netem Interop / netem interop (push) Successful in 1m22s
Supply chain / cargo-deny advisories (push) Successful in 17s
Supply chain / cargo-deny bans licenses sources (push) Successful in 15s
Supply chain / actionlint (push) Failing after 4s
Build binaries / Build (arm-musleabi) (push) Successful in 4m46s
Build binaries / Build (aarch64-musl) (push) Successful in 4m54s
Semver / cargo-semver-checks (push) Successful in 48s
Publish irtt-server image / publish (push) Successful in 1m5s
Build binaries / Build (arm-musleabihf) (push) Successful in 3m54s
Build binaries / Build (armv7-musleabi) (push) Successful in 4m1s
Build binaries / Build (armv7-musleabihf) (push) Successful in 4m1s
Build binaries / Build (i686-musl) (push) Successful in 3m57s
Build binaries / Build (mips-musl) (push) Successful in 3m47s
Build binaries / Build (mips64-muslabi64) (push) Successful in 3m44s
Build binaries / Build (mipsel-musl) (push) Successful in 3m52s
Build binaries / Build (mips64el-muslabi64) (push) Successful in 4m5s
Build binaries / Build (riscv64gc-musl) (push) Successful in 4m17s
Build binaries / Build (x86_64-musl) (push) Successful in 4m20s
chore(release): prepare client 0.7.0, stats 0.6.0 and app 0.10.0
2026-10-27 11:30:08 +07:00
..

irtt-client

Reusable client/session library for IRTT-compatible round-trip-time probing: socket lifecycle, open negotiation, probe send/receive, loss/duplicate/late classification, and a typed event stream.

Looking for the CLI?

If you just want to run probes from the command line, use the irtt-rs application package instead, which installs the irtt-client binary. This crate is the library the binaries are built on.

API tiers

  • Client — runtime-free blocking adapter. No Tokio dependency; this is the default build.
  • AsyncClient (feature tokio) — low-level Tokio adapter for callers that own a runtime and drive readiness directly.
  • managed (feature tokio) — a unified managed driver: ManagedClientTask / ManagedClientHandle for multi-target orchestration under a Tokio runtime, and BlockingManagedClient for synchronous callers, which owns its own dedicated current-thread runtime.

Client and AsyncClient send one probe whenever called. They expose the negotiated parameters, pending-probe status, and timeout deadlines; callers own cadence and run duration. The managed driver provides fixed cadence, missed-slot handling, finite runs, and staggered or burst pacing. Low-level sends return Result<SendReceipt, SendProbeError> instead of event lists. A SendReceipt carries the committed sequence, remote, post-send timestamp, accepted bytes, and send-call duration. NotCommitted(ClientError) guarantees no accepted datagram or committed probe; AfterCommit { receipt, source } preserves the accepted send when subsequent validation or TX processing fails. Use ClientEvent::from(receipt) for an EchoSent event with scheduled_at and timer_error absent; the managed driver supplies those schedule measurements and publishes committed sends even when post-send processing fails.

Managed continuous measurement runs can opt into automatic recovery with ManagedClientConfig.reconnect_timeout: Some(timeout). Initial connection failures, closed/failed sessions, server-limited completion, and reply silence while sending trigger independent per-target retries. reconnect_initial_delay (default 250 ms) doubles to reconnect_max_delay (default 10 s); a valid reply resets the delay. Both delays must be positive and schedulable, with the maximum at least twice the initial delay. Explicit stop and target removal cancel retries. Recovery is disabled by default and is invalid for finite or negotiation-only runs.

In 0.7, complete ManagedClientConfig literals must include the three recovery fields (or use ..Default::default()), and exhaustive ManagedConfigError matches must handle the new recovery-policy variants. A target can emit repeated session-start events within one instance; reset session-bound state, including statistics, for each reopened session. Use irtt-stats 0.6 with client 0.7 events.

Tokio stays optional: the default build has no runtime and no Tokio dependency at all.

See examples/ in the repository for runnable examples of each tier.

Reusable configuration

ClientConfig contains no endpoint. The low-level APIs take it separately: Client::connect(endpoint, config) and AsyncClient::connect(endpoint, config).await, accepting String or &str endpoints. An omitted port defaults to 2112.

Configuration is grouped by ownership:

  • address_family: AddressFamily::{Any, Ipv4, Ipv6}, defaulting to Any. It filters remote resolution; Ipv6 also sets IPV6_V6ONLY.
  • socket: SocketConfig for local bind, device/routing options, and TTL.
  • request: SessionRequest for duration, interval, length, received stats, timestamps, clock, DSCP, server fill, and run mode.
  • open: OpenPolicy for attempt timeouts and negotiation policy.
  • auth, probe_timeout, and max_pending_probes: authentication and local probe tracking policy.

Clone one config to connect to multiple endpoints. Managed targets retain their own ID, endpoint, address-family override, and authentication inheritance/override; shared ManagedClientConfig.client is reusable without endpoint mutation.

ManagedTargetConfig.address_family defaults to None, inheriting the shared family policy. Some(AddressFamily::Ipv4), Some(AddressFamily::Ipv6), or Some(AddressFamily::Any) overrides it for that target. Every new generation resolves the original endpoint again; callers can constrain a hostname without replacing it with a resolved IP. Changing the family specification replaces that target's generation, including switching between inheritance and an equal explicit override. Hostname expansion and discovery are frontend policies.

Blocking receive policy belongs to Client: client.set_recv_timeout(Some(duration))? sets it before or after opening, and client.set_recv_timeout(None)? restores the default indefinite wait. Open attempts use only open.timeouts, restoring the adapter setting afterward. Async and managed clients have no blocking receive-timeout setting.

This breaks the former flat config, endpoint-in-config, socket family flags, and SocketConfig.recv_timeout APIs. Use the grouped fields and adapter method directly; defaults and protocol/runtime behavior are preserved.

Authentication

ClientConfig.auth is concrete: Authentication::Unauthenticated or Authentication::Hmac(HmacKey::new(bytes)). Keys share their bytes across clones and print only HmacKey([REDACTED]) through Debug. Borrowing key material requires an explicit as_bytes() call. An empty key still selects HMAC authentication; textual key syntax belongs to the application.

For managed targets, ManagedTargetConfig.auth defaults to TargetAuth::Inherit. TargetAuth::Override(Authentication::Unauthenticated) disables shared authentication, and TargetAuth::Override(Authentication::Hmac(key)) replaces the shared key. Initial construction and update planning resolve inheritance into concrete session authentication before execution. Switching between inheritance and an override replaces the target generation even when their resolved authentication is equal.

This replaces the former ClientConfig.hmac_key and ClientAuthConfig API; there are no compatibility aliases.

Documentation

Full API documentation is on docs.rs/irtt-client.

Project

Part of irtt-rs, an independent Rust implementation of an IRTT-compatible protocol stack.