Skip to main content

ServerConfig

Struct ServerConfig 

Source
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

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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:

RequestedDualSingleNone
NoneNoneNoneNone
SendSendSendNone
ReceiveReceiveReceiveNone
BothBothMidpointNone
MidpointMidpointMidpointNone

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.

Source

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.

Source

pub fn hmac_key(&self) -> Option<&[u8]>

The configured HMAC key, if this server authenticates.

Source

pub fn max_sessions(&self) -> usize

The maximum number of simultaneously live sessions.

Source

pub fn max_packet_length(&self) -> usize

The maximum echo datagram size a session may negotiate, in bytes.

Source

pub fn min_send_interval(&self) -> Duration

The floor on a negotiated send interval, and the allowance refill cadence.

Source

pub fn burst_allowance(&self) -> u32

How many echo requests a session may have answered before its allowance has to replenish.

Source

pub fn idle_timeout(&self) -> Duration

How long a session may go without an echo request before it is released.

Source

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.

Source

pub fn timestamp_allowance(&self) -> TimestampAllowance

How many timestamps this server is willing to provide.

Source

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

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ServerConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for ServerConfig

Source§

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.

Source§

impl Eq for ServerConfig

Source§

impl PartialEq for ServerConfig

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for ServerConfig

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.