Skip to content

Experimental tunnel API for out-of-package network transports - #3152

Merged
mgravell merged 4 commits into
mainfrom
marc/tunnel-transport
Aug 3, 2026
Merged

Experimental tunnel API for out-of-package network transports#3152
mgravell merged 4 commits into
mainfrom
marc/tunnel-transport

Conversation

@mgravell

@mgravell mgravell commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

This is purely experimental work looking at SocketSet as a mechanism to potentially support io_uring, kTLS, and friends - without burying them in the core package for now.

Checklist

  • I fully and freely contribute this code in accordance with the project license (and am legally able to do so)
  • I take responsibility for this contribution's quality and correctness, including any portions produced with AI assistance (see CONTRIBUTING.md).

… (SER009, experimental)

The [Experimental] transport seam decided with Marc: a duplex byte-transport abstraction that is
deliberately NOT a Stream and NOT a pipe, plus a null-default virtual on Tunnel that supplies the ENTIRE
transport for a connection -- the same hijack as BeforeAuthenticateAsync one level deeper (no socket is
created at all), returning null for every existing tunnel.

The shape is derived from measured transport work rather than taste, and each member's derivation is in
its doc comment: any-thread copying writes with an explicit Flush (batching at the caller's natural
boundaries was the largest single lever measured), PUSH inbound with transport-owned spans (pull
adapters over a push transport measured 24-40%), and an OnBatchEnd notification (coalescing burst
responses into one flush eliminated a measured 3x send amplification). Abstract classes by design so
members can be added with safe defaults while experimental; receive-into-caller-buffer is deliberately
deferred to exactly that mechanism.

House ceremony: SER009 registered in Experiments, docs/exp/SER009.md, PublicAPI entries in both
projects with the [SER009] experimental prefix. A working SocketSet implementation of this shape
already exists and is gated across plaintext/TLS/@abstract surfaces (SocketSet repo,
src/SocketSet.StackExchange.Redis + bench/tunnel-selftest); it retargets to these types next.
…members abstract on the transport

With Flush on the transport, a separate .Output object never truly described output; the split was
inherited from IDuplexPipe, whose 3-object shape exists for independent Input/Output completion that
this contract does not have. GetMemory/GetSpan/Advance are now abstract members of DuplexTransport
itself, and passing the transport AS IBufferWriter<byte> grants stage-only access: the holder composes,
the owner flushes at its batch boundary.

TransportReceiver deliberately stays separate: it is the CONSUMER's half, and it must remain
abstract-class-evolvable on the net461/netstandard2.0 targets, where interfaces cannot grow.

Experimental (SER009), so this is a free change; PublicAPI entries updated to match. Implementation
side re-gated ALL PASS across plaintext/TLS/@abstract before this landed.
… abstract

GetMemory is the one true abstract of the writer face; GetSpan defaults to GetMemory(sizeHint).Span,
so an implementer owes exactly one buffer-acquisition member. Transports with a genuinely cheaper span
path (the SocketSet implementation forwards to its connection's own GetSpan) override it -- nice if
they do, correct if they don't.
The seam is public only because a seam must be public to be implemented; the doc now says so, spells
out that no stability of any kind is implied (members, semantics, name, home, existence -- any version,
no ceremony), and frames suppressing the diagnostic as accepting exactly that. If a generally useful
transport seam emerges it gets stabilised deliberately, not by this surface quietly hardening.
@mgravell
mgravell merged commit 74d3921 into main Aug 3, 2026
5 checks passed
@mgravell
mgravell deleted the marc/tunnel-transport branch August 3, 2026 13:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant