pub struct ProxySessionConfig {
pub draft: DraftVersion,
pub upstream_transport: UpstreamTransportType,
pub upstream_addr: String,
pub skip_upstream_cert_verify: bool,
pub upstream_ca_certs: Vec<Vec<u8>>,
pub upstream_connect_timeout_secs: u64,
pub upstream_transport_config: Option<Arc<TransportConfig>>,
pub upstream_transport_profile: Option<TransportProfile>,
pub upstream_installer: Option<Arc<dyn TransportInstaller>>,
pub upstream_socket: Option<Arc<dyn AsyncUdpSocket>>,
pub egress: EgressConfig,
pub shape: Option<ShapeProfile>,
}Expand description
Configuration for a proxy session’s upstream connection.
Fields§
§draft: DraftVersionThe MoQT draft version to use for parsing.
upstream_transport: UpstreamTransportTypeThe transport type to use for the upstream connection.
upstream_addr: StringUpstream relay address (e.g., "192.168.1.10:4443" for QUIC).
skip_upstream_cert_verify: boolWhether to skip TLS verification for the upstream connection.
upstream_ca_certs: Vec<Vec<u8>>Custom CA certificates for the upstream connection (DER-encoded).
upstream_connect_timeout_secs: u64Timeout in seconds for the upstream connection attempt. 0 means no timeout.
upstream_transport_config: Option<Arc<TransportConfig>>Optional QUIC transport parameters — flow-control windows, MTU, keep-alive, congestion control — applied to the upstream relay connection.
None leaves quinn’s defaults in place. Ignored for WebTransport
upstreams, which build their endpoint through wtransport.
Setting this and upstream_transport_profile is refused when
the session connects, with ProxyError::TransportConfigAndProfile
naming Leg::Upstream — see that variant for why the two cannot
be merged. The refusal stands on a WebTransport upstream too, where
both fields would have been ignored: a contradiction reported on one
transport and swallowed on the other is worse than either answer.
upstream_transport_profile: Option<TransportProfile>The same parameters as upstream_transport_config, as a value that
can be written down, checked and stored.
Some(_) builds the relay leg’s quinn::TransportConfig from this
profile — through upstream_installer, or through
crate::transport::DefaultInstaller when there is none — and
installs it before the endpoint is built and before anything is
dialled. A profile the installer refuses is
ProxyError::TransportProfile, and no connection is attempted.
None installs no profile: the leg then takes
upstream_transport_config if it names one, and quinn’s defaults
otherwise. It is the only alternative to that field, never a
companion to it. Neither field is installed on a WebTransport
upstream, which builds its endpoint through wtransport; the
refusals above are answered there all the same, before the
transport is dispatched on.
upstream_installer: Option<Arc<dyn TransportInstaller>>How upstream_transport_profile becomes the config the relay leg
installs.
None uses crate::transport::DefaultInstaller, which applies
the profile over a fresh quinn::TransportConfig::default(). Supply
one to start from a base of your own instead — the trait exists
because a quinn::TransportConfig cannot be cloned, so the only way
to have a base and a profile is to build the base again for each
leg.
Inert without a profile. TransportInstaller::build takes a
profile, so an installer set beside an empty
upstream_transport_profile is never called and the leg installs
nothing.
It composes with an upstream_qlog spec — named in plain code
font because that field exists only under the qlog feature, so a
link from this always-compiled one would not resolve. A leg carrying
a profile, a spec and an installer builds its config here, once, and
the capture sink is attached to what came back;
TransportInstaller::build returns an owned
quinn::TransportConfig precisely so that the two can stack.
upstream_socket: Option<Arc<dyn AsyncUdpSocket>>The socket every datagram of the upstream connection is sent on and received from.
None binds an ephemeral 0.0.0.0:0 socket. Some(_) builds the
upstream endpoint over the caller’s socket instead, so a decorating
implementation — a tap, a counter, a network-impairment shim — sees
and can alter the whole relay leg. Ownership is shared, so the
caller keeps its handle on the socket while the session runs, and
the relay sees the supplied socket’s address as this proxy’s.
This is the relay leg only. The client-facing leg is a separate endpoint over a separate socket, supplied — or not — when the listener is built.
§A WebTransport upstream cannot honour this
upstream_transport_config above is ignored for WebTransport
upstreams, because wtransport builds their endpoint. A socket is
not: it is refused. Connecting with
UpstreamTransportType::WebTransport and a socket set returns
ProxyError::UpstreamSocketUnsupported and connects to nothing.
The two are treated differently because the consequences of ignoring them are. A dropped transport config yields quinn’s defaults — a connection that works, with windows the caller did not pick. A dropped socket yields a relay leg that bypasses the caller’s shim entirely, so every impairment armed on it is reported by the shim and applied to nothing, and the run looks clean because it is clean. That failure is invisible from the outside, so it is made loud here instead.
§One socket, one session
Each session builds its own endpoint over the socket it is handed. Two endpoints reading one socket take each other’s datagrams — whichever polls first gets a packet, and a packet for a connection an endpoint does not own is discarded — so a socket shared across sessions running concurrently breaks all of them. Give concurrent sessions one socket each.
egress: EgressConfigEngine-side knobs for action execution — the per-stream deferred write queue’s byte budget and the ceiling on a hold.
Ignored when the hook’s crate::hook::ProxyHook::interest is
Interest::NONE: nothing is ever queued, so nothing reads them.
shape: Option<ShapeProfile>How this session’s media egress is shaped — named token buckets, the class rules that aim at them, one bounded-queue policy and the discipline that arbitrates between classes.
None is today’s behaviour exactly: no scheduler is constructed,
nothing extra is queued, and no deadline is armed.
Some(_) is configuration, not a hook capability, and that is
the whole point of the field: it arms framing on its own, with no
hook and no observer. A profile that only took effect when someone
also attached a hook would let a user configure 500 kbps, get a byte
pump, and read a successful run — which is the failure mode this
knob exists to make impossible. Conversely, attaching an observer
never arms shaping: see shaping_enabled on ForwardCtx.
Control streams are never shaped, on any path.
Implementations§
Source§impl ProxySessionConfig
impl ProxySessionConfig
Sourcepub fn upstream_alpn(&self, client_alpn: &[u8]) -> Vec<Vec<u8>>
pub fn upstream_alpn(&self, client_alpn: &[u8]) -> Vec<Vec<u8>>
Returns the ALPN protocol identifiers for the upstream connection.
For QUIC upstreams, mirrors the negotiated client ALPN so we connect
to the relay with the same protocol the client is speaking. Falls
back to self.draft.quic_alpn() if the client ALPN is empty
(e.g., the listener didn’t capture it).