tcp

package
v0.2.39 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2026 License: MPL-2.0 Imports: 30 Imported by: 0

Documentation

Index

Constants

View Source
const EchoHandler = "echo"

EchoHandler is the example protocol handler: `;handler=echo`.

View Source
const LineHandler = "line"

LineHandler is the default handler: the newline-delimited protocol the head has always spoken.

View Source
const MAX_MESSAGE_SIZE = units.MB * 10

MAX_MESSAGE_SIZE is the longest line the head accepts. A longer line is consumed and dropped; the connection stays open.

Variables

View Source
var ErrRerouted = errors.New("rerouted")

ErrRerouted ends a connection whose route no longer stands: its inlet was deactivated, its hostname revoked or re-bound, its tenant removed.

Functions

func RegisterHandler added in v0.2.31

func RegisterHandler(name string, f HandlerFactory)

RegisterHandler adds a named protocol handler, selectable per listener with `;handler=NAME`. Called from init() in the handler's package. The name is load-bearing twice over: events the handler emits carry it as `@src`, and a hostname-routed connection enters `<stack>/_NAME`, so a stack opts into the protocol by declaring that inlet. A bad, reserved or duplicate name is a programming error and panics at init.

Types

type DeniedError added in v0.2.31

type DeniedError struct {
	Status int
	Reason string
}

DeniedError is the admission gate refusing one event (a suspended tenant, a rate limit). The handler says so in its protocol's words and closes.

func (*DeniedError) Error added in v0.2.31

func (e *DeniedError) Error() string

type Event added in v0.2.31

type Event struct {
	// Body is the raw protocol unit (a line, a frame) → `@client.body`,
	// base64. nil leaves the field off.
	Body []byte
	// Facts are the handler's parsed view of it → `@<src>.<key>`. A key may
	// be a dotted path. The line handler has none: `@tcp.*` is the head's.
	Facts map[string]any
}

Event is what a handler contributes to one run. The envelope's source is the handler's own name (`@src == "irc"` for a handler registered as "irc"; "tcp" for the line handler), its facts land under that name, and the connection's `@tcp.*` facts, `@client.ip` and the route ride along, chassis-stamped. A handler cannot write anywhere else in `_txc`.

type Handler added in v0.2.31

type Handler interface {
	ServeConn(ctx context.Context, rc RoutedConn) error
}

Handler speaks one protocol on a connection the head has already accepted. Everything before the first protocol byte is the head's: the accept gate and caps, the TLS handshake or the edge's PROXY header, the connect run that routes the connection and lets the stack refuse it, the per-tenant slot, drain. ServeConn gets the byte stream and the routing outcome, and turns protocol traffic into events with RoutedConn.Emit.

One Handler serves every connection on its listener, concurrently. ServeConn returns when the connection is finished — nil for an ordinary end (the peer hung up, the protocol said goodbye), an error naming why otherwise; the head logs it and closes the socket either way. ctx is cancelled at chassis shutdown, and the head closes the socket then too, so a blocked Read returns.

type HandlerFactory added in v0.2.31

type HandlerFactory func(pu *processor.Unit) Handler

HandlerFactory builds a listener's Handler at bind time.

type RouteResolver added in v0.2.31

type RouteResolver interface {
	ResolveErr(key ingress.RouteKey) (ingress.RouteTarget, bool, error)
}

RouteResolver is the data-plane resolver detect-tenant uses (ingress.DBResolver.ResolveErr); the head asks it whether a pinned connection's route still stands.

type RouteStamp added in v0.2.31

type RouteStamp struct {
	Tenant, Stack, Ingress string
	HostnameVerified       bool
}

RouteStamp is a connection's pinned route: what `_txc.route.*` carries on each of its events.

type RoutedConn added in v0.2.31

