Skip to main content

NetSession

Struct NetSession 

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

Session state after handshake completion.

Implementations§

Source§

impl NetSession

Source

pub fn new( keys: SessionKeys, peer_addr: SocketAddr, pool_size: usize, default_reliable: bool, ) -> Self

Create a new session from handshake results

Source

pub fn seal_route_hop_into( &self, out: &mut [u8], header: &RoutingHeader, inner: &[u8], ) -> Result<usize, RouteHopError>

Wrap inner in an authenticated route-hop envelope for this edge, writing into a caller-owned buffer (SUBNET_AUTH_PLAN.md D6).

The sequence is this edge’s own, independent of the packet AEAD counter, so hop accounting can never disturb the end-to-end session being carried.

This is the form the forwarding path uses: the buffer belongs to the forwarder and is reused across packets, so relaying does not allocate. Size it with route_hop::sealed_len.

A too-small buffer is refused before a sequence is taken — burning one on a local sizing mistake would open a gap in this edge’s sequence space for no reason.

Source

pub fn seal_route_hop(&self, header: &RoutingHeader, inner: &[u8]) -> Vec<u8>

Allocating form of Self::seal_route_hop_into, for callers off the forwarding path.

Source

pub fn open_route_hop<'a>( &self, buf: &'a [u8], ) -> Result<OpenedHop<'a>, RouteHopError>

Verify an inbound route-hop envelope and admit its sequence exactly once.

Returns the opened hop on success. A bad tag is rejected before the replay window is touched, so a forged packet cannot burn a sequence slot the legitimate peer still needs.

Source

pub fn cached_node_id(&self) -> Option<u64>

Read the cached peer NodeId resolution. Returns None until the dispatcher’s first resolution call publishes a value via Self::cache_node_id. See the field doc for the perf rationale.

Source

pub fn cache_node_id(&self, node_id: u64)

Publish the resolved peer NodeId for subsequent calls. Idempotent — concurrent first-resolution callers all write the same value (the resolver is deterministic for a given session_id), so a store over an existing identical value is correct. Callers should pass non-zero node_id; 0 is the reserved “unresolved” sentinel and is a no-op.

Source

pub fn next_control_tx_seq(&self) -> u64

Allocate the next sequence number for a subprotocol control packet. Uses a session-level counter separate from any user stream’s sequence space — see CONTROL_STREAM_ID.

Source

pub fn session_id(&self) -> u64

Get the session ID

Source

pub fn peer_addr(&self) -> SocketAddr

Get the peer address

Source

pub fn rx_cipher(&self) -> &PacketCipher

Get the RX cipher

Source

pub fn get_or_create_stream( &self, stream_id: u64, ) -> RefMut<'_, u64, StreamState>

Get or create stream state

Source

pub fn get_or_create_stream_for_packet( &self, stream_id: u64, reliable: bool, ) -> RefMut<'_, u64, StreamState>

Like Self::get_or_create_stream, but the receiver-side stream is created reliable when the arriving packet is RELIABLE-flagged — the sender’s reliability is a property of the traffic, not of the receiver’s default_reliable. Without this the auto-created receive stream is FireAndForget and never builds a NACK, so a reliable sender’s lost packets are unrecoverable. Only affects the reliability mode at first-touch (creation); an existing stream keeps its mode.

Source

pub fn collect_timed_out_retransmits(&self) -> Vec<Arc<RetransmitDescriptor>>

Collect retransmit descriptors for every reliable stream whose oldest unacked packet has exceeded its RTO. Drives the timeout backstop (STREAM_RETRANSMIT D-4) that recovers tail loss — the last packets dropped, with no later arrival to trigger a receiver NACK. Each call advances the per-packet retry clock, so a descriptor isn’t re-emitted until another RTO elapses, and a packet past max_retries is dropped from the window.

Source

pub fn collect_gap_reports( &self, want_ranges: bool, max_ranges: usize, ) -> Vec<GapReport>

Collect the per-stream gap report for every stream that currently has a gap (H-4 + STREAM_ACK_BATCHING R-4), in ONE walk taking each stream’s reliability lock exactly once.

