Skip to main content

Session

Struct Session 

Source
pub struct Session { /* private fields */ }
Expand description

Session - virtual association between two endpoints

Implementations§

Source§

impl Session

Source

pub fn new( session_id: SessionId, shared_secret: &[u8; 32], peer_side: bool, ) -> Result<Self, CoreError>

Create a new session with given shared secret

Source

pub fn from_derived( session_id: SessionId, crypto: CryptoState, scheduler_mode: SchedulerMode, traffic_secret: [u8; 32], is_server: bool, ) -> Self

Create session from a pre-derived crypto state (e.g., after handshake).

traffic_secret is the master from which the supplied crypto was derived — it seeds the rekey HKDF chain. is_server records which side of the handshake we are; rekey re-derives keys with the same side so per-direction layout is preserved.

Source

pub fn resume( session_id: SessionId, resumption_secret: &[u8; 32], peer_side: bool, ) -> Result<Self, CoreError>

Resume a session using resumption secret (0-RTT)

Source

pub fn id(&self) -> &SessionId

Get session ID

Source

pub fn state(&self) -> SessionState

Get current state

Source

pub fn set_state(&self, new_state: SessionState)

Transition to a new state

Source

pub fn open_stream(&self) -> Arc<Stream>

Open a new stream

Source

pub fn get_stream(&self, stream_id: StreamId) -> Option<Arc<Stream>>

Get an existing stream

Source

pub fn close_stream(&self, stream_id: StreamId) -> bool

Close a stream

Source

pub fn stream_count(&self) -> u32

Get number of active streams

Source

pub fn replay_rejected_total(&self) -> u64

Total number of replayed packets rejected by the sliding-window check across all streams in this session. Intended for the replay_rejected_total metric.

Source

pub fn current_epoch(&self) -> u8

Current rekey generation (Phase 1.5). Starts at 0; each successful rekey increments by one. Carried on the wire in PacketHeader.epoch so the peer can match the right derived key.

Source

pub fn is_server(&self) -> bool

Whether this session is acting as the server side. Determined at construction; required for re-deriving per-direction keys on rekey.

Source

pub fn rekey(&self) -> Result<u8, CoreError>

Mid-session key rotation (Phase 1.5).

Derives the next traffic secret from the current one via HKDF-Expand(current, "phantom-rekey-v1", 32) and builds a fresh CryptoState under that secret. The new state is installed via an atomic ArcSwap::store, so concurrent encrypt/decrypt calls observe either the old or the new state — never a partially-written in-between. The previous traffic secret is explicitly zeroed before being overwritten.

Returns the new epoch (1, 2, 3, …). Wraps an error if the epoch counter has saturated u8::MAX (after 255 successful rekeys — equivalent to ~5 days at the default 30-minute cadence; long-lived sessions are expected to reconnect rather than wrap).

Wire signalling: callers that want the peer to follow this rekey emit a V2 packet whose header carries the new epoch (and optionally the PacketFlags::REKEY flag). Receivers respond by calling rekey() themselves once they see the bump — keeping both ends in lockstep.

Source

pub fn send_invocations(&self) -> u64

Send-side AEAD invocation count for the current epoch (resets to 0 on each rekey). Drives send_needs_rekey.

Source

pub fn rekey_threshold(&self) -> u64

The send-invocation high-watermark at which the pump auto-rekeys.

Source

pub fn set_rekey_threshold(&self, n: u64)

Override the auto-rekey high-watermark (default REKEY_SOFT_LIMIT). Clamped to >= 1. Rust-only — primarily for tests/soak harnesses that need to exercise mid-session rekey without sending 2^47 packets.

Source

pub fn set_seq_rekey_watermark(&self, n: u32)

Override the per-stream sequence rekey watermark (default SEQ_REKEY_WATERMARK, 2^31). Clamped to >= 1. Rust-only — primarily for tests/soak harnesses that need to exercise the per-stream forced rekey (C1) without driving a single stream through 2^31 sequence numbers.

Source

pub fn stream_seq_needs_rekey(&self, stream_id: StreamId, seq: u32) -> bool

True once stream_id’s sequence has advanced past the per-stream watermark within the current epoch (C1). The send path checks this before stamping each packet and, when set, forces a rekey so a per-stream u32 sequence can never wrap within one epoch — which would otherwise repeat the AEAD nonce (epoch, stream_id, sequence, path_id) under a fixed key (Invariant 8).

