pub struct NetSession { /* private fields */ }Expand description
Session state after handshake completion.
Implementations§
Source§impl NetSession
impl NetSession
Sourcepub fn new(
keys: SessionKeys,
peer_addr: SocketAddr,
pool_size: usize,
default_reliable: bool,
) -> Self
pub fn new( keys: SessionKeys, peer_addr: SocketAddr, pool_size: usize, default_reliable: bool, ) -> Self
Create a new session from handshake results
Sourcepub fn seal_route_hop_into(
&self,
out: &mut [u8],
header: &RoutingHeader,
inner: &[u8],
) -> Result<usize, RouteHopError>
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.
Sourcepub fn seal_route_hop(&self, header: &RoutingHeader, inner: &[u8]) -> Vec<u8> ⓘ
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.
Sourcepub fn open_route_hop<'a>(
&self,
buf: &'a [u8],
) -> Result<OpenedHop<'a>, RouteHopError>
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.
Sourcepub fn cached_node_id(&self) -> Option<u64>
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.
Sourcepub fn cache_node_id(&self, node_id: u64)
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.
Sourcepub fn next_control_tx_seq(&self) -> u64
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.
Sourcepub fn session_id(&self) -> u64
pub fn session_id(&self) -> u64
Get the session ID
Sourcepub fn peer_addr(&self) -> SocketAddr
pub fn peer_addr(&self) -> SocketAddr
Get the peer address
Sourcepub fn get_or_create_stream(
&self,
stream_id: u64,
) -> RefMut<'_, u64, StreamState>
pub fn get_or_create_stream( &self, stream_id: u64, ) -> RefMut<'_, u64, StreamState>
Get or create stream state
Sourcepub fn get_or_create_stream_for_packet(
&self,
stream_id: u64,
reliable: bool,
) -> RefMut<'_, u64, StreamState>
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.
Sourcepub fn collect_timed_out_retransmits(&self) -> Vec<Arc<RetransmitDescriptor>>
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.
Sourcepub fn collect_gap_reports(
&self,
want_ranges: bool,
max_ranges: usize,
) -> Vec<GapReport>
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.
Sourcepub fn take_failed_stream_ids(&self) -> Vec<u64>
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.
Sourcepub fn try_stream(&self, stream_id: u64) -> Option<Ref<'_, u64, StreamState>>
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.
Sourcepub fn try_acquire_tx_credit_guard(
self: &Arc<Self>,
stream_id: u64,
bytes: u32,
) -> TxAdmit
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::Acquiredwith aTxSlotGuardthat refundsbytesback totx_credit_remainingwhen dropped — including on async cancellation, panic, and early return — unless the caller invokesTxSlotGuard::committo 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::WindowFulliftx_credit_remainingis belowbytes.backpressure_eventshas already been bumped.TxAdmit::StreamClosedif the stream isn’t registered (never opened, closed, or idle-evicted).
Sourcepub fn try_acquire_tx_credit_matching_epoch(
self: &Arc<Self>,
stream_id: u64,
expected_epoch: u64,
bytes: u32,
) -> TxAdmit
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.
Sourcepub fn try_rollback_tx_seq(
self: &Arc<Self>,
stream_id: u64,
epoch: u64,
seq: u64,
) -> bool
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
impl NetSession
Sourcepub fn open_stream_with(
&self,
stream_id: u64,
reliable: bool,
fairness_weight: u8,
) -> u64
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.
Sourcepub fn open_stream_full(
&self,
stream_id: u64,
reliable: bool,
fairness_weight: u8,
tx_window: u32,
) -> u64
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.
Sourcepub fn close_stream(&self, stream_id: u64)
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.
Sourcepub fn is_grant_quarantined(&self, stream_id: u64) -> bool
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.
Sourcepub fn evict_idle_streams(
&self,
max_idle: Duration,
max_streams: usize,
reason_tag: &'static str,
) -> usize
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.
Sourcepub fn get_stream(&self, stream_id: u64) -> Option<Ref<'_, u64, StreamState>>
pub fn get_stream(&self, stream_id: u64) -> Option<Ref<'_, u64, StreamState>>
Get stream state (read-only)
Sourcepub fn thread_local_pool(&self) -> &SharedLocalPool
pub fn thread_local_pool(&self) -> &SharedLocalPool
Get the thread-local pool for zero-contention packet building
Sourcepub fn build_heartbeat(&self) -> Bytes
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.
Sourcepub fn verify_and_touch_heartbeat(&self, parsed: &ParsedPacket) -> bool
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.
Sourcepub fn last_activity_ns(&self) -> u64
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.
Sourcepub fn is_timed_out(&self, timeout: Duration) -> bool
pub fn is_timed_out(&self, timeout: Duration) -> bool
Check if session has timed out
Sourcepub fn deactivate(&self)
pub fn deactivate(&self)
Deactivate the session
Sourcepub fn stream_ids(&self) -> Vec<u64>
pub fn stream_ids(&self) -> Vec<u64>
Get all stream IDs
Sourcepub fn stream_count(&self) -> usize
pub fn stream_count(&self) -> usize
Get the number of streams
Sourcepub fn has_open_streams(&self) -> bool
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.
Sourcepub fn has_unacked(&self) -> bool
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.