networking

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 23, 2026 License: BSD-3-Clause Imports: 10 Imported by: 0

Documentation

Overview

Package networking drives the RESP codec over real connections. It owns the per-connection lifecycle: the accept loop, the input (query) buffer, the command parse-and-dispatch loop, the output buffer, and graceful shutdown. It interprets no command itself; a Handler is the seam the command-dispatch layer fills (doc 07 §5, doc 19 §3 and §4).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Addr is the TCP listen address ("host:port"); empty disables the TCP
	// listener. Use ":0" to let the OS pick a free port (handy in tests).
	Addr string
	// UnixSocket is the filesystem path for a Unix domain socket; empty disables
	// it. Unix connections bypass the protected-mode notion by construction.
	UnixSocket string
	// UnixSocketPerm is chmod'd onto the socket file right after bind.
	UnixSocketPerm os.FileMode
	// MaxClients caps simultaneous connections; 0 means unlimited. At the cap a
	// new connection is accepted, sent "-ERR max number of clients reached", and
	// closed, matching Redis's acceptCommonHandler.
	MaxClients int
	// MaxBulkLen caps a single bulk argument (proto-max-bulk-len). 0 selects
	// resp.DefaultMaxBulkLen.
	MaxBulkLen int64
	// QueryBufLimit caps the per-connection query buffer (client-query-buffer-limit).
	// 0 means no limit. A connection whose buffered, not yet parsed input grows past
	// it is closed.
	QueryBufLimit int64
	// IdleTimeout closes a connection after this much inactivity; 0 disables it.
	IdleTimeout time.Duration
	// TCPKeepAlive is the SetKeepAlivePeriod applied to accepted TCP sockets; 0
	// leaves the OS default and does not enable keepalive.
	TCPKeepAlive time.Duration
}

Config holds the listener and connection settings the server reads at start. The zero Config is usable: it listens on no address, so a caller must set at least Addr or UnixSocket. Defaults that match Redis are applied in New for the fields left zero.

type Conn

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

Conn is one client connection. Everything on it is touched by a single goroutine (the read loop), so the per-connection state needs no locking; only the cross-goroutine close path is atomic.

func NewOfflineConn

func NewOfflineConn() *Conn

NewOfflineConn builds a connection that is not backed by a socket. The command layer uses it to replay commands internally, such as loading a dataset from the AOF at startup, where the replies are not sent anywhere. Output is encoded into an in-memory buffer the caller never reads.

func (*Conn) CloseASAP

func (c *Conn) CloseASAP()

CloseASAP forces the connection shut from another goroutine (server shutdown or CLIENT KILL). It unblocks an in-progress socket read so the read loop observes the close and tears down.

func (*Conn) Closed

func (c *Conn) Closed() <-chan struct{}

Closed returns a channel that is closed when the connection is force-closed from another goroutine (server shutdown or CLIENT KILL). A blocking command selects on it so a parked client wakes instead of leaking its goroutine.

func (*Conn) Created

func (c *Conn) Created() time.Time

Created returns the time the connection was accepted.

func (*Conn) DB

func (c *Conn) DB() int

DB returns the currently selected logical database index.

func (*Conn) Deliver

func (c *Conn) Deliver(p []byte) error

Deliver writes a complete, pre-framed RESP value straight to the socket from another goroutine, the path a PUBLISH on one connection uses to push a message to a subscriber on another. It holds the write lock so it cannot interleave with the subscriber's own reply flush. A write to a closed socket returns an error the caller can ignore: the connection is going away anyway.

func (*Conn) Enc

func (c *Conn) Enc() *resp.Encoder

Enc returns the reply encoder bound to this connection's output buffer. It already carries the connection's protocol version, so a handler builds one logical reply and the encoder picks the RESP2 or RESP3 shape.

func (*Conn) ID

func (c *Conn) ID() uint64

ID returns the globally unique, never-reused connection id.

func (*Conn) IsOffline

func (c *Conn) IsOffline() bool

