Skip to main content

irtt_client/
lib.rs

1//! Reusable client/session/event layer for IRTT-compatible probes.
2//!
3//! `irtt-client` opens IRTT-compatible sessions, sends echo probes, receives
4//! replies, classifies loss/late/duplicate packets, and emits [`ClientEvent`]
5//! values for callers to consume directly or aggregate with `irtt-stats`.
6//!
7//! Timing values intentionally preserve signed measurement semantics. When
8//! server timing is available, [`RttSample::effective`] is adjusted for server
9//! processing and can be negative if the reported server processing time exceeds
10//! the raw client-observed RTT. Directional [`OneWayDelaySample`] values are
11//! also signed when the required wall-clock timestamps are available; negative
12//! values usually indicate client/server clock skew.
13//!
14//! A managed session can drive the socket loop on a worker thread and publish
15//! events through a subscription:
16//!
17//! ```no_run
18//! use std::time::Duration;
19//!
20//! use irtt_client::{ClientConfig, ClientEvent, ManagedClient, SubscriberConfig};
21//!
22//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
23//! let config = ClientConfig {
24//!     server_addr: "127.0.0.1:2112".to_owned(),
25//!     duration: Some(Duration::from_secs(10)),
26//!     interval: Duration::from_secs(1),
27//!     ..ClientConfig::default()
28//! };
29//!
30//! let (session, events) =
31//!     ManagedClient::start_with_subscription(config, SubscriberConfig::default())?;
32//!
33//! while let Ok(event) = events.recv() {
34//!     match event {
35//!         ClientEvent::EchoReply { seq, rtt, .. } => {
36//!             println!("seq={seq} effective_rtt_us={}", rtt.effective.as_micros());
37//!         }
38//!         ClientEvent::SessionClosed { .. } => break,
39//!         _ => {}
40//!     }
41//! }
42//!
43//! let _outcome = session.join()?;
44//! # Ok(())
45//! # }
46//! ```
47//!
48#![cfg_attr(
49    not(all(target_os = "linux", feature = "ancillary")),
50    forbid(unsafe_code)
51)]
52#![cfg_attr(all(target_os = "linux", feature = "ancillary"), deny(unsafe_code))]
53
54mod client;
55mod config;
56mod error;
57mod event;
58mod managed;
59mod metadata;
60mod probe;
61mod receive;
62mod session;
63mod socket;
64mod socket_options;
65mod timing;
66
67pub use client::Client;
68pub use config::{
69    ClientConfig, NegotiationPolicy, RecvBudget, RunMode, SocketConfig, MAX_DSCP_CODEPOINT,
70    MAX_SERVER_FILL_BYTES, MAX_TTL, MAX_UDP_PAYLOAD_LENGTH,
71};
72pub use error::{ClientError, EventSubscriptionError};
73pub use event::{
74    ClientEvent, OneWayDelaySample, OpenOutcome, PacketMeta, ReceivedStatsSample, RttSample,
75    ServerTiming, SignedDuration, WarningKind,
76};
77pub use managed::{
78    CancellationToken, EventHub, EventSubscription, ManagedClient, ManagedClientSession,
79    SessionEndReason, SessionOutcome, SubscriberConfig, SubscriberOverflow,
80};
81pub use session::{NegotiatedParams, NegotiationRestriction};
82pub use timing::ClientTimestamp;