The per-stream (epoch, base) checkpoint is rebased lazily on the first call after an epoch change, so the measured span is always relative to where the stream entered the current epoch.

Source

pub fn send_needs_rekey(&self) -> bool

True once the send direction has crossed the rekey high-watermark and the epoch has room to advance. The data pump checks this before each application send and, when set, rekeys + flags the packet REKEY so the peer follows via the authenticated epoch bump.

Source

pub fn decrypt_packet_accepting_rekey( &self, header: &PacketHeader, ciphertext: &[u8], ) -> Result<Vec<u8>, CoreError>

Decrypt a packet, transparently following an authenticated forward rekey of up to MAX_REKEY_CATCHUP epochs (C1).

  • header.epoch == current: ordinary decrypt_packet.
  • current < header.epoch <= current + MAX_REKEY_CATCHUP: derive the candidate key that many epochs ahead and trial-decrypt. Only on AEAD success — i.e. once the epoch bump is proven authentic — is the rekey committed and the replay window consulted (Invariant 4 ordering preserved). A forged header.epoch fails the AEAD open, nothing is committed, and the session does not desync. The bound caps an attacker to at most MAX_REKEY_CATCHUP HKDF steps per spoofed packet.
  • anything else (behind current, more than MAX_REKEY_CATCHUP ahead, or epoch saturated): rejected. Over a reliable transport the sender retransmits at the then-current epoch, so no data is lost.
Source

pub fn ratchet_to_epoch(&self, target: u8) -> Result<(), CoreError>

Advance to a specific target epoch by repeatedly applying the rekey HKDF chain. Used by the receive path to “catch up” when it sees a packet from a higher epoch than the locally known one. Refuses to go backwards (a lower target than current returns Ok without changes).

Source

pub fn validated_paths(&self) -> Vec<u8>

Snapshot of currently Validated path ids. Useful for the scheduler when picking an outbound path.

Source

pub fn path_state(&self, path_id: u8) -> Option<PathStateKind>

State of a specific path within this session. Returns None for path ids the session has never observed.

Source

pub fn begin_path_validation(&self, path_id: u8) -> Option<[u8; 32]>

Register a new path id and immediately issue a 32-byte PATH_CHALLENGE for it. Returns the challenge bytes; the caller must transmit them in a V2 packet with PacketFlags::PATH_VALIDATION set on the new path. Subsequent calls on an already-Validating path re-issue a fresh challenge.

Returns None if the path is in a terminal state (Validated or Failed).

Source

pub fn complete_path_validation(&self, path_id: u8, response: &[u8]) -> bool

Verify a peer’s PATH_VALIDATION response. Returns true if the response matches the in-flight challenge (path is now Validated). Returns false otherwise — the path may have transitioned to Failed.

Source

pub fn mark_path_seen(&self, path_id: u8)

Record that a packet was observed on the path. Cheap to call per-packet — used by the data pump to keep last_packet_seen fresh for the timeout sweep.

Source

pub fn pacer(&self) -> Arc<Pacer>

Shared handle to this session’s outbound rate-limiter. Cheap to clone (Arc). The data pump consults this before every outbound packet; idle by default (Pacer::unlimited).

Source

pub fn on_packet_sent(&self, bytes: u64)

Record that a packet of bytes length is going on the wire. Feeds the BBR-style bandwidth estimator. Cheap (one mutex lock

  • a counter increment).
Source

pub fn on_packet_acked(&self, sample: DeliverySample) -> u64

Record that an ACK arrived with delivery sample sample. The returned u64 is the updated bottleneck bandwidth estimate; we reflect it into the pacer so the outbound rate tracks the peer’s actual receive throughput.

Source

pub fn on_packet_lost(&self, bytes: u64)

Record that a packet of bytes length was lost (no ACK before retransmit timer fired). Drives BBR’s loss-based feedback.

Source

pub fn bbr_state(&self) -> BbrState

Current BBR congestion-control state. Observability / test hook — lets callers confirm a loss drove the estimator into FastRecovery.

Source

pub fn bandwidth_snapshot(&self) -> BandwidthSnapshot