type RoutedConn struct {
	// Conn is the application byte stream: decrypted on a `;tls` listener,
	// past the PROXY header on a `;proxy=` one. The head closes it when
	// ServeConn returns.
	Conn net.Conn

	RID      string
	Listener string

	Tenant, Stack string // where the connect run routed the connection
	Host          string // @tcp.host — canonical; "" when routed by listener

	TLS              bool
	ALPN, TLSVersion string

	ClientIP              string
	RemotePort, LocalPort int

	// Route is the whole route the connect run promoted; Emit stamps it on
	// every later event.
	Route RouteStamp

	// Emit runs one event for this connection through the pipeline and
	// waits for the outcome. The event enters the stack the connection is
	// pinned to — the route is pre-stamped, not re-decided per event —
	// after the head has checked that route still stands; admission still
	// runs on every event. Any error means the connection is over:
	// ErrRerouted, a *DeniedError, a timeout, a failed run, shutdown.
	Emit func(ctx context.Context, ev Event) (event.DispatchResult, error)

	// AddFuel charges the connection for work the handler does itself,
	// outside any run — answering a keepalive, parsing, fan-out. The head
	// already charges the connect and every byte through Conn; all of it
	// is billed on the connection's next event (see meter). Costs follow
	// docs/advanced/fuel.md: 1 fuel ≈ 100µs of chassis work.
	AddFuel func(fuel int64)
}

RoutedConn is one accepted connection as a Handler sees it. Every field is the head's own observation or the bus loop's trusted routing outcome (event.DispatchResult) — a handler never parses identity out of an envelope, and never out of what the client sent.

type TCPController

type TCPController struct {
	// contains filtered or unexported fields
}

TCPController is the raw socket head. It owns every accepted net.Conn end to end: the accept loop admits it, the connect run through _sys/boot decides whether it stays open (and which tenant and stack it belongs to), and the listener's protocol Handler — by default the line handler, one bounded event per newline-terminated line — serves it until the stack hangs up, the peer goes quiet, or the chassis shuts down.

A `;tls` listener terminates TLS here and stamps the SNI hostname as `@tcp.host`, the connection's routing fact. A `;proxy=` listener sits behind an edge that already terminated TLS and fills the same fields from the edge's PROXY v2 header (chassis/edgeproxy), so a stack never sees which side did the handshake. Routing itself stays in `_sys/boot`: detect-tenant reads `@tcp.host`, route promotes it, and the head only learns the outcome (event.DispatchResult).

func NewController

func NewController(ctx context.Context, pu *processor.Unit) *TCPController

func (*TCPController) Addrs added in v0.2.31

func (tcp *TCPController) Addrs() []net.Addr

Addrs reports the bound addresses in --tcp-listen-addrs order, valid once Start has returned. Tests bind ":0" and read the port here.

func (*TCPController) SetResolver added in v0.2.31

func (tcp *TCPController) SetResolver(r RouteResolver)

SetResolver wires the resolver the head re-checks pinned routes with. Call before Start.

func (*TCPController) SetTLSConfig added in v0.2.31

func (tcp *TCPController) SetTLSConfig(t *tls.Config)

SetTLSConfig wires the managed certificate source for `;tls` listeners. Call before Start.

func (*TCPController) Start

func (tcp *TCPController) Start()

Start binds every --tcp-listen-addrs entry and starts an accept loop per listener. Binding happens synchronously so a port conflict is a clear Fatal before anything logs "started", and so Addrs() is valid the moment Start returns.

func (*TCPController) Stop

func (tcp *TCPController) Stop()

Stop closes the listeners, then every open connection, and waits for their handlers to unwind, bounded by --tcp-drain-timeout. The server has already run the in-flight drain and cancelled ctx by the time this is called, so any run still waiting on the bus is already unblocking.

func (*TCPController) WantsManagedTLS added in v0.2.31

func (tcp *TCPController) WantsManagedTLS() bool

WantsManagedTLS reports whether any listener needs the bundled cert manager (`;tls` without `;self-signed`), so the server can build it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL