Skip to main content

moq_uring/quic/
endpoint.rs

1//! The multi-connection endpoint: one socket, many QUIC connections.
2//!
3//! An [`Endpoint`] owns a [`udp::Socket`](crate::udp::Socket) and routes
4//! every received datagram to the connection its destination connection id
5//! names: dials share the socket with accepted connections, which is what
6//! lets one worker socket carry a relay's inbound sessions and its upstream
7//! cluster dials at once. A single demux task receives; each connection keeps
8//! a driver task of its own for timers and egress.
9//!
10//! Every connection id this endpoint issues is [`CID_LEN`] bytes, which is
11//! what lets a short header (which does not encode the id's length) be
12//! parsed at all. Ids rotate as peers consume them (`NEW_CONNECTION_ID`), so
13//! a migrating client stays routable; an Initial for an unsupported version
14//! gets a version negotiation packet back.
15//!
16//! The socket is the endpoint's identity. Its worker is where the demux and
17//! every connection driver run, whichever thread built the endpoint. A socket
18//! adopted as a member of a steered `SO_REUSEPORT` group (one worker per core
19//! on one port; see [`udp::Bound`](crate::udp::Bound)) brings its slot along,
20//! and every id the endpoint issues then carries the
21//! [`moq_sock::shard::cid_prefix`] steering byte, so the kernel keeps
22//! delivering a connection's packets to the worker that owns it. Dials
23//! through the endpoint carry it too, which is what steers a cluster peer's
24//! responses back to the dialing worker.
25
26use super::server;
27
28pub use super::noq::Endpoint;
29
30/// Every connection id this endpoint issues is this long: long enough to be
31/// unguessable per socket, and fixed because a short header does not encode
32/// the id's length, so parsing one assumes it.
33pub const CID_LEN: usize = 8;
34
35/// What an endpoint serves, beyond dialing.
36#[derive(Clone, Debug)]
37#[non_exhaustive]
38pub struct Config {
39	/// Accept incoming connections with this configuration. Without it the
40	/// endpoint only dials, and inbound handshakes are dropped.
41	pub server: Option<server::Config>,
42
43	/// How many incoming connections may await acceptance at once (default 1024).
44	///
45	/// This bounds both handshakes in flight and completed connections queued
46	/// for [`Endpoint::accept`]. An Initial past the cap is dropped; a real
47	/// peer retransmits and lands once the application drains the backlog or
48	/// a handshake fails.
49	pub backlog: usize,
50}
51
52impl Default for Config {
53	fn default() -> Self {
54		Self {
55			server: None,
56			backlog: 1024,
57		}
58	}
59}
60
61impl Config {
62	/// Accept incoming connections with `server`, on top of dialing.
63	pub fn with_server(mut self, server: server::Config) -> Self {
64		self.server = Some(server);
65		self
66	}
67}
68
69/// A fresh [`CID_LEN`]-byte connection id, leading with the steering prefix
70/// when the endpoint's socket is a member of a reuseport group.
71pub(crate) fn cid(shard: Option<moq_sock::shard::Shard>) -> [u8; CID_LEN] {
72	let mut cid: [u8; CID_LEN] = rand::random();
73	if let Some(shard) = shard {
74		cid[0] = moq_sock::shard::cid_prefix(shard);
75	}
76	cid
77}