pub struct PhantomSession { /* private fields */ }Expand description
Client-first session — instant connect(), non-blocking send().
§Design
let session = PhantomSession::connect("server:443"); // instant!
session.send(data).await; // queued until handshake completes
session.send(data2).await; // also queued
// ... handshake completes in background ...
// queued data auto-flushed, new sends go directlyThe session progresses through states:
Connecting → ClassicalReady → PqcUpgrading → PqcReady → Connected
Implementations§
Source§impl PhantomSession
impl PhantomSession
Sourcepub fn connect_with_transport<T: SessionTransport>(
peer_addr: &str,
transport: T,
expected_server_key: HybridVerifyingKey,
) -> Self
pub fn connect_with_transport<T: SessionTransport>( peer_addr: &str, transport: T, expected_server_key: HybridVerifyingKey, ) -> Self
Create a new session and start the background handshake task.
Requires expected_server_key for MITM resistance — the client will
abort the handshake unless the server presents this exact verifying key.
Callers obtain this key out-of-band (e.g. from PhantomListener::verifying_key_bytes).
The handshake runs in the background:
- Exchange hybrid PQC
ClientHello/ServerHello. - Verify server identity against
expected_server_key. - Derive AEAD keys; flush queued sends as encrypted packets.
All network I/O goes through the provided SessionTransport. The
task that drives the handshake + data pump runs on the default
TokioRuntime; use
connect_with_transport_with_runtime
to substitute a different Runtime.
Sourcepub fn connect_with_transport_with_runtime<T: SessionTransport>(
peer_addr: &str,
transport: T,
expected_server_key: HybridVerifyingKey,
runtime: Arc<dyn Runtime>,
) -> Self
pub fn connect_with_transport_with_runtime<T: SessionTransport>( peer_addr: &str, transport: T, expected_server_key: HybridVerifyingKey, runtime: Arc<dyn Runtime>, ) -> Self
Like connect_with_transport but
runs the background task on the supplied Runtime. Intended for
WASM / embedded / test backends that don’t drive tokio::spawn.
Sourcepub fn connect_with_resumption<T: SessionTransport>(
peer_addr: &str,
transport: T,
expected_server_key: HybridVerifyingKey,
resumption_hint: ([u8; 32], [u8; 32]),
early_data: Vec<u8>,
) -> Result<Self, CoreError>
pub fn connect_with_resumption<T: SessionTransport>( peer_addr: &str, transport: T, expected_server_key: HybridVerifyingKey, resumption_hint: ([u8; 32], [u8; 32]), early_data: Vec<u8>, ) -> Result<Self, CoreError>
Connect with a 0-RTT resumption attempt.
resumption_hint is the (session_id, resumption_secret) tuple
from a prior session’s PhantomSession::resumption_hint.
early_data (≤ EARLY_DATA_MAX_LEN bytes) is sealed and carried
inside the resuming ClientHello so it reaches the server on the very
first flight — saving a round-trip versus 1-RTT.
Acceptance is best-effort: a stale/unknown ticket or an AEAD failure
leaves early_data_accepted at
Some(false) and the handshake completes as a normal 1-RTT exchange —
the caller must then send that payload over the normal channel.
Returns Err only when early_data exceeds the cap.
Runs on the default TokioRuntime.
Source§impl PhantomSession
impl PhantomSession
Sourcepub fn observability(&self) -> Arc<Observability>
pub fn observability(&self) -> Arc<Observability>
Session observability handle (Rust-only — Observability is not a
UniFFI type). For a server-accepted session this is the
PhantomListener’s shared instance; for a client it is the session’s
own. Read .snapshot() for the lock-free metric counters.
Source§impl PhantomSession
impl PhantomSession
Sourcepub fn connect(peer_addr: String) -> Arc<Self>
pub fn connect(peer_addr: String) -> Arc<Self>
Create a new session — returns instantly.
Handshake is not started until a transport is provided.
Use connect_with_transport() for full integration.
Sourcepub fn open_stream(&self) -> Arc<PhantomStream>
pub fn open_stream(&self) -> Arc<PhantomStream>
Open a new multiplexed stream
Sourcepub async fn send(&self, data: Vec<u8>) -> Result<(), CoreError>
pub async fn send(&self, data: Vec<u8>) -> Result<(), CoreError>
Send data through the session.
- If the session is connected: sends immediately
- If still handshaking: queues the data for auto-flush later
Sourcepub async fn recv(&self) -> Result<Vec<u8>, CoreError>
pub async fn recv(&self) -> Result<Vec<u8>, CoreError>
Receive data from the session.
Internally the recv pipeline keeps payloads as Bytes to avoid the
per-packet Vec clone that used to fan out to the stream demux. The
FFI surface still hands callers a Vec<u8>; if this is the last
refcount the Vec is moved out of the underlying buffer, otherwise
Bytes::to_vec copies.
Sourcepub fn connection_state(&self) -> ConnectionState
pub fn connection_state(&self) -> ConnectionState
Get the current connection state (lock-free).
Sourcepub fn is_data_ready(&self) -> bool
pub fn is_data_ready(&self) -> bool
Whether the session is ready for data transmission.
Sourcepub fn is_pqc_ready(&self) -> bool
pub fn is_pqc_ready(&self) -> bool
Whether the session has full PQC protection.
Sourcepub async fn flush_queue(&self) -> Result<u32, CoreError>
pub async fn flush_queue(&self) -> Result<u32, CoreError>
Flush all queued messages (called when handshake completes).
Sourcepub async fn queued_count(&self) -> u32
pub async fn queued_count(&self) -> u32
Number of messages queued (waiting for handshake).
Sourcepub async fn early_data_accepted(&self) -> Option<bool>
pub async fn early_data_accepted(&self) -> Option<bool>
The 0-RTT verdict for this session.
None— still handshaking, the handshake failed, or the client sent no early-data on this connect.Some(true)— the server consumed the 0-RTT early-data.Some(false)— the client sent early-data and the server rejected it (stale/unknown ticket, oversized blob, or AEAD failure). The caller must re-send that payload over the normal channel.
Sourcepub async fn resumption_hint(&self) -> Option<ResumptionHint>
pub async fn resumption_hint(&self) -> Option<ResumptionHint>
Extract a ResumptionHint for a future 0-RTT reconnect.
Returns Some after a successful handshake; None while still
handshaking, after a failure, or before the inner session has
been published.
Store the hint alongside the pinned HybridVerifyingKey of the
server it was negotiated against and feed it back to
connect_pinned_with_resumption. Reusing a hint across
servers is a configuration bug — the resumption_secret is
server-pinned.
Sourcepub async fn current_epoch(&self) -> Option<u8>
pub async fn current_epoch(&self) -> Option<u8>
Current rekey epoch of the established session (None while still
connecting). Rust-only — used by soak / integration tests to confirm
that automatic mid-session rekey (C1) advanced the epoch.
Sourcepub async fn set_rekey_threshold(&self, n: u64) -> bool
pub async fn set_rekey_threshold(&self, n: u64) -> bool
Override the automatic-rekey send-invocation high-watermark on the
established session (default REKEY_SOFT_LIMIT). Returns false if
the session is still connecting. Rust-only — primarily for soak/load
harnesses that need to exercise mid-session rekey without sending 2^47
packets.
Sourcepub async fn disconnect(&self) -> Result<(), CoreError>
pub async fn disconnect(&self) -> Result<(), CoreError>
Send the graceful close frame and shut the session down.
Named disconnect rather than close because UniFFI’s Kotlin
generator unconditionally adds AutoCloseable.close() to every
object, and a Rust-side close here would conflict with it.
Source§impl PhantomSession
impl PhantomSession
Sourcepub fn demux(&self) -> Arc<StreamDemultiplexer>
pub fn demux(&self) -> Arc<StreamDemultiplexer>
Get the stream demultiplexer (internal use, not exposed to UniFFI)