transport

package
v0.1.0-proto2g Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: MPL-2.0 Imports: 18 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// ALPNGoblinRPC is the goblinctl/scheduler RPC channel.
	ALPNGoblinRPC = "goblin-rpc"
	// ALPNSerfQUIC carries Serf gossip over QUIC datagrams/streams.
	ALPNSerfQUIC = "serf-quic"
	// ALPNRaftQUIC carries the Raft transport stream.
	ALPNRaftQUIC = "raft-quic"
	// ALPNGoblinCkpt carries CRIU checkpoint images between nodes
	// during migration (GOBLIN-DIV-018). Deliberately its own ALPN, and
	// therefore its own QUIC connection: a multi-gigabyte image sharing
	// a connection-level flow-control window with Raft heartbeats would
	// degrade the control plane exactly when a migration is in flight.
	ALPNGoblinCkpt = "goblin-ckpt"
	// ALPNGapiQUIC is the kernel's protocol, imported - never redefined
	// - so the two repos cannot drift (consumes GAPI-DIV-011).
	ALPNGapiQUIC = gapitransport.ALPNGapiQUIC
)

ALPN protocol identifiers for the orchestrator's QUIC listeners and dialers. They mirror the ecosystem ALPN registry as their governing contract (append-only, tombstoned): a collision is a review failure, not a runtime discovery. Every handler and the ALPN router switch import these; inline literals are forbidden (GOBLIN-DIV-010).

View Source
const (
	// CodeALPNNotServing: the negotiated ALPN is in the registry and
	// NOTHING IS EVER GOING TO SERVE IT here - a tombstoned row, or a
	// plane this build does not carry. Not retryable.
	CodeALPNNotServing = quic.ApplicationErrorCode(0x100)
	// CodeAdapterBacklogged: the adapter's accept channel is full; the
	// connection is refused rather than stalling every other plane.
	CodeAdapterBacklogged = quic.ApplicationErrorCode(0x101)
	// CodeClusterNotReady: a CLUSTER ALPN arrived before the cluster
	// stack registered it - Phase 4 has not completed on this node.
	// RETRYABLE, and that is the entire reason it is a separate code
	// (GOBLIN-DIV-051).
	//
	// It used to share 0x100 with the case above, and the conflation was
	// not cosmetic. A joining peer that cannot tell "not yet" from
	// "never" must treat a transient phase skew as a hard join failure,
	// which is exactly what it did: node-2 dialling node-1 during the
	// window before node-1 registered serf-quic got a refusal it read as
	// fatal, gave up, and the cluster never formed a leader. That race
	// was intermittent and its signature was a placement timeout, which
	// is how it survived as an unexplained flake across three suites.
	CodeClusterNotReady = quic.ApplicationErrorCode(0x102)
)

QUIC application error codes the shared listener closes with. Named, never reused: a refused connection tells the peer exactly why.

Variables

This section is empty.

Functions

func GenerateInsecureSelfSignedCert

func GenerateInsecureSelfSignedCert() (tls.Certificate, error)

GenerateInsecureSelfSignedCert generates a self-signed cert for testing/insecure modes.

func IsClusterALPN

func IsClusterALPN(alpn string) bool

IsClusterALPN reports whether alpn is served only once the cluster stack exists.

func IsClusterNotReady

func IsClusterNotReady(err error) bool

IsClusterNotReady reports whether err is a peer's cluster-not-ready refusal - the retryable one.

It matches only the REMOTE close. A local application error with the same code would mean this node refused something, which is not a reason to redial anyone.

func RegistryALPNs

func RegistryALPNs() []string

RegistryALPNs returns the full ALPN registry the shared listener advertises; per-ALPN TLS policies (GetConfigForClient) must carry the same list or negotiation would silently narrow.

Types

type QUICConn

type QUICConn struct {
	*quic.Stream
	*quic.Conn
	// contains filtered or unexported fields
}

QUICConn adapts a QUIC stream to net.Conn

func (*QUICConn) Close

func (c *QUICConn) Close() error

func (*QUICConn) LocalAddr

func (c *QUICConn) LocalAddr() net.Addr

func (*QUICConn) Read

func (c *QUICConn) Read(b []byte) (n int, err error)

func (*QUICConn) RemoteAddr

func (c *QUICConn) RemoteAddr() net.Addr

func (*QUICConn) SetDeadline

func (c *QUICConn) SetDeadline(t time.Time) error

func (*QUICConn) SetReadDeadline

func (c *QUICConn) SetReadDeadline(t time.Time) error

func (*QUICConn) SetWriteDeadline

func (c *QUICConn) SetWriteDeadline(t time.Time) error

func (*QUICConn) Write

func (c *QUICConn) Write(b []byte) (n int, err error)

type QUICSerfTransport

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

