Release the session a client close names. A close is bound to a session only when the token matches and the datagram arrived from that session's exact endpoint, so holding a token is not by itself authority to tear the session down: a close from a foreign source port, address, family or IPv6 scope leaves the session live, and one close cannot take down a sibling session the same peer opened separately. A token that is unknown, already closed or zero matches nothing and leaves the table untouched; zero is reserved for no-test replies and never issued. Nothing is sent either way. Protocol version 1 defines no acknowledgement for a client close, so a successful close returns the same `Ok(None)` as a rejected one and a delivered close is indistinguishable to the client from a lost one. A standalone `Reply|Close` datagram is tolerated by clients but has no demonstrated use, so none is encoded. Authentication still runs before the session is looked up. That keeps a bad MAC on a live token indistinguishable from an unknown token, and means a close that fails authentication — missing, wrongly keyed, corrupted, or unexpected on a server with no key — cannot remove a session. Trailing bytes after the token stay acceptable: the structural decoder already tolerates them and the server does not re-parse the request. The session table remains the only record of how full the server is, so a close frees capacity immediately and a refused open can succeed once one is released. Close draws no token and touches no other state; the endpoint lookup borrows the table only until the comparison is made, so the removal needs no clone. Echo remains ignored. The test that pinned close as a no-op is replaced by `tests/close.rs`, which covers removal, silence, repeated close, echo after close, endpoint binding, unknown/zero/stale tokens, authentication failure, trailing bytes, sibling sessions and capacity reuse; `unsupported.rs` keeps echo and structurally invalid traffic.
53 lines
1.9 KiB
Rust
53 lines
1.9 KiB
Rust
//! 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,
|
|
//! resource decisions and reply construction. It performs no I/O. Socket and
|
|
//! runtime orchestration — the UDP listener, address handling, timers, expiry
|
|
//! and shutdown — will live around it and is intentionally Tokio-native. There
|
|
//! is no blocking or alternate-runtime counterpart and no transport
|
|
//! abstraction.
|
|
//!
|
|
//! # 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`]). A single
|
|
//! unauthenticated datagram creates a session and opens are never deduplicated,
|
|
//! so an unbounded table is a liability rather than a compatibility feature.
|
|
//! Upstream's observed lack of session bounds is explicitly not a compatibility
|
|
//! target.
|
|
//!
|
|
//! # Current scope
|
|
//!
|
|
//! Open handling, session creation and client-initiated close. Echo
|
|
//! processing, server-initiated close, session lifetime and expiry, and the
|
|
//! Tokio runtime are separate slices; a structurally valid echo request is
|
|
//! currently accepted by the admission boundary and then ignored.
|
|
#![forbid(unsafe_code)]
|
|
|
|
mod config;
|
|
mod core;
|
|
mod error;
|
|
mod negotiate;
|
|
mod session;
|
|
mod token;
|
|
|
|
#[cfg(test)]
|
|
mod tests;
|
|
|
|
pub use config::{ServerConfig, DEFAULT_MAX_SESSIONS};
|
|
pub use core::ServerCore;
|
|
pub use error::ServerError;
|