1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! IRTT-compatible server behavior.
//!
//! This crate shares wire semantics with the client through `irtt-proto` and
//! does not depend on `irtt-client`.
//!
//! # Structure
//!
//! [`ServerCore`] is the deterministic protocol and session engine: packet
//! admission, authentication policy, open negotiation, the session table, echo
//! receive state, rate and lifetime policy, resource decisions and reply
//! construction. It performs no I/O; the clock its timestamps and deadlines
//! come from is a private injected seam, not a runtime abstraction, so the
//! engine stays testable. Each reply it produces is an [`OutboundDatagram`]:
//! the packet and the raw traffic class it must be sent with. [`Server`] owns
//! one Tokio UDP listener and one core, and provides sequential receive, reply,
//! scheduled expiry maintenance and caller-controlled shutdown. [`ServerSet`]
//! owns one or more `Server`s as a single service: it binds them all or none,
//! runs each in its own task, fans one shutdown out to them and fails the group
//! if any listener does. The crate is intentionally Tokio-native; there is no
//! blocking or alternate-runtime counterpart and no transport abstraction.
//!
//! # One listener or several
//!
//! `Server` is the primitive and stays directly usable. `ServerSet` is the
//! service around it, and a set of one is an ordinary set rather than a special
//! case — the server CLI runs every invocation, single-bind included, through
//! one.
//!
//! Listeners in a set share nothing but the configuration they were cloned
//! from. Each has its own socket, core, session table and tokens, so a token
//! issued by one is unknown at the others, and every bound in
//! [`ServerConfig`] — `max_sessions` included — applies **per listener**, not
//! per process.
//!
//! # Rejection is silence
//!
//! The protocol defines no error reply, no reset and no NACK. Malformed,
//! unauthenticated and policy-refused datagrams are discarded without a
//! response and without disturbing any live session, and a client tells
//! "rejected" from "lost" only by timing out. [`ServerError`] is therefore
//! reserved for internal failures on the server's own side.
//!
//! # Resource policy
//!
//! Total session state is bounded (see [`DEFAULT_MAX_SESSIONS`]), and so is the
//! echo datagram a single session can negotiate (see
//! [`DEFAULT_MAX_PACKET_LENGTH`]), the rate one session is answered at (see
//! [`DEFAULT_MIN_SEND_INTERVAL`] and [`DEFAULT_BURST_ALLOWANCE`]) and how long
//! one lives without traffic (see [`DEFAULT_IDLE_TIMEOUT`]). A single
//! unauthenticated datagram creates a session and opens are never deduplicated,
//! so neither an unbounded table nor a remotely chosen buffer size is a
//! compatibility feature. Upstream's observed lack of session bounds, its
//! unlimited default packet length, and its never expiring a session that has
//! not carried an echo request are explicitly not compatibility targets: an
//! `irtt-rs` session ages from the moment it is opened.
//!
//! # Reply source address
//!
//! A reply leaves from the address its request was sent to. An
//! explicit-address listener gets that from the bind and uses ordinary
//! receive/send. A wildcard listener (`0.0.0.0` or `[::]`) instead reads each
//! request's local destination from packet metadata and sends that request's
//! reply from it, so a client on the host's second address is answered from the
//! endpoint it contacted rather than from whichever one the routing table would
//! have chosen.
//!
//! That path is implemented for Linux, macOS and FreeBSD. On other targets a
//! wildcard bind is refused by [`Server::from_socket`] — and so by
//! [`Server::bind`] — rather than served incorrectly; explicit-address
//! listeners work everywhere they did before.
//!
//! # Current scope
//!
//! Open handling and negotiation, session creation, normal echo processing,
//! per-session rate limiting, idle expiry, the maximum-duration
//! server-initiated close, the negotiated per-session reply traffic class,
//! server fill, the optional timestamp-allowance and DSCP capability
//! restrictions, wildcard reply-source selection, Tokio UDP orchestration and
//! multi-listener supervision through [`ServerSet`].
//!
//! # Capability restrictions
//!
//! Two optional negotiation policies restrict what a session may ask this server
//! to provide, and both are off by default, so a configuration that sets neither
//! negotiates exactly what it always did.
//!
//! [`TimestampAllowance`] reduces the requested timestamp placement: `Single`
//! provides at most one timestamp instant, answering a request for both instants
//! with the midpoint, and `None` provides no timestamps at all. The requested
//! clock is never rewritten, so a single placement still reports one field per
//! negotiated clock domain. [`ServerConfig::with_dscp_allowed`] refuses to provide
//! traffic-class marking, negotiating any requested DSCP value to zero, after
//! which the session's replies leave unmarked like any other zero-DSCP session.
//!
//! # Server fill
//!
//! An echo reply's payload region is filled from the session's negotiated
//! ServerFill descriptor: `none`, `rand`, or `pattern:` followed by a repeating
//! hexadecimal pattern. Every valid descriptor is accepted — there is no
//! allow-list to configure — and one this server cannot parse is answered with
//! its default, `pattern:69727474`, which is also what a client expressing no
//! preference is served without any change to the negotiated parameters.
//!
//! A `none` payload is zeroes. Payload bytes carry no protocol meaning, and a
//! server must never emit residue from another request or client. Request
//! payload bytes never reach a reply under any mode.
pub use ;
pub use ;
pub use ServerError;
pub use ;
pub use ;