pub(crate) struct ControlPlane {
client: Mutex<ClientLeg>,
upstream_transport: Mutex<Option<TransportProfile>>,
legs: LegSetup,
shape: ShapeControl,
stats: Arc<ProxyRecorder>,
sessions: Mutex<HashMap<SessionId, SessionHandle>>,
high_water: AtomicU64,
}Expand description
The state a ProxyControl reads, owned by the proxy and shared with
every handle it hands out.
One per TransparentProxy, never
process-global: session ids are minted from a counter on the proxy and
start again at 1 for each one, so two proxies in a process would collide
on every id in a shared table.
Fields§
§client: Mutex<ClientLeg>The client-facing leg: the listener once it exists, and the transport parameters a live request has installed on it.
One lock over both because the two have to move together. A request
arriving while run() is between binding the endpoint and publishing
it must not be dropped: it stores the parameters and finds no
listener, and the publish then installs them. Split across two locks
there is a window in which a request stores its parameters after the
publish has read them and before the listener is visible, and the
setting is accepted, reported as applied, and reaches nothing.
upstream_transport: Mutex<Option<TransportProfile>>The transport parameters a live request has set for the relay leg, or
None while the proxy’s own template is what every session dials
with.
legs: LegSetupThe two legs’ fixed facts, from the configuration the proxy was built with.
shape: ShapeControlThis proxy’s shaping profile and its pacing switch.
stats: Arc<ProxyRecorder>What every session this proxy accepts reports its shaping figures into, on top of its own.
Held here rather than on the [TransparentProxy] because this is
what a session is already handed: attach_control is the one call
that reaches every accepted session and no directly-driven one, which
is exactly the set whose traffic belongs in a proxy-wide total.
Constructed with the plane and never replaced, so it outlives every
session and a total taken from it never falls when one ends —
unlike Self::sessions, whose entries are released by a Drop.
sessions: Mutex<HashMap<SessionId, SessionHandle>>Every session that is running right now.
high_water: AtomicU64The highest id ever registered here.
The only trace a finished session leaves, and it exists to separate
ControlError::SessionEnded from ControlError::NoSuchSession.
Ids are minted monotonically from a counter on the proxy, so an id
at or below this one has run; anything above it has not. A set of
retired ids would answer the same question and would grow for the
life of the proxy.
0 before any session registers, and no session is ever SessionId(0).
Implementations§
Source§impl ControlPlane
impl ControlPlane
Sourcepub(crate) fn new(legs: LegSetup) -> Arc<Self> ⓘ
pub(crate) fn new(legs: LegSetup) -> Arc<Self> ⓘ
An empty control plane: nothing bound, no sessions.
Sourcepub(crate) fn publish_listener(
self: &Arc<Self>,
listener: Arc<Listener>,
) -> BoundGuard
pub(crate) fn publish_listener( self: &Arc<Self>, listener: Arc<Listener>, ) -> BoundGuard
Publish listener as this proxy’s bound endpoint, and hand back the
guard that un-publishes it.
A guard rather than a matching clear call because the accept loop
leaves by three routes — cancellation, a fatal listener error
propagated with ?, and the whole future being dropped by whoever
spawned it — and only one of them is a place a call could be
written.
Any transport parameters a request set before there was a listener are installed here, under the same lock the request took, which is what makes a request that arrives during the bind land on the endpoint rather than on nothing.
Sourcepub(crate) fn client_transport(&self) -> Option<Arc<TransportConfig>>
pub(crate) fn client_transport(&self) -> Option<Arc<TransportConfig>>
The transport parameters the client leg should bind with, or None
when no request has set any and the proxy’s template stands.
Sourcefn set_client_transport(&self, transport: Arc<TransportConfig>)
fn set_client_transport(&self, transport: Arc<TransportConfig>)
Install transport on the client leg, now if there is an endpoint
and at bind time if there is not.
Sourcepub(crate) fn upstream_transport(&self) -> Option<TransportProfile>
pub(crate) fn upstream_transport(&self) -> Option<TransportProfile>
The profile every session this proxy accepts from now on dials the
relay with, or None when the proxy’s template stands.
Sourcepub(crate) fn shape(&self) -> &ShapeControl
pub(crate) fn shape(&self) -> &ShapeControl
This proxy’s shaping profile and pacing switch, for a session to build its scheduler from and to watch.
Sourcepub(crate) fn stats_recorder(&self) -> Arc<ProxyRecorder> ⓘ
pub(crate) fn stats_recorder(&self) -> Arc<ProxyRecorder> ⓘ
The proxy-wide shaping counters, for a session to report into.
Handed out as an Arc clone rather than a borrow because the session
keeps it: its recorder forwards into this for the session’s whole
life, which outlives any borrow of the plane a call could hold.
Sourcefn build_transport(
&self,
leg: Leg,
profile: &TransportProfile,
) -> Result<Arc<TransportConfig>, ControlError>
fn build_transport( &self, leg: Leg, profile: &TransportProfile, ) -> Result<Arc<TransportConfig>, ControlError>
Turn profile into the config leg would install, refusing exactly
what a configured profile on that leg would be refused for.
Built through the leg’s own TransportInstaller when it has one,
so a caller who supplied an installer to start with gets the same
step here — a live request that quietly used the default installer
instead would produce a connection built differently from every one
the proxy made before it, with nothing saying so.
Source§impl ControlPlane
impl ControlPlane
Sourcepub(crate) fn register(
self: &Arc<Self>,
id: SessionId,
handle: SessionHandle,
) -> SessionGuard
pub(crate) fn register( self: &Arc<Self>, id: SessionId, handle: SessionHandle, ) -> SessionGuard
Register id as live, and hand back the guard that ends it.
See this module’s own documentation for why the removal is a Drop
and not a call on each of the session’s termination paths.
Sourcefn session(&self, id: SessionId) -> Option<SessionHandle>
fn session(&self, id: SessionId) -> Option<SessionHandle>
The handle for one live session, or None when it is not registered.
The only correct way to read the map: a caller that held the lock itself could still be holding it while it talked to the session.
Sourcefn reach(&self, id: SessionId) -> Result<SessionHandle, ControlError>
fn reach(&self, id: SessionId) -> Result<SessionHandle, ControlError>
The handle to act on id through, or the refusal that says why
there is none.
Three answers, and the third is the one worth stating: a session that is
registered but whose cancellation token has already fired is refused as
ended rather than acted on. It is going down and its tasks are
unwinding, so a request accepted there would be taken and then never
served — which is exactly the accepts a request and discards it
outcome this module refuses to have.