The proactive retransmit tick needs two things for a gapped stream — the legacy NACK and (for capable peers) the positive SACK ranges — and both derive from the same received-range index (build_nack and build_ack_ranges are non-empty under the identical has_gaps() condition). Snapshotting them under one lock keeps a tick’s NACK and SACK for a stream mutually consistent and halves the tick’s per-stream lock/DashMap cost versus the old two-walk shape (collect_gap_nacks + collect_ack_ranges).

ranges is only built when want_ranges (the peer advertises the ack-ranges capability); otherwise it is left empty so a non-advertising peer pays nothing for the SACK build. Streams without gaps contribute nothing — the grant’s piggybacked ack_seq already covers the contiguous case.

Source

pub fn take_failed_stream_ids(&self) -> Vec<u64>

Take-and-clear the “given up” flag across all streams, returning the ids of streams whose reliable layer exhausted retransmits on some packet (H-3). The caller signals a reset to the peer so the receiver fails fast instead of stalling to a timeout.

Source

pub fn try_stream(&self, stream_id: u64) -> Option<Ref<'_, u64, StreamState>>

Look up stream state without creating it. Returns None if the stream was never opened or has been closed.

Source

pub fn try_acquire_tx_credit_guard( self: &Arc<Self>, stream_id: u64, bytes: u32, ) -> TxAdmit

Try to acquire bytes of send credit on stream_id with RAII refund semantics.

Returns:

  • TxAdmit::Acquired with a TxSlotGuard that refunds bytes back to tx_credit_remaining when dropped — including on async cancellation, panic, and early return — unless the caller invokes TxSlotGuard::commit to suppress the refund after a successful socket send. This is the cure for the credit-leak that a plain “decrement / await / maybe-refund” shape would hit when the sending future is dropped mid-.await (e.g., tokio::select! cancel).
  • TxAdmit::WindowFull if tx_credit_remaining is below bytes. backpressure_events has already been bumped.
  • TxAdmit::StreamClosed if the stream isn’t registered (never opened, closed, or idle-evicted).
Source

pub fn try_acquire_tx_credit_matching_epoch( self: &Arc<Self>, stream_id: u64, expected_epoch: u64, bytes: u32, ) -> TxAdmit

Like Self::try_acquire_tx_credit_guard, but additionally rejects the admission if the live StreamState’s epoch differs from expected_epoch.

Use from the typed-handle send_on_stream path so a handle held across a close+reopen cycle doesn’t admit against the new stream’s state.

Source

pub fn try_rollback_tx_seq( self: &Arc<Self>, stream_id: u64, epoch: u64, seq: u64, ) -> bool

Roll back a TX sequence allocated by Self::try_acquire_tx_credit_matching_epoch when the packet it was minted for never reached the wire (scheduler/socket backpressure after the seq was consumed). Guarded by epoch so a close+reopen race can’t roll back a sequence on a fresh stream state that never issued it — the exact discipline TxSlotGuard::drop uses for the byte-credit refund.

Returns true if the sequence was reclaimed (it was the most- recently-issued seq and no concurrent send raced ahead), leaving no receiver-visible gap; false otherwise.

Source§

impl NetSession

Source

pub fn open_stream_with( &self, stream_id: u64, reliable: bool, fairness_weight: u8, ) -> u64

Open a stream with an explicit reliability mode and fair-scheduler weight.

Idempotent: if the stream already exists, this is a no-op and the caller’s config is ignored with a warning log — the first open wins. Callers that want to change a stream’s config must close + re-open it.

Source

pub fn open_stream_full( &self, stream_id: u64, reliable: bool, fairness_weight: u8, tx_window: u32, ) -> u64

Extended open that also sets the per-stream TX window for backpressure. tx_window == 0 keeps the pre-backpressure behavior (unbounded local queue).

Returns the epoch of the live StreamState for stream_id — either the fresh one created for a new stream, or the existing one if the stream is already open (first-open-wins). Callers embed this in their Stream handle so later sends can reject stale handles after close+reopen.

Source

pub fn close_stream(&self, stream_id: u64)

Close a stream: mark it inactive and remove its state.

