pub struct Listener {
endpoint: Endpoint,
server_config: ServerConfig,
}Expand description
A transport-agnostic MoQT listener that accepts both raw-QUIC and WebTransport clients on the same UDP port.
Fields§
§endpoint: Endpoint§server_config: ServerConfigThe server configuration this endpoint was built with, kept so that
Listener::set_transport can replace one field of it without
rebuilding the rest.
A clone of the value handed to quinn rather than a fresh build, and
the difference is not an optimisation. Rebuilding would re-parse the
certificate — which means retaining the private key here, and
PrivateKeyDer is not Clone — and quinn::ServerConfig::with_crypto
draws a fresh random handshake-token master key each time it is
called, which would invalidate every retry token already outstanding.
Keeping the built value costs one Arc per field and none of that.
Implementations§
Source§impl Listener
impl Listener
Sourcepub fn bind(config: ListenerConfig) -> Result<Self, ProxyError>
pub fn bind(config: ListenerConfig) -> Result<Self, ProxyError>
Bind to the configured address and start listening.
The listener advertises every supported MoQT ALPN (moq-00 and
moqt-<N> for all known drafts) plus h3 for WebTransport. The
client picks which one to speak; the proxy forwards whatever
arrives.
This binds an ordinary UDP socket at ListenerConfig::bind_addr,
wraps it with quinn’s default runtime adapter and hands it to
Listener::bind_with_socket. Must therefore be called from
inside a tokio runtime context — as it always had to be, because
quinn reaches for the same runtime when it binds a socket itself.
Sourcepub fn bind_with_socket(
config: ListenerConfig,
socket: Arc<dyn AsyncUdpSocket>,
) -> Result<Self, ProxyError>
pub fn bind_with_socket( config: ListenerConfig, socket: Arc<dyn AsyncUdpSocket>, ) -> Result<Self, ProxyError>
Bind the listener over a caller-supplied abstract socket.
Every datagram this listener sends to, or receives from, a client
passes through socket, so a caller that supplies a decorating
implementation — a tap, a counter, a network-impairment shim —
observes and can alter the whole client-facing leg. Ownership is
shared, so the caller keeps its handle on the socket after the
endpoint is running.
ListenerConfig::bind_addr is ignored here: socket is already
bound, and its address is the one Listener::local_addr reports.
The rest of the configuration — the certificate, the advertised
ALPN list, the transport parameters — applies exactly as it does to
Listener::bind, which is a thin wrapper around this function.
§One socket covers WebTransport clients too
This single seam reaches raw-QUIC and WebTransport clients alike,
because on the client-facing side the proxy never builds a
WebTransport endpoint of its own. It builds the QUIC endpoint here,
reads the negotiated ALPN off the handshake, and for h3 clients
hands the still-connecting QUIC connection to the WebTransport
library to finish. The library adopts a connection that already
lives on this endpoint rather than binding a socket for it, so
there is no second datagram path to intercept.
The relay leg to the upstream relay is a separate endpoint and is not affected by this socket.
Sourcepub(crate) fn set_transport(&self, transport: Arc<TransportConfig>)
pub(crate) fn set_transport(&self, transport: Arc<TransportConfig>)
Install transport as the QUIC transport parameters this listener
gives to the connections it accepts from now on.
§It cannot reach a connection that already exists
A quinn connection takes its TransportConfig once, out of the
server configuration in force when its handshake began, and keeps
that Arc for as long as it lives. There is no way to hand a live
connection a different one — quinn exposes four setters on an
accepted connection (the two stream-count limits and the two
windows) and nothing else. So this changes what the next accepted
connection gets and leaves every connection already running exactly
as it was.
That is worth stating rather than glossing, because the failure it produces is silent: on a proxy nobody is connecting to any more, this call succeeds, changes the endpoint, and never reaches a single packet.
Everything else about the endpoint — the certificate, the advertised ALPN list, the handshake token key — is carried over from the configuration the listener bound with, so a client’s view of this server is unchanged apart from the transport parameters.
Sourcepub async fn accept(&self) -> Result<AcceptedConn, ProxyError>
pub async fn accept(&self) -> Result<AcceptedConn, ProxyError>
Accept the next incoming connection and dispatch based on the ALPN negotiated during the TLS handshake.
Raw-QUIC connections are returned immediately with the negotiated
ALPN so the caller can pick the MoQT draft. For h3 clients the
listener drives the HTTP/3 + extended-CONNECT handshake to
completion before returning a ready wtransport::Connection.
Sourcepub fn local_addr(&self) -> Result<SocketAddr, ProxyError>
pub fn local_addr(&self) -> Result<SocketAddr, ProxyError>
Get the local address this listener is bound to.