redis/redis
Networking
Active contributors: antirez, Oran Agra, debing.sun, Yossi Gottlieb.
Purpose
The networking subsystem accepts TCP/Unix/TLS connections, parses RESP, dispatches commands, and writes replies back. It is the largest single chunk of code outside type implementations: src/networking.c is 5,783 lines and is on the hottest path of the server.
Source layout
| File | Role |
|---|---|
src/networking.c |
Client lifecycle: accept, query buffer, RESP parsing, output buffers, addReply* helpers. |
src/connection.c, src/connection.h |
Connection abstraction. connSocketType, connTLSType, connUnixType. |
src/socket.c |
TCP/IPv4/IPv6 specifics. |
src/unix.c |
Unix domain socket specifics. |
src/tls.c |
OpenSSL-backed TLS. Plug-in implementation of connection. |
src/anet.c, src/anet.h |
Low-level socket helpers (TCP, non-blocking I/O, getsockopt wrappers). Shared with redis-cli and redis-benchmark. |
src/resp_parser.c, src/resp_parser.h |
RESP2 + RESP3 byte-level parser. |
src/call_reply.c, src/call_reply.h |
Helpers for re-decoding a captured reply (used by modules and replication). |
src/logreqres.c |
When built with LOG_REQ_RES, captures every command and reply for schema validation. |
The client struct
struct client (declared in src/server.h, fields too numerous to list) is the runtime state for one connected peer. Notable fields:
| Field | Purpose |
|---|---|
conn |
The connection* (TCP/Unix/TLS). |
db |
Currently selected redisDb*. |
argv, argc |
Parsed command arguments (an array of robj*). |
cmd, lastcmd, realcmd |
The command being executed and the previous one. |
reqtype |
RESP type currently being parsed (inline / multi-bulk). |
multibulklen, bulklen |
Parser state — how many bulks remain, how big the next one is. |
querybuf |
The SDS that holds bytes received from this client. |
qb_pos |
The offset into querybuf consumed so far. |
reply |
A list of clientReplyBlocks holding outgoing bytes. |
bufpos, buf |
A small inline output buffer to avoid the list for short replies. |
flags |
Bitmask of CLIENT_* flags (CLIENT_BLOCKED, CLIENT_PUBSUB, CLIENT_TRACKING, CLIENT_MULTI, …). |
mstate |
If in MULTI, the queued commands. |
bstate |
If blocked, the kind of block and resume info. |
pubsub_* |
Subscribed channels/patterns, sharded channels. |
tracking_* |
Tracked keys for client-side caching. |
resp |
RESP version (2 or 3). |
id |
Monotonic client id used by CLIENT KILL ID. |
Clients are kept in server.clients (an adlist). Per-thread IO scratch lists are in server.io_threads_*. Replicas are in server.slaves. The master link client is server.master.
Accept path
sequenceDiagram
participant Kernel
participant Listener as listener fd
participant Accept as acceptTcpHandler
participant Client as struct client
Kernel->>Listener: SYN
Listener->>Accept: AE_READABLE
Accept->>Kernel: accept(2)
Kernel-->>Accept: connfd
Accept->>Client: createClient(conn)
Accept->>Client: connSetReadHandler(readQueryFromClient)
Note over Client: client added to server.clientsFor TLS, acceptTLSHandler does the same after wrapping the fd in an SSL object. For Unix sockets, acceptUnixHandler.
The number of listeners is configurable: TCP on bind addresses + port, optional TLS on tls-port, optional Unix on unixsocket. Each binds a separate listener fd and registers accept*Handler.
Read path
readQueryFromClient reads up to 16 KiB into the query buffer (chunked when IO threads are active to keep latency stable). Then processInputBuffer runs the RESP state machine:
while (c->qb_pos < sdslen(c->querybuf)) {
if (!c->reqtype) {
if (c->querybuf[c->qb_pos] == '*') c->reqtype = PROTO_REQ_MULTIBULK;
else c->reqtype = PROTO_REQ_INLINE;
}
if (c->reqtype == PROTO_REQ_INLINE) {
if (processInlineBuffer(c) != C_OK) break;
} else {
if (processMultibulkBuffer(c) != C_OK) break;
}
if (c->argc > 0) processCommandAndResetClient(c);
}Inline parsing handles the legacy line-based protocol (SET foo bar\r\n). Multi-bulk parsing handles the standard RESP form (*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n).
processCommandAndResetClient calls processCommand (in src/server.c), which runs the ACL check, cluster slot check, command lookup, and dispatches to c->cmd->proc(c).
Write path
Command implementations call addReply* helpers. They write into either c->buf (the 16 KiB inline buffer) or append a clientReplyBlock to c->reply. The fd is then registered as writable, and writeToClient drains both buffers in beforeSleep.
The output-buffer-limit subsystem (client-output-buffer-limit normal/replica/pubsub) caps the total size of c->reply. If a client exceeds the soft or hard limit, the connection is closed asynchronously.
For replicas the same path applies, but with a much larger limit and special handling: replica writes carry replication offsets that are tracked separately so the master knows how far each replica has caught up.
RESP versions
HELLO 2 (default) speaks RESP2 — the historical protocol. HELLO 3 upgrades to RESP3, which adds:
- Maps (
%), sets (~), big numbers ((), doubles (,), booleans (#), null (_), verbatim strings (=), attributes (|), pushes (>). - Push frames so the server can deliver invalidation messages without the client polling.
The encoder helpers (addReplyMap, addReplySet, addReplyArrayLen, …) auto-select between RESP2 and RESP3 based on c->resp. Some commands have explicitly different reply shapes in the two protocols (e.g. HGETALL returns an array in RESP2 and a map in RESP3); those branches in their handlers.
The parser is in src/resp_parser.c and is shared with the Lua reply re-decoder.
Connection abstraction
struct connection (declared in src/connection.h) is a thin vtable that hides socket-vs-TLS differences:
struct ConnectionType {
void (*ae_handler)(struct aeEventLoop *el, int fd, void *clientData, int mask);
int (*connect)(struct connection *conn, const char *addr, int port, ...);
int (*write)(struct connection *conn, const void *data, size_t len);
int (*read)(struct connection *conn, void *buf, size_t len);
int (*close)(struct connection *conn);
int (*set_write_handler)(struct connection *conn, ConnectionCallbackFunc handler, int barrier);
int (*set_read_handler)(struct connection *conn, ConnectionCallbackFunc handler);
/* ... many more ... */
};Three implementations:
- socket in
src/socket.c— TCP and IPv6. - unix in
src/unix.c— Unix domain. - tls in
src/tls.c— OpenSSL.
connTypeOfCluster returns the right type for the cluster bus (TLS or plain depending on tls-cluster).
TLS
src/tls.c implements the connection vtable using OpenSSL. It supports:
- Server-side TLS (clients connect with
--tls). - Client-side TLS for replication and cluster.
- TLSv1.2 and TLSv1.3, configurable cipher list, OCSP stapling.
- Optional client cert verification.
- Optional
tls-auth-clientsfor ACL+TLS hybrid authentication.
The TLS code can either be linked into redis-server (make BUILD_TLS=yes) or built as redis-tls.so (make BUILD_TLS=module) loaded with loadmodule. The module form is rare in production but is sometimes used in environments that ship a TLS-disabled binary by default.
Pub/Sub paths
The Pub/Sub state of a client (subscribed channels and patterns) lives on client. When a PUBLISH happens, the publisher's handler walks server.pubsub_channels (a dict of channel → list of subscribers) and calls addReplyPubsubMessage on each. Sharded Pub/Sub uses server.pubsubshard_channels and is per-slot; see Pub/Sub & tracking.
Where to start modifying
- Add a connection type (e.g. QUIC) — implement the vtable in a new file, register it in
src/connection.c'sconnTypeRegister*calls. - Tweak RESP parsing —
processMultibulkBuffer/processInlineBufferinsrc/networking.c. - Change accept behaviour —
acceptTcpHandler,acceptUnixHandler,acceptTLSHandlernear the top ofsrc/networking.c. - Tune output buffer accounting —
getClientOutputBufferMemoryUsageand theclient-output-buffer-limittable insrc/config.c.
Related pages
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.