Read a snapshot of the bandwidth / pacing estimator. Cheap; held over a single mutex lock.

Source

pub fn send_notifier(&self) -> Arc<Notify>

Shared handle to the outbound-ready notify. The API-layer data pump awaits this via Notify::notified(); any task with the handle can wake it instantly via Self::notify_outbound_ready.

Source

pub fn notify_outbound_ready(&self)

Wake the data pump’s send loop immediately so it can drain newly- queued packets instead of waiting for the next 10 ms tick. Cheap (a single notify_one()); duplicate calls collapse to one wake.

Source

pub fn encrypt_packet( &self, header: &PacketHeader, plaintext: &[u8], ) -> Result<Vec<u8>, CoreError>

Encrypt a packet payload.

The AEAD nonce is derived from the authenticated (epoch, stream_id, sequence, path_id) fields of the packet header rather than from an internal monotonic counter, so a failed peer decrypt never desyncs the receiver. The AAD is the 45-byte wire image of the header (PacketHeader::to_wire), so any wire-level mutation invalidates the tag.

Source

pub fn decrypt_packet( &self, header: &PacketHeader, ciphertext: &[u8], ) -> Result<Vec<u8>, CoreError>

Decrypt a packet payload. Performs AEAD verify + per-stream sliding-window replay rejection (the window check runs after a successful AEAD open — Invariant 4 — so we never key off un-authenticated sequence numbers).

A failed decrypt does NOT desync future decrypts: the AEAD nonce is derived from this packet’s authenticated header fields, so the receiver stays in lock-step with the sender regardless of intervening bad packets.

Source

pub fn create_control_packet( &self, _message: ControlMessage, payload: Vec<u8>, ) -> PhantomPacket

Create a control packet

Source

pub fn scheduler(&self) -> &Arc<Scheduler>

Get the scheduler

Source

pub fn set_resumption_secret(&self, secret: [u8; 32])

Set resumption secret for 0-RTT.

If a secret was already set, the previous bytes are explicitly zeroed before being replaced — defense in depth in case set_resumption_secret is called multiple times within a session.

Source

pub fn resumption_secret(&self) -> Option<[u8; 32]>

The resumption secret for 0-RTT, if one has been installed. Rust-only — the FFI surface exposes this via PhantomSession::resumption_hint().

Source

pub fn can_resume(&self) -> bool

Check if session can be resumed (has resumption secret)

Source

pub fn resumption_hint(&self) -> Option<([u8; 32], [u8; 32])>

Extract the resumption hint needed to attempt 0-RTT resume on a future connect (Phase 4.1). Returns Some((session_id_bytes, resumption_secret)) only after a successful handshake — the resumption_secret is set by process_client_hello / process_server_hello once shared key material is in place.

The caller is responsible for storing the tuple alongside the pinned HybridVerifyingKey of the server it was negotiated with. Mixing tickets across servers is a configuration bug — the resumption_secret is server-pinned.

Source

pub fn update_activity(&self)

Update last activity timestamp

Source

pub fn is_expired(&self, timeout: Duration) -> bool

Check if session is expired

Trait Implementations§

Source§

impl Debug for Session

Source§

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

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

impl Drop for Session

Source§

fn drop(&mut self)

On session drop, explicitly zero the resumption secret. The CryptoState inside crypto is itself ZeroizeOnDrop, so its session_key is handled there.

Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CompatExt for T

Source§

fn compat(self) -> Compat<T>
where T: Sized,

Applies the Compat adapter by value. Read more
Source§

fn compat_ref(&self) -> Compat<&T>

Applies the Compat adapter by shared reference. Read more
Source§

fn compat_mut(&mut self) -> Compat<&mut T>

Applies the Compat adapter by mutable reference. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, UT> HandleAlloc<UT> for T
where T: Send + Sync,

Source§

fn new_handle(value: Arc<T>) -> Handle

Create a new handle for an Arc value Read more
Source§

unsafe fn clone_handle(handle: Handle) -> Handle

Clone a handle Read more
Source§

unsafe fn consume_handle(handle: Handle) -> Arc<T>

Consume a handle, getting back the initial Arc<> Read more
Source§

unsafe fn get_arc(handle: Handle) -> Arc<Self>

Get a clone of the Arc<> using a “borrowed” handle. Read more
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

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

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more