Idempotent — closing a non-existent stream is a no-op. After close, a subsequent open_stream_with creates a fresh stream.

Also records stream_id in the grant-quarantine set so that any StreamWindow grant still in flight from a peer who was communicating with the just-closed lifetime is dropped rather than spuriously crediting a later reopen — see GRANT_QUARANTINE_WINDOW and Self::is_grant_quarantined.

Source

pub fn is_grant_quarantined(&self, stream_id: u64) -> bool

Whether a StreamWindow grant for stream_id should be dropped because the stream was closed within GRANT_QUARANTINE_WINDOW. Lazily garbage-collects expired entries on call.

Source

pub fn evict_idle_streams( &self, max_idle: Duration, max_streams: usize, reason_tag: &'static str, ) -> usize

Remove streams whose last_activity is older than max_idle, keeping the active count at or below max_streams by LRU-evicting the oldest if still over cap. Returns the number of streams evicted. Called from the session owner’s heartbeat loop.

Source

pub fn get_stream(&self, stream_id: u64) -> Option<Ref<'_, u64, StreamState>>

Get stream state (read-only)

Source

pub fn thread_local_pool(&self) -> &SharedLocalPool

Get the thread-local pool for zero-contention packet building

Source

pub fn build_heartbeat(&self) -> Bytes

Build an AEAD-authenticated heartbeat packet for this session.

Routes through thread_local_pool so the heartbeat shares its TX counter with data-path packets — heartbeats and data interleave cleanly on the wire, and the receiver’s replay window admits them in either order.

Wrapping heartbeat construction in this method removes the surface that would otherwise let callers build heartbeats with a fresh PacketBuilder::new(&[0u8; 32], session_id), which (a) would use the wrong key so the receiver’s AEAD verify would reject every heartbeat, and (b) would reuse counter=0 across successive heartbeats so the replay window would reject every heartbeat after the first.

Source

pub fn verify_and_touch_heartbeat(&self, parsed: &ParsedPacket) -> bool

Verify an inbound heartbeat’s AEAD tag against this session’s RX cipher, commit the counter into the replay window, and refresh last_activity. Returns true if the packet was accepted; the session is mutated only on success.

Verify and touch are fused into a single call so callers cannot get the order wrong (verify-then-touch, never the reverse) or forget to touch (which would defeat session idle-timeout for legitimate heartbeats).

Source-address validation (legacy adapter: 1:1 source per session) and any post-accept observation (mesh: failure_detector.heartbeat) remain the caller’s responsibility — those policies vary by adapter and don’t belong inside the helper.

Heartbeats MUST decrypt the AEAD tag rather than be fast- pathed through to failure_detector.heartbeat and session.touch() based on is_heartbeat() alone — without the decrypt step, an off-path attacker who observed the cleartext session_id and source UDP address could spoof heartbeats indefinitely.

Source

pub fn touch(&self)

Update last activity timestamp

Source

pub fn last_activity_ns(&self) -> u64

Nanoseconds since epoch of the last activity. Useful for tests / diagnostics that need to observe whether touch has been called.

Source

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

Check if session has timed out

Source

pub fn is_active(&self) -> bool

Check if session is active

Source

pub fn deactivate(&self)

Deactivate the session

Source

pub fn stream_ids(&self) -> Vec<u64>

Get all stream IDs

Source

pub fn stream_count(&self) -> usize

Get the number of streams

Source

pub fn has_open_streams(&self) -> bool

true if any application stream is currently open on this session. Control-plane traffic rides a separate sequence space and is not counted. Used by the NAT-traversal direct-path upgrade’s busy gate (NAT_TRAVERSAL_V2_PLAN.md C3): a session carrying live streams must not be swapped out from under them.

Source

pub fn has_unacked(&self) -> bool

true if any stream on this session has unacked in-flight reliable data (a non-empty retransmit window). Walks the live streams and short-circuits on the first with pending packets. Companion to Self::has_open_streams for the upgrade busy gate — swapping the session would drop this in-flight data with no retransmit on the new session.

Trait Implementations§

Source§

impl Debug for NetSession

Source§

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

Formats the value using the given formatter. 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<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> 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<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