pub struct ServerConfig { /* private fields */ }Expand description
Configuration for a ServerCore.
Fields are private and set through consuming builder methods, so later slices can add configuration without breaking construction.
Server fill is deliberately not configurable. The policy is fixed and
safe: every valid descriptor is honored, one that cannot be parsed falls back
to pattern:69727474, and a client expressing no preference is served that
same default. There is no allow-list to configure, because refusing a valid
mode would prevent nothing — the payload carries no protocol meaning, a
descriptor is bounded to 32 wire bytes, a random fill is bounded by
max_packet_length like every other reply, and
none is zero-filled here rather than left as residue. An operator
restriction can be added if a real use case turns up.
§Example
Configure a modest per-listener session budget and restrict timestamp placement while leaving DSCP marking disabled:
use std::time::Duration;
use irtt_server::{ServerConfig, TimestampAllowance};
let config = ServerConfig::default()
.with_max_sessions(128)
.with_idle_timeout(Duration::from_secs(30))
.with_timestamp_allowance(TimestampAllowance::Single)
.with_dscp_allowed(false);
assert_eq!(config.max_sessions(), 128);
assert_eq!(config.idle_timeout(), Duration::from_secs(30));
assert_eq!(config.timestamp_allowance(), TimestampAllowance::Single);
assert!(!config.dscp_allowed());Implementations§
Source§impl ServerConfig
impl ServerConfig
Sourcepub fn with_hmac_key(self, key: impl Into<Vec<u8>>) -> Self
pub fn with_hmac_key(self, key: impl Into<Vec<u8>>) -> Self
Sets the HMAC key, enabling authentication for this server.
Authentication is global: with a key configured, every request must
carry FLAG_HMAC and a valid MAC, and every reply is authenticated.
Without one, any request carrying FLAG_HMAC is dropped.
Sourcepub fn with_max_sessions(self, max_sessions: usize) -> Self
pub fn with_max_sessions(self, max_sessions: usize) -> Self
Sets the maximum number of simultaneously live sessions.
Once the table holds this many sessions, a session-creating open is silently dropped; nothing is evicted. Zero refuses every session-creating open while still answering no-test opens, which create no state. There is deliberately no unbounded setting.
Sourcepub fn with_max_packet_length(self, max_packet_length: usize) -> Self
pub fn with_max_packet_length(self, max_packet_length: usize) -> Self
Sets the maximum echo datagram size a session may negotiate, in bytes.
This governs the executable echo datagram of a session, not the size of the open exchange: a requested positive Length above this value is reduced to it during negotiation, and an open whose mandatory echo field block would not fit is silently refused, since the server could not emit a compliant reply for it. Authentication counts toward that field block. The same limit additionally admits inbound echo request datagrams by their received length, before any receive state moves.
The value is trusted local configuration, like
with_max_sessions: an operator may
deliberately raise it far past what any path carries, and that is their
resource choice to make. What must stay bounded is the default, which
is why there is deliberately no unlimited setting.
Zero is accepted and is not a synonym for unlimited. No session can describe an echo packet smaller than its mandatory field block, so a zero maximum silently refuses every session-creating open — and every no-test open too, since both are validated against the same effective session.
Sourcepub fn with_min_send_interval(self, min_send_interval: Duration) -> Self
pub fn with_min_send_interval(self, min_send_interval: Duration) -> Self
Sets the floor on the send interval a session may negotiate, which is also the cadence its reply allowance replenishes at.
A requested interval below this is raised to it during negotiation, and
an absent Interval — which means the wire default of zero, not an
explicit zero, which is refused — is answered with it. The negotiated
value may still end up below this floor, because the idle-timeout cap
of with_idle_timeout is applied afterwards;
where that happens, the session’s allowance replenishes at the shorter
negotiated interval instead, so this server never enforces a cadence
slower than the one it handed the client.
Duration::ZERO disables both: no interval is raised, and an
otherwise admissible echo never waits for allowance. It does not
disable the burst allowance, which refuses everything when it is zero.
Sourcepub fn with_burst_allowance(self, burst_allowance: u32) -> Self
pub fn with_burst_allowance(self, burst_allowance: u32) -> Self
Sets how many echo requests a session may have answered before its allowance has to replenish.
The allowance is per session, starts full, is spent one unit per served
echo and refills at one unit per
min_send_interval, never above this value.
An echo arriving with no allowance is dropped without a reply and
without advancing any reception statistic.
Zero is accepted and means no allowance at all: every echo is rate-limited, whatever the interval is set to. It is deliberately not a synonym for unlimited.
Sourcepub fn with_idle_timeout(self, idle_timeout: Duration) -> Self
pub fn with_idle_timeout(self, idle_timeout: Duration) -> Self
Sets how long a session may go without a served or rate-limited echo request before it is released.
The deadline runs from the open, not from the first echo, so a session that never carries one still ages out. Release is silent — the protocol defines no expiry notification — and immediate at the deadline.
This additionally caps the negotiated send interval at a quarter of the timeout, so a client sending at the interval it was given cannot idle itself out.
Duration::ZERO is accepted and is not a synonym for “never expire”:
it releases a session the next time expiry is evaluated. There is
deliberately no unbounded setting.
Sourcepub fn with_max_test_duration(self, max_test_duration: Duration) -> Self
pub fn with_max_test_duration(self, max_test_duration: Duration) -> Self
Sets the maximum test duration a session may negotiate.
A requested Duration above this is reduced to it, and a continuous request — an absent Duration, meaning the wire default of zero — is answered with it too, since restricting continuous mode to a finite test is the whole point of configuring a maximum. An explicit zero Duration is refused before negotiation and never reaches this.
Duration::ZERO means no maximum, exactly as
without_max_test_duration does. A
finite maximum of zero could only be honored by negotiating a Duration of
zero, which on the wire means continuous — the opposite of a limit — so
rewriting a client’s finite request into a continuous one is refused
rather than encoded.
Sourcepub fn without_max_test_duration(self) -> Self
pub fn without_max_test_duration(self) -> Self
Removes any configured maximum test duration, which is the default.
A session then negotiates the duration it asked for, including continuous, and no server-initiated close is ever triggered by duration. The session table bound and the idle timeout still apply, so this is not an unbounded setting.
Sourcepub fn with_timestamp_allowance(
self,
timestamp_allowance: TimestampAllowance,
) -> Self
pub fn with_timestamp_allowance( self, timestamp_allowance: TimestampAllowance, ) -> Self
Sets how many timestamps this server is willing to provide.
A requested placement above the allowance is reduced during negotiation, so the open reply is honest about what the session’s echo replies will carry:
| Requested | Dual | Single | None |
|---|---|---|---|
None | None | None | None |
Send | Send | Send | None |
Receive | Receive | Receive | None |
Both | Both | Midpoint | None |
Midpoint | Midpoint | Midpoint | None |
The one substitution is the observed one: under a single-timestamp allowance a request for both instants is answered with the midpoint, not with whichever of the two the server felt like keeping.
The requested Clock is left exactly as it was in
every case. The allowance restricts which instants are reported, and
each reported instant still carries one field per negotiated clock domain
— Single on Clock::Both reports a wall
and a monotonic midpoint. Only None removes timestamp fields
outright, and it does so because the echo layout carries none once the
placement is StampAt::None.
Restriction runs before the effective-session check, which is what
makes a None allowance accept a request that selected timestamps
without sending a Clock: such a session is refused as requested, because
timestamps from no clock cannot be produced, but under this policy its
effective placement is none and the absent clock no longer matters.
Sourcepub fn with_dscp_allowed(self, dscp_allowed: bool) -> Self
pub fn with_dscp_allowed(self, dscp_allowed: bool) -> Self
Sets whether this server provides the traffic-class marking a session requests.
true, the default, negotiates the requested DSCP parameter unchanged —
including a raw value outside 0..=255, which stays in the negotiated
parameters and is transported unmarked.
false negotiates it to zero, whatever was requested, so the reply
tells the client its replies will be unmarked and the session’s stored
parameters say the same. The open is never refused over DSCP, and nothing
is clamped or wrapped: this is an operator policy about providing
traffic-class marking at all, not a judgement about a particular value.
It is also not socket capability detection. What a given host can apply to a socket is a transport concern, settled per send by the runtime.
Sourcepub fn max_sessions(&self) -> usize
pub fn max_sessions(&self) -> usize
The maximum number of simultaneously live sessions.
Sourcepub fn max_packet_length(&self) -> usize
pub fn max_packet_length(&self) -> usize
The maximum echo datagram size a session may negotiate, in bytes.
Sourcepub fn min_send_interval(&self) -> Duration
pub fn min_send_interval(&self) -> Duration
The floor on a negotiated send interval, and the allowance refill cadence.
Sourcepub fn burst_allowance(&self) -> u32
pub fn burst_allowance(&self) -> u32
How many echo requests a session may have answered before its allowance has to replenish.
Sourcepub fn idle_timeout(&self) -> Duration
pub fn idle_timeout(&self) -> Duration
How long a session may go without an echo request before it is released.
Sourcepub fn max_test_duration(&self) -> Option<Duration>
pub fn max_test_duration(&self) -> Option<Duration>
The maximum test duration a session may negotiate, if one is configured.
Never Some(Duration::ZERO): a zero maximum is stored as None, since
a negotiated Duration of zero means continuous rather than instant.
Sourcepub fn timestamp_allowance(&self) -> TimestampAllowance
pub fn timestamp_allowance(&self) -> TimestampAllowance
How many timestamps this server is willing to provide.
Sourcepub fn dscp_allowed(&self) -> bool
pub fn dscp_allowed(&self) -> bool
Whether a requested DSCP value is negotiated as asked, rather than to zero.
Trait Implementations§
Source§impl Clone for ServerConfig
impl Clone for ServerConfig
Source§impl Debug for ServerConfig
impl Debug for ServerConfig
Source§impl Default for ServerConfig
impl Default for ServerConfig
Source§fn default() -> Self
fn default() -> Self
An unauthenticated server bounded to DEFAULT_MAX_SESSIONS sessions,
each negotiating at most DEFAULT_MAX_PACKET_LENGTH bytes per echo,
no faster than DEFAULT_MIN_SEND_INTERVAL with a burst of
DEFAULT_BURST_ALLOWANCE, and released after
DEFAULT_IDLE_TIMEOUT without an echo request.
No maximum test duration is configured, matching the reference server’s ordinary policy. A session is still bounded, by the table size and the idle timeout.
Both capability restrictions are off: every requested timestamp placement
is honored (TimestampAllowance::Dual) and a requested DSCP value is
negotiated as asked. They are opt-in, so an existing configuration
negotiates exactly what it did before they existed.