pub struct UdpClientTransport { /* private fields */ }std and non-WebAssembly only.Implementations§
Source§impl UdpClientTransport
impl UdpClientTransport
Sourcepub async fn connect(server: SocketAddr) -> Result<Self, CoreError>
pub async fn connect(server: SocketAddr) -> Result<Self, CoreError>
Bind a fresh UNCONNECTED UDP socket for talking to server, choosing a random
lifetime connection-ID. The socket is left unconnected (no socket.connect) so the
client can recv_from any source — the precondition for hearing, and later
following, a server that migrates to a new address. Datagrams are sent with
send_to(server_addr).
Sourcepub async fn migrate_to(
&self,
new_local_addr: SocketAddr,
) -> Result<(), CoreError>
pub async fn migrate_to( &self, new_local_addr: SocketAddr, ) -> Result<(), CoreError>
Rebind to a fresh local socket and route subsequent traffic through it
(Phase 4 / P4.2b — embedder-triggered migration). Best-effort and
non-blocking on validation: it binds a fresh unconnected socket (sends still
send_to the tracked server_addr), then atomically swaps it in as the active
socket while KEEPING the old one for the overlap (the recv loop listens on both
until the new path shows
life, then drops the old — broken-rebind safety / D7). Subsequent app data +
L1 retransmits go out the new socket, so the server detects the new source
(P4.1) and challenges → validates → swaps its peer. The caller is responsible
for bumping the session send path_id (Session::next_migration_path_id).
A bind/connect failure returns Err WITHOUT touching the active socket, so a
migration to a dead/invalid address never tears the session down — the session
keeps running on the old socket.
Typed core of the migration; the SocketAddr-free SessionTransport::migrate
trait entry parses a String and delegates here.
Trait Implementations§
Source§impl SessionTransport for UdpClientTransport
impl SessionTransport for UdpClientTransport
Source§async fn migrate(&self, local_addr: String) -> Result<(), CoreError>
async fn migrate(&self, local_addr: String) -> Result<(), CoreError>
SocketAddr-free trait entry for connection migration (Phase 4 / P4.2c). Parses
the embedder-supplied local bind address and delegates to the typed
migrate_to. A malformed address is a clean Err that
leaves the session on its existing socket (best-effort, never fatal).
Source§async fn send_bytes(&self, data: &[u8]) -> Result<(), CoreError>
async fn send_bytes(&self, data: &[u8]) -> Result<(), CoreError>
Source§async fn recv_bytes(&self) -> Result<Bytes, CoreError>
async fn recv_bytes(&self) -> Result<Bytes, CoreError>
Bytes is
a refcounted view over an opaque buffer; subsequent clone()s
are cheap.Source§fn set_frame_phase(&self, phase: FramePhase)
fn set_frame_phase(&self, phase: FramePhase)
FramePhase, adjusting the receive
frame-size cap (WIRE-001). Default no-op — transports that do not
length-prefix / buffer, or are inherently bounded, need not implement it.
Called once by the session machinery at the handshake → data-pump
boundary. Adding this defaulted method is source-compatible for every
existing impl.Source§fn set_outbound_cid(&self, cid: [u8; 8])
fn set_outbound_cid(&self, cid: [u8; 8])
current_outbound_cid() (the rotating CID_0), switching the
transport off the bootstrap ConnId onto the chain. Default no-op —
socket-routed transports (TCP / WebSocket / WASI / Embedded) carry no
on-wire CID and ignore it. Source-compatible for every existing impl.Source§fn confirm_authenticated_source(&self)
fn confirm_authenticated_source(&self)
PATH_CHALLENGE target) is only ever an AEAD-authenticated source, so a
spoofed CID-matched datagram (which never decrypts) cannot clobber the candidate slot
and misdirect / stall a legitimate migration. SocketAddr-free — the address stays inside
the concrete transport. Default no-op for transports without migration.Source§fn has_migration_candidate(&self) -> bool
fn has_migration_candidate(&self) -> bool
true; stream
transports (TCP / WebSocket / WASI / Embedded) have no migration and use
the default false. Deliberately SocketAddr-free so the generic data
pump that calls it stays no_std-clean (std::net::SocketAddr does not
exist in core/alloc); the candidate address is held inside the
concrete transport.Source§async fn send_to_candidate(&self, data: &[u8]) -> Result<bool, CoreError>
async fn send_to_candidate(&self, data: &[u8]) -> Result<bool, CoreError>
data — an already-encrypted PATH_VALIDATION challenge built by the
session — to the transport’s internally-tracked candidate source, distinct
from the established peer, under the transport’s own anti-amplification cap
(RFC 9000 §8.2). Returns Ok(true) if a candidate existed and the send was
within budget, Ok(false) otherwise (no candidate, or the 3× cap was hit).
Default (non-address transports): a no-op Ok(false). The candidate
address never crosses this boundary, keeping the trait no_std-safe.Source§fn promote_candidate(&self) -> bool
fn promote_candidate(&self) -> bool
true if a candidate
was promoted. Default no-op (false) for transports without migration.
SocketAddr-free — the address is internal to the concrete transport.Source§fn migrate_server(
&self,
_local_addr: String,
) -> impl Future<Output = Result<(), CoreError>> + Send
fn migrate_server( &self, _local_addr: String, ) -> impl Future<Output = Result<(), CoreError>> + Send
migrate for the accepting peer. The server binds a
fresh local socket, sends subsequent server→client datagrams from it (so the client
sees a new s2c source and follows it), and receives on it too (so once the client
switches its send target the c2s frames are delivered transparently). The address
crosses as a String to keep the trait SocketAddr-free / no_std-clean. Best-effort:
a parse / bind failure returns Err and the session keeps running on the old socket.
Default no-op Ok(()) — only the native UDP server implements it. Kept distinct from
migrate so the FFI-exported client migrate() cannot trigger a
server migration.