IsOffline reports whether the connection has no backing socket. The command layer uses it to know a command cannot truly block: a blocking command on an offline connection (a script's redis.call, the AOF replay) runs as its non-blocking equivalent instead of parking the goroutine forever.

func (*Conn) LastInteraction

func (c *Conn) LastInteraction() time.Time

LastInteraction returns the time of the most recent command on the connection.

func (*Conn) LocalAddr

func (c *Conn) LocalAddr() string

LocalAddr returns the server-side address the client connected to.

func (*Conn) Name

func (c *Conn) Name() string

Name returns the connection name set by CLIENT SETNAME.

func (*Conn) OutBytes

func (c *Conn) OutBytes() []byte

OutBytes returns the bytes accumulated in the output buffer. It is used by an offline connection (NewOfflineConn) to read back a command's reply, for example when a script's redis.call runs a command and needs its RESP reply.

func (*Conn) Proto

func (c *Conn) Proto() int

Proto reports the negotiated RESP version (2 or 3).

func (*Conn) Quit

func (c *Conn) Quit()

Quit asks the loop to flush the current output and then close the connection, the behaviour of the QUIT command. The reply already written stands.

func (*Conn) RemoteAddr

func (c *Conn) RemoteAddr() string

RemoteAddr returns the client address as "ip:port" or a Unix socket path.

func (*Conn) ResetOut

func (c *Conn) ResetOut()

ResetOut clears the output buffer. An offline connection reused across several commands calls this between them so each reply starts clean.

func (*Conn) Session

func (c *Conn) Session() any

Session returns the command-layer session object, or nil if none is attached.

func (*Conn) SetDB

func (c *Conn) SetDB(db int)

SetDB selects a logical database index, as SELECT does.

func (*Conn) SetName

func (c *Conn) SetName(name string)

SetName sets the connection name.

func (*Conn) SetProto

func (c *Conn) SetProto(proto int)

SetProto switches the RESP version, as HELLO does. The change takes effect for every reply encoded after this call.

func (*Conn) SetSession

func (c *Conn) SetSession(s any)

SetSession attaches the command-layer session object.

func (*Conn) TotCmds

func (c *Conn) TotCmds() uint64

TotCmds returns the number of commands processed on the connection.

func (*Conn) TotNetIn

func (c *Conn) TotNetIn() uint64

TotNetIn returns the total bytes read from the connection.

func (*Conn) TotNetOut

func (c *Conn) TotNetOut() uint64

TotNetOut returns the total bytes written to the connection.

func (*Conn) WriteRaw

func (c *Conn) WriteRaw(p []byte)

WriteRaw appends pre-framed bytes to the output buffer, the path for the pooled static replies in package resp. The bytes must be a complete, correctly framed RESP value.

type DisconnectHandler

type DisconnectHandler interface {
	OnDisconnect(c *Conn)
}

DisconnectHandler is an optional interface a Handler may implement to learn when a connection's read loop has exited, so it can drop any per-connection state it holds (pub/sub subscriptions, for one). It is called once per connection, from that connection's own goroutine.

type Handler

type Handler interface {
	Handle(c *Conn, argv [][]byte)
}

Handler processes one fully parsed client command. The argv slice holds the command name in argv[0] and its arguments after; the handler writes its reply through c.Enc (or c.WriteRaw for the pooled static replies). The networking layer never inspects argv; that is the dispatch layer's job.

argv and its backing bytes are owned by the connection only for the duration of the call. A handler that retains them past return must copy.

type HandlerFunc

type HandlerFunc func(c *Conn, argv [][]byte)

HandlerFunc adapts an ordinary function to Handler.

func (HandlerFunc) Handle

func (f HandlerFunc) Handle(c *Conn, argv [][]byte)

Handle calls f(c, argv).

type PanicHandler

type PanicHandler interface {
	OnPanic(cause any, stack []byte)
}

PanicHandler is an optional capability a Handler can implement to turn a panic in a command goroutine into a crash report. The serve loop recovers a panic, calls OnPanic with the cause and the goroutine stack, and the handler is expected to write the report and stop the process. If the handler is missing or returns, the serve loop re-panics so the crash stays fatal.

type Server

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

Server accepts connections on its listeners and runs one goroutine per connection. It owns the client registry and the graceful-shutdown path; it delegates every command to its Handler.

func New

func New(cfg Config, handler Handler) *Server

New builds a Server from cfg and the command handler. It does not open any socket; call ListenAndServe.

func (*Server) Addr

func (s *Server) Addr() net.Addr

Addr returns the address of the first TCP listener, useful when the config used ":0". It returns nil before ListenAndServe has bound a socket.

func (*Server) Close

func (s *Server) Close() error

Close stops accepting, force-closes every live connection so their read loops return, waits for them to finish, and removes the Unix socket file. It is safe to call once; a second call is a no-op.

func (*Server) ConnByID

func (s *Server) ConnByID(id uint64) *Conn

ConnByID returns the connection with the given id, or nil if none is live.

func (*Server) CountClients

func (s *Server) CountClients() int

CountClients returns the number of currently connected clients.

func (*Server) IdleTimeout

func (s *Server) IdleTimeout() time.Duration

IdleTimeout reports the current idle timeout. 0 means no timeout.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe(cfg Config) error

ListenAndServe opens the configured listeners and serves until Close. It returns nil on a clean Close and the bind error if a listener cannot open.

func (*Server) MaxBulkLen

func (s *Server) MaxBulkLen() int64

MaxBulkLen reports the current single-argument bulk cap.

func (*Server) QueryBufLimit

func (s *Server) QueryBufLimit() int64

QueryBufLimit reports the current per-connection query buffer cap. 0 means no limit.

func (*Server) SetIdleTimeout

func (s *Server) SetIdleTimeout(d time.Duration)

SetIdleTimeout changes the idle timeout. It takes effect on the next read on each connection, so CONFIG SET timeout applies without a restart.

func (*Server) SetMaxBulkLen

func (s *Server) SetMaxBulkLen(n int64)

SetMaxBulkLen changes the bulk cap. A zero or negative value resets it to the default, and the next parsed request uses the new limit, so CONFIG SET proto-max-bulk-len applies without a restart.

func (*Server) SetQueryBufLimit

func (s *Server) SetQueryBufLimit(n int64)

SetQueryBufLimit changes the query buffer cap. A zero or negative value clears it, and the next read on each connection uses the new value, so CONFIG SET client-query-buffer-limit applies without a restart.

func (*Server) SetTCPKeepAlive

func (s *Server) SetTCPKeepAlive(d time.Duration)

SetTCPKeepAlive changes the keepalive period. It applies to connections accepted after the change, the same as Redis.

func (*Server) Snapshot

func (s *Server) Snapshot() []*Conn

Snapshot returns the live connections at the moment of the call. The slice is a copy, so the caller can iterate without holding the registry lock, which is what CLIENT LIST needs.

func (*Server) TCPKeepAlive

func (s *Server) TCPKeepAlive() time.Duration

TCPKeepAlive reports the current keepalive period. 0 leaves the OS default.

Jump to

Keyboard shortcuts

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