Struct WssLimits
pub struct WssLimits {
pub max_pending_handshakes: usize,
pub handshake_timeout: Duration,
pub max_sessions: usize,
pub max_sessions_per_client: usize,
pub incomplete_message_timeout: Duration,
}Expand description
Bounds on the WSS listener’s pre-authentication and session state.
The remote WSS plane is the daemon’s mandatory mTLS surface and its default
bind is 0.0.0.0, so every state an unauthenticated peer can reach has to
be bounded in both time and count. Without these, each accepted TCP socket
spawned a task that awaited the TLS handshake and the WebSocket upgrade with
no deadline and no cap, so a peer that merely connected - and never proved
anything - could accumulate sockets, tasks and TLS parser state without
limit. Mirrors the bounds the relay applies to its own admission path.
Fields§
§max_pending_handshakes: usizeCeiling on sockets past accept() that have not finished the TLS
handshake and WebSocket upgrade. When the pool is exhausted new sockets
are dropped at accept rather than queued, so a slowloris spread across
many source addresses sheds instead of accumulating.
handshake_timeout: DurationOne absolute deadline covering TLS accept AND the WebSocket upgrade, measured from accept. It is a single budget for the whole setup sequence, not a fresh window per phase: the heartbeat only starts once a session is established, so without this a peer could stall in either handshake forever.
max_sessions: usizeCeiling on concurrently established WSS sessions. Bounds the steady state that survives authentication, so an authorized-but-abusive peer cannot grow dispatcher and transport state without limit.
max_sessions_per_client: usizeCeiling on concurrent sessions presenting ONE client certificate, keyed by that certificate’s SHA-256 fingerprint.
max_sessions alone is an arithmetic ceiling, not a host-memory budget:
every session may declare a message up to the parser envelope
(rpc_ws_config), so the session ceiling is a memory ceiling, and one
admitted-but-hostile credential (or a stolen one, before it is detected
and revoked) can occupy all of it. This bounds the parser bytes ONE
credential can reserve at max_sessions_per_client x envelope.
incomplete_message_timeout: DurationHow long a partially-received data message may be held by the parser.
The heartbeat proves liveness, not progress: tungstenite yields interleaved control frames while a fragmented message is still incomplete, so a peer can Ping forever while the parser retains the partial buffer. This bounds that hold time.
The deadline is armed by the peer’s own DECLARATION, not by bytes
received. tungstenite reserves a frame’s declared length the moment it
parses that frame’s header, before any payload arrives, so bytes read is
not a proxy for bytes reserved: a 14-byte header can reserve the whole
parser envelope. A frame scanner under the parser (FrameScanner) reads
the same plaintext byte stream and starts this clock at the FIRST byte
of a data frame’s header, so every partial-message reservation is
bounded from the moment it exists. Control frames are inert to it by
construction, and with no data message in progress there is no deadline
at all - an idle connection is the heartbeat’s business.
It is a lifetime bound, not a stall detector - a peer that trickles
bytes is exactly the case a stall detector would miss - so it also
bounds the slowest legitimate upload: a full-size request
(crate::rpc::attachments::MAX_REQUEST_BYTES, 20 MiB) must arrive
within this window (at the 60s default that is a ~341 KiB/s floor;
operators on slower links should raise the window, not disable it).
Trait Implementations§
Auto Trait Implementations§
impl Freeze for WssLimits
impl RefUnwindSafe for WssLimits
impl Send for WssLimits
impl Sync for WssLimits
impl Unpin for WssLimits
impl UnsafeUnpin for WssLimits
impl UnwindSafe for WssLimits
Blanket Implementations§
§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more