Documentation
¶
Overview ¶
Package server — adoption of listeners inherited from a supervisor.
Package server — the datagram batch-read abstraction.
Package server — compile-time interface assertions, kept out of the production source per KTN-IFACE-ASSERT-PLACEMENT.
Package server — the portable datagram reader.
Package server — the pooled stream connection.
Package server — compile-time interface assertions, kept out of the production source per KTN-IFACE-ASSERT-PLACEMENT.
Package server — the socket that holds its connection slot until it closes.
Package server — the completion state of one connection handed to net/http.
Package server — batch-reader selection on Linux.
Package server — batch-reader selection on platforms without recvmmsg.
Package server — every served socket family is left to the kernel here.
Package server — the two socket families Windows cannot open at all.
Package server — the bounded TLS handshake.
Package server — the net/http adapter.
Package server — the bounds only an HTTP group has.
Package server — the listener bridge that lets net/http consume our accepts.
Package server — the width-correct kernel length assignment.
Package server — the start, accept and drain lifecycle.
Package server — compile-time interface assertions, kept out of the production source per KTN-IFACE-ASSERT-PLACEMENT.
Package server — listener construction.
Package server — the listener that hands out close-tracking sockets.
Package server — a loop group's engine on Linux: the leaf's native backends, handed duplicated listener descriptors, or the portable backend.
Package server — a loop group's engine off Linux: the portable backend.
Package server — loop groups: HandleLoop, the options a loop group refuses at Start, its listeners and its engine in the server's lifecycle (ADR 0186).
Package server — the portable loop backend: the default engine's accept path and goroutines, every handler callback serialised onto one handler goroutine (ADR 0186 §D3, §D7).
Package server — the recvmmsg batched datagram reader.
Package server — the recvmmsg message header layout.
Package server — the functional options.
Package server — the pooled datagram.
Package server — a group of datagram listeners.
Package server — datagram listener construction and the read loop.
Package server — the datagram read loop.
Package server — per-connection state recycling.
Package server — the descriptor-bearing socket contract.
Package server — SO_REUSEPORT support on the BSD family.
Package server — SO_REUSEPORT support on Linux.
Package server — the SO_REUSEPORT floor for platforms without it.
Package server is the inbound half of the SDK's network domain (ADR 0029): one unified listener engine for TCP, Unix, TLS and mutual TLS, serving pluggable handlers grouped behind shared middlewares and policies.
Package server — kernel sockaddr decoding for the batched reader.
Package server — a group of listeners sharing one handler and policy.
Package server — the per-group connection ceiling.
Package server — deliberate discard of non-actionable cleanup errors.
Package server — how a Unix kernel reports a datagram longer than the read buffer: by truncating it, which is not an error at all.
Package server — how Windows reports a datagram longer than the read buffer.
Index ¶
- type Admission
- type AdmissionConfig
- type GroupOption
- func Adopt(names ...string) GroupOption
- func BatchSize(n int) GroupOption
- func Engine(e corenet.EngineValue) GroupOption
- func HandshakeTimeout(d time.Duration) GroupOption
- func IdleTimeout(d time.Duration) GroupOption
- func Listen(network, addr string) GroupOption
- func Loop(v corenet.LoopValue) GroupOption
- func MaxConns(n int) GroupOption
- func MaxHeaderBytes(n int) GroupOption
- func MaxPacketSize(n int) GroupOption
- func Name(name string) GroupOption
- func Plaintext() GroupOption
- func PreHandshake(a *Admission) GroupOption
- func ReadBufferSize(n int) GroupOption
- func ReadHeaderTimeout(d time.Duration) GroupOption
- func ReadTimeout(d time.Duration) GroupOption
- func Shards(n int) GroupOption
- func TLS(id corenet.IdentityValue) GroupOption
- func WriteTimeout(d time.Duration) GroupOption
- type Option
- type PacketGroup
- type Server
- func (s *Server) Close() error
- func (s *Server) Group(name string, opts ...GroupOption) *StreamGroup
- func (s *Server) PacketGroup(name string, opts ...GroupOption) *PacketGroup
- func (s *Server) RegisterHealth(h corehealth.Health) error
- func (s *Server) Serve(ctx context.Context) error
- func (s *Server) Shutdown(ctx context.Context) error
- func (s *Server) Start(ctx context.Context) error
- func (s *Server) State() corenet.StateValue
- type StreamGroup
- func (g *StreamGroup) Handle(h corenet.ConnHandler) *StreamGroup
- func (g *StreamGroup) HandleFunc(f corenet.ConnHandlerFunc) *StreamGroup
- func (g *StreamGroup) HandleHTTP(h http.Handler) *StreamGroup
- func (g *StreamGroup) HandleLoop(h corenet.LoopHandler) *StreamGroup
- func (g *StreamGroup) Name() string
- func (g *StreamGroup) Use(middlewares ...corenet.Middleware[corenet.ConnHandler]) *StreamGroup
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Admission ¶ added in v0.1.1
type Admission struct {
// contains filtered or unexported fields
}
Admission is the pre-handshake admission of ADR 0174 D2: a per-address budget of connections that have not completed their handshake, checked before any TLS byte is read, with a reserved budget for declared addresses so a flood from elsewhere never locks them out. It is safe for concurrent use, and shared by a StreamGroup (PreHandshake) and by any transport that runs its own listener.
func NewAdmission ¶ added in v0.1.1
func NewAdmission(cfg AdmissionConfig) *Admission
NewAdmission returns an admission with no reserved address.
func (*Admission) Admit ¶ added in v0.1.1
Admit counts a new connection from remote against its address's budget. It returns ok false, counted, when the budget is spent: the caller closes the connection before reading a byte. Otherwise release, idempotent, gives the slot back once the handshake completes or the connection ends.
func (*Admission) Refused ¶ added in v0.1.1
Refused counts the connections refused before their handshake.
func (*Admission) SetReserved ¶ added in v0.1.1
SetReserved replaces the reserved addresses. Each is a host or a host:port, resolved now; one that does not resolve is given no reserved budget, never an unkeyed one.
type AdmissionConfig ¶ added in v0.1.1
type AdmissionConfig struct {
// PerAddress caps the connections one IPv4 address, or one IPv6 /64, may
// hold before their handshake completes. Default 4.
PerAddress int
// Reserved is the budget of the addresses declared with SetReserved.
// Default 8.
Reserved int
}
AdmissionConfig parameterises NewAdmission. A zero budget is clamped to its default, never read as "unlimited" (ADR 0031, clamp half).
type GroupOption ¶
type GroupOption func(*StreamGroup)
GroupOption configures a StreamGroup.
func Adopt ¶
func Adopt(names ...string) GroupOption
Adopt takes over a socket inherited from a supervisor instead of binding one.
Socket activation is what makes a zero-downtime restart possible: the supervisor holds the bound socket across the exec, so no connection is lost and no bind races. The name is the one the unit file publishes in LISTEN_FDNAMES. Repeat the option to adopt several sockets into one group.
A named socket the supervisor did not pass is SocketAdoptFailed, never a silent fallback to binding: a service that quietly binds its own port has lost exactly the property activation exists to provide.
func BatchSize ¶
func BatchSize(n int) GroupOption
BatchSize sets how many datagrams one read attempts to collect. One disables batching explicitly; zero selects the platform default. Where the platform cannot batch, State reports the degradation rather than hiding it.
func Engine ¶ added in v0.26.18
func Engine(e corenet.EngineValue) GroupOption
Engine names the engine family the group runs on (ADR 0187): EngineGoroutine, one goroutine per connection, or EngineLoop, the loop engine; Loop then picks the loop's backend. The zero value, EngineAuto, lets the handler's type choose, which is what a group without the option does. An engine the group's handler cannot run on, or that another option contradicts — EngineGoroutine with Loop or HandleLoop, EngineLoop with Handle, HandleFunc or HandleHTTP or on a datagram group — fails Start with EngineUnsupported, and is never replaced by the other engine.
func HandshakeTimeout ¶
func HandshakeTimeout(d time.Duration) GroupOption
HandshakeTimeout bounds the TLS negotiation on a group's listeners.
Unset does NOT mean unbounded here, unlike the other three: the handshake is the phase a peer can stall before any handler exists to notice, so it falls back to the domain's default rather than to no bound at all.
func IdleTimeout ¶
func IdleTimeout(d time.Duration) GroupOption
IdleTimeout bounds how long a connection may sit with no traffic.
func Listen ¶
func Listen(network, addr string) GroupOption
Listen adds an address to a group. It is variadic-friendly by repetition: calling it twice binds two addresses to the same handler, which is how one service reaches both a TCP port and a Unix socket.
func Loop ¶ added in v0.26.13
func Loop(v corenet.LoopValue) GroupOption
Loop configures a group's loop engine (ADR 0186 §D5): its backend, its loops and rings, and its per-connection and pressure bounds. It is judged at Start, once the group's handler is known: a group served by HandleLoop runs on it, and a group served by Handle, HandleFunc or HandleHTTP refuses it with LoopOptionUnsupported, whichever order the declarations came in. A group with no handler fails with HandlerMissing instead, and one given a second handler with HandlerAlreadySet. A datagram group refuses it with LoopOptionUnsupported too. A group served by HandleLoop without it runs on the zero LoopValue.
func MaxConns ¶
func MaxConns(n int) GroupOption
MaxConns caps how many connections the group serves at once.
The budget is per group, not per socket: a group listening on a TCP port and a Unix socket, or sharded across several listeners, shares one ceiling — which is what an operator sizing a server actually means. Beyond it a connection is accepted and closed immediately with ConnLimitReached, because a refusal the peer can observe beats a timeout it cannot tell from a hang. Zero means no ceiling.
func MaxHeaderBytes ¶
func MaxHeaderBytes(n int) GroupOption
MaxHeaderBytes caps how many bytes net/http reads for one request's line and header fields. A request over the cap is answered 431 Request Header Fields Too Large and never reaches the handler.
Unset (or non-positive) keeps net/http's own default, 1 MiB (http.DefaultMaxHeaderBytes) — which was applying silently before this option existed. net/http reads a small fixed allowance past the cap before refusing, so the refusal happens a few kilobytes after n, not at the byte. It has no effect on a group that does not serve HTTP.
func MaxPacketSize ¶
func MaxPacketSize(n int) GroupOption
MaxPacketSize caps the datagram size a group accepts. A larger datagram is dropped and counted in State, never delivered as a truncated prefix.
func Name ¶ added in v0.26.18
func Name(name string) GroupOption
Name names the group in State, logs and errors (ADR 0187). On a group declared with an empty name it sets the name, which must then be unique like any other; on one declared with a name it must repeat it. An empty Name, or one that differs from a non-empty declared name, fails Start with GroupNameConflict.
func Plaintext ¶ added in v0.26.18
func Plaintext() GroupOption
Plaintext declares that the group serves no TLS (ADR 0187). Every engine honours it. A group given both Plaintext and TLS, in either order, fails Start with PlaintextWithTLS. It is not yet required of a plaintext group: the simple API will require it of every HTTP group without TLS.
func PreHandshake ¶ added in v0.1.1
func PreHandshake(a *Admission) GroupOption
PreHandshake puts the group's accepted connections under a, before any TLS byte is read (ADR 0174 D2).
func ReadBufferSize ¶
func ReadBufferSize(n int) GroupOption
ReadBufferSize sizes the per-connection scratch buffer handed to the handler.
func ReadHeaderTimeout ¶
func ReadHeaderTimeout(d time.Duration) GroupOption
ReadHeaderTimeout bounds the HEADER phase of an HTTP request on its own: the request line and the header fields must arrive within d of the connection becoming ready for a request, however long the read timeout lets the body take.
The header phase is the one a slowloris attack stalls — a few bytes a second, never finishing a line — and it is also the phase a legitimate client completes in milliseconds, so it deserves a far shorter bound than a read timeout sized for an upload. Unset (or non-positive) keeps what the group did before this option existed: the header phase is bounded by the read timeout. It has no effect on a group that does not serve HTTP.
func ReadTimeout ¶
func ReadTimeout(d time.Duration) GroupOption
ReadTimeout bounds one read from the peer. On an HTTP group it bounds each read of a request body, refreshed per read, the header phase unless ReadHeaderTimeout is set, and the wait for the next request unless IdleTimeout is.
func Shards ¶
func Shards(n int) GroupOption
Shards sets how many listeners to open on each of the group's addresses.
Several listeners on one address is what SO_REUSEPORT buys: the kernel load-balances incoming connections across them, so N accept loops never contend on one accept queue. Zero selects one per core; one disables sharding. Where the platform or the socket family cannot shard, the count collapses to one and State reports why rather than staying silent.
func TLS ¶
func TLS(id corenet.IdentityValue) GroupOption
TLS turns the group's listeners into TLS listeners, or mutual-TLS ones when the identity requires a client certificate. One option covers both, so the two cannot drift apart in configuration.
func WriteTimeout ¶
func WriteTimeout(d time.Duration) GroupOption
WriteTimeout bounds one write to the peer.
type Option ¶
type Option func(*Server)
Option configures a Server.
func WithDrainTimeout ¶
WithDrainTimeout bounds how long Shutdown waits for in-flight connections before closing them hard.
type PacketGroup ¶
type PacketGroup struct {
// contains filtered or unexported fields
}
PacketGroup is a set of datagram sockets sharing one handler, one middleware chain and one policy. It mirrors StreamGroup deliberately: the whole point of the domain is that a UDP service is wired the same way a TCP one is.
func (*PacketGroup) Handle ¶
func (g *PacketGroup) Handle(h corenet.PacketHandler) *PacketGroup
Handle sets the group's handler, replacing any previous one.
func (*PacketGroup) HandleFunc ¶
func (g *PacketGroup) HandleFunc(f corenet.PacketHandlerFunc) *PacketGroup
HandleFunc sets the group's handler from a plain function.
func (*PacketGroup) Use ¶
func (g *PacketGroup) Use(middlewares ...corenet.Middleware[corenet.PacketHandler]) *PacketGroup
Use appends middlewares, outermost first.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server owns a set of listener groups and their lifecycle.
It is safe for concurrent use. Declaration-time mistakes — a duplicate group name, an unusable address — are recorded and returned by Start rather than panicking or forcing an error check on every declaration, which is what keeps wiring a server down to a handful of readable lines.
func (*Server) Close ¶
Close releases every listener and severs every live connection immediately, without draining.
func (*Server) Group ¶
func (s *Server) Group(name string, opts ...GroupOption) *StreamGroup
Group declares a listener group and returns it for handler attachment.
It returns the group rather than (group, error) on purpose: a declaration error is recorded and surfaced by Start, so the common path stays a single chained expression instead of an error check per line.
func (*Server) PacketGroup ¶
func (s *Server) PacketGroup(name string, opts ...GroupOption) *PacketGroup
PacketGroup declares a datagram listener group and returns it for handler attachment. It mirrors Group deliberately: the point of the domain is that a UDP service is declared the same way a TCP one is.
func (*Server) RegisterHealth ¶ added in v0.26.20
func (s *Server) RegisterHealth(h corehealth.Health) error
RegisterHealth registers the server's readiness and liveness checks on h, both named "net/server" (ADR 0188). Readiness is built from State: ready while serving with no stalled loop group. Liveness fails once a loop group has stayed stalled for the stall grace, 30 seconds. A receive that never completes on a live ring is not watched.
func (*Server) Serve ¶
Serve starts the server and blocks until ctx is cancelled, then drains.
It is the one-call entry point: a caller that has nothing else to do on the main goroutine writes Serve and gets startup, blocking and graceful shutdown without assembling them. It also returns, after the same drain, once every ring of a loop group has been drained by its watchdog: LoopGroupStalled, naming the group (ADR 0188).
func (*Server) Shutdown ¶
Shutdown stops accepting and waits for in-flight connections to finish, severing what remains once ctx expires.
func (*Server) Start ¶
Start binds every group's listeners and begins accepting.
It returns once every listener is bound, so a caller that gets a nil error knows the ports are open — which is what makes a test able to dial immediately, and a supervisor able to report readiness honestly.
func (*Server) State ¶
func (s *Server) State() corenet.StateValue
State returns a snapshot of the server's lifecycle and listeners.
type StreamGroup ¶
type StreamGroup struct {
// contains filtered or unexported fields
}
StreamGroup is a set of listeners sharing one handler, one middleware chain and one policy. Grouping exists so a server can expose the same handler on a TCP port and a Unix socket — or two ports with different TLS identities — without the caller assembling the wiring twice.
func (*StreamGroup) Handle ¶
func (g *StreamGroup) Handle(h corenet.ConnHandler) *StreamGroup
Handle sets the group's handler. A group declares one handler, once: a second declaration on the same group — Handle, HandleFunc, HandleHTTP or HandleLoop, in any order — does not replace the first, and Start returns HandlerAlreadySet naming the group (ADR 0186 §D1).
func (*StreamGroup) HandleFunc ¶
func (g *StreamGroup) HandleFunc(f corenet.ConnHandlerFunc) *StreamGroup
HandleFunc sets the group's handler from a plain function. It exists because the overwhelmingly common case is one function, and making that case require a named type would be the papercut that decides whether the API feels light.
func (*StreamGroup) HandleHTTP ¶
func (g *StreamGroup) HandleHTTP(h http.Handler) *StreamGroup
HandleHTTP serves an http.Handler over this group's listeners.
The group keeps its own limits, TLS identity and drain; net/http only does the protocol. That split is ADR 0029 D3: reimplementing HTTP would mean owning request smuggling defences, HTTP/2 flow control and HPACK to lose, not gain, throughput.
func (*StreamGroup) HandleLoop ¶ added in v0.26.17
func (g *StreamGroup) HandleLoop(h corenet.LoopHandler) *StreamGroup
HandleLoop serves the group on the loop engine (ADR 0186): h is called on the loop's own thread for every connection of the group, with the bytes each one receives, instead of a goroutine per connection. It is opt-in, and plaintext only.
The group keeps the server's lifecycle — the bind, the adoption of inherited sockets, MaxConns, the drain, State — and Loop(v) sizes and places the engine: io_uring after a probe of the running kernel, then epoll, on Linux, and the portable backend, the default engine's accept path serialised onto one handler goroutine, everywhere else. Start refuses a loop group given TLS with LoopTLSUnsupported, one given Use or an option neither the engine (IdleTimeout, MaxConns, Adopt, Plaintext, Name, Engine) nor h, through LoopOptionHonourer, honours with LoopOptionUnsupported — an option given counts, its zero value included —, and an explicit backend the platform or the kernel cannot run with UnsupportedPlatform or LoopBackendUnavailable.
A callback of h runs on the loop's thread and must not block it: a blocking call stalls every connection of its loop. h is declared once, like every handler: a second declaration of any kind makes Start return HandlerAlreadySet.
func (*StreamGroup) Use ¶
func (g *StreamGroup) Use(middlewares ...corenet.Middleware[corenet.ConnHandler]) *StreamGroup
Use appends middlewares, outermost first.
Source Files
¶
- admission.go
- adopt.go
- batch.go
- batch_compliance.go
- batch_portable.go
- conn.go
- conn_compliance.go
- conn_tracked.go
- conn_waiter.go
- datagram_source_linux.go
- doc.go
- engine_option.go
- family_other.go
- handshake.go
- health.go
- http_adapter.go
- http_bounds.go
- http_listener.go
- http_read_deadline.go
- kernel_len_linux.go
- lifecycle.go
- linux_compliance.go
- listen.go
- listen_tracked.go
- loop_engine_linux.go
- loop_group.go
- loop_portable.go
- multireader_linux.go
- multireader_mmsghdr_linux.go
- operator.go
- option_set.go
- options.go
- packet.go
- packet_group.go
- packet_listen.go
- packet_loop.go
- platform.go
- platform_linux.go
- pool.go
- raw_conn_provider_linux.go
- reuseport_linux.go
- server.go
- sockaddr_linux.go
- stall.go
- stream_group.go
- stream_group_limiter.go
- swallow.go
- truncation_other.go