QUICSerfTransport implements memberlist.Transport using QUIC. It uses QUIC Datagrams for packet-based gossip and QUIC Streams for reliable sync. It does not own a listener: inbound connections arrive from the shared control-plane listener's ALPN router (GOBLIN-DIV-023); only the dial side opens connections, offering exactly the serf-quic ALPN.

func NewRoutedQUICSerfTransport

func NewRoutedQUICSerfTransport(routed <-chan *quic.Conn, advertise net.Addr, tlsConf *tls.Config) (*QUICSerfTransport, error)

NewRoutedQUICSerfTransport builds the serf transport over routed connections. advertise is the node's single advertised control-plane address - it becomes the serf member address, so it must be dialable by peers.

func (*QUICSerfTransport) DialTimeout

func (t *QUICSerfTransport) DialTimeout(addr string, timeout time.Duration) (net.Conn, error)

DialTimeout creates a reliable stream connection to the given address.

func (*QUICSerfTransport) FinalAdvertiseAddr

func (t *QUICSerfTransport) FinalAdvertiseAddr(ip string, port int) (net.IP, int, error)

FinalAdvertiseAddr returns the address to advertise: the node's single control-plane address unless memberlist overrides it.

func (*QUICSerfTransport) PacketCh

func (t *QUICSerfTransport) PacketCh() <-chan *memberlist.Packet

PacketCh returns a channel for reading incoming packets.

func (*QUICSerfTransport) Shutdown

func (t *QUICSerfTransport) Shutdown() error

Shutdown closes the transport's dialed connections. The shared listener stays open - it belongs to the supervisor, not this adapter.

func (*QUICSerfTransport) StreamCh

func (t *QUICSerfTransport) StreamCh() <-chan net.Conn

StreamCh returns a channel for accepting incoming stream connections.

func (*QUICSerfTransport) WriteTo

func (t *QUICSerfTransport) WriteTo(b []byte, addr string) (time.Time, error)

WriteTo sends a packet to the given address (connectionless semantics). In QUIC, we use Datagrams on an established connection.

type QUICStreamLayer

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

QUICStreamLayer implements raft.StreamLayer over QUIC. It does not own a listener: inbound connections arrive from the shared control-plane listener's ALPN router (GOBLIN-DIV-023); only the dial side opens connections, offering exactly the raft-quic ALPN.

func NewRoutedQUICStreamLayer

func NewRoutedQUICStreamLayer(conns <-chan *quic.Conn, addr net.Addr, tlsConf *tls.Config) *QUICStreamLayer

NewRoutedQUICStreamLayer builds the raft stream layer over routed connections. addr is the node's single advertised control-plane address - it becomes this server's raft address, so it must be dialable by peers.

func (*QUICStreamLayer) Accept

func (l *QUICStreamLayer) Accept() (net.Conn, error)

Accept waits for the next routed raft-quic connection and surfaces its first stream as the raft net.Conn.

func (*QUICStreamLayer) Addr

func (l *QUICStreamLayer) Addr() net.Addr

Addr returns the advertised control-plane address.

func (*QUICStreamLayer) Close

func (l *QUICStreamLayer) Close() error

Close stops accepting routed connections. The shared listener stays open - it belongs to the supervisor, not this adapter.

func (*QUICStreamLayer) Dial

func (l *QUICStreamLayer) Dial(addr raft.ServerAddress, timeout time.Duration) (net.Conn, error)

Dial creates a new connection to the given address.

type SharedListener

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

SharedListener is goblind's single control-plane QUIC listener (GOBLIN-DIV-023): every protocol shares one bind address and is routed to its adapter by negotiated ALPN. Adapters attach with Register; a connection negotiating an ALPN with no attached adapter is refused at accept with CodeALPNNotServing - fail closed, which is also the phase-aware admission rule (cluster ALPNs are not served until the cluster stack registers them).

func NewSharedListener

func NewSharedListener(bindAddr string, tlsCfg *tls.Config, clusterReady func() bool) (*SharedListener, error)

NewSharedListener binds the control-plane address and starts the accept loop. The TLS config is cloned; its NextProtos are replaced with the full ALPN registry (datagrams are enabled - serf gossip requires RFC 9221 support end to end). clusterReady is required, not optional. It reports whether the cluster stack has registered its planes; the listener uses it to tell a peer "not yet" instead of "never" (GOBLIN-DIV-051). A nil predicate is a programming error rather than a default, because the default that would suit a test - always ready - is the answer that reintroduces the defect in production.

func (*SharedListener) Addr

func (l *SharedListener) Addr() net.Addr

Addr is the single advertised control-plane address.

func (*SharedListener) Close

func (l *SharedListener) Close() error

Close stops the accept loop and closes the listener.

func (*SharedListener) Register

func (l *SharedListener) Register(alpn string) (<-chan *quic.Conn, error)

Register attaches an adapter to an ALPN and returns its accept channel. Registering an ALPN twice, or one outside the registry, is a wiring bug and errors.

Jump to

Keyboard shortcuts

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