Who knows whom
The links between layers are one-way and short.
Read the arrow as "references".
Transport and the packet layer sit side by side and know nothing of each other. Both rely on Primitives. Glue references both, and the application references glue.
Why this separation
Transport stays useful without generated packets. Proxies, sniffers, and custom protocol experiments need frames, compression, and encryption, but not the decoding of specific packets.
The packet layer, in turn, works without a network. It receives an
IncomingPacket
as input, and the source does not matter - a socket, a file, a test. This is why
packets and their per-version layouts are checked with round-trip tests, without
a server.
One non-obvious result
Typed sending (SendAsync<T>) lives in glue, not next to the packets. Otherwise
the packet layer would have to see transport, and the separation would break.
A handler is not a visitor
The packet layer offers two ways to decode an incoming packet: the
PacketFlow visitor
(synchronous Visit<T>) and the
ClientboundHandler
/
ServerboundHandler
handler (asynchronous On<Name>, returning ValueTask). Why these are separate
paths, not one built on top of the other, is covered in
Handlers and unknown packets.