Skip to content

Configuration Reference

irrld edited this page Jul 30, 2026 · 6 revisions

Options are scoped the way Netty's are: options configure the thing you created, child_options configure each session a listener accepts. A client has no children, so its options are the session's.

void ConfigureServer() {
  ServerConfig config{"0.0.0.0", 25000, std::chrono::seconds(10),
                      ConnectionType::ZDT};

  // options: the listener itself
  config.options.max_connections = 4096;

  // child_options: every session the listener accepts
  config.child_options.common.idle_timeout = std::chrono::seconds(30);
  config.child_options.common.encryption = true;
  config.child_options.common.compression = CompressionType::Zstandard;
  config.child_options.common.compression_threshold = 128;
  config.child_options.common.send_queue_capacity = 1024;
  config.child_options.tcp.no_delay = true;
  config.child_options.zdt.max_datagrams_in_flight = 256;
  config.child_options.zdt.rto_min = std::chrono::milliseconds(50);
  config.child_options.zdt.mtu_ladder.Set({1492, 1200, 576});
}

void ConfigureClient() {
  // a client has no children, so its options are the session's
  ClientConfig config{"127.0.0.1", 25000, std::chrono::seconds(10),
                      ConnectionType::ZDT};
  config.options.common.idle_timeout = std::chrono::seconds(30);
  config.options.zdt.keepalive_interval = std::chrono::milliseconds(500);
}

They are plain structs, not a typed-key map: every option is known at compile time, so unset fields simply keep their defaults.

Config

Field Notes
server_ip / server_port Where to connect (client) or bind (server)
connection_timeout Give up on a connection attempt after this. Zero waits forever
connection_type ConnectionType::TCP or ConnectionType::ZDT
options Listener scope on a server; session scope on a client
child_options Server only: applied to each accepted session

CommonOptions

Applies to any session, whatever the transport.

Option Default Notes
idle_timeout 10 s Drop a session silent this long. Zero disables. TCP leaves this to the OS unless its transport implements one
collect_metrics true Ignored unless built with ZNET_ENABLE_METRICS
encryption true Read only on the accepting side. See Encryption and Compression
compression Default Resolved at session start to whatever the build supports
compression_threshold 128 B Below this, messages go uncompressed
send_queue_capacity 512 Packets a session holds for its worker to encode

send_queue_capacity

This is the backpressure knob. SendPacket returns false once the queue is full, which is how an application learns it is outrunning the link. A refusal loses nothing — you still hold the packet.

The queue is a ring allocated whole at construction, roughly 32 bytes a slot rounded up to a power of two, with no per-message allocation afterwards. Size it to the largest burst worth absorbing between two of the worker's ticks, not to the total you ever expect to send. A transport queues further messages behind its own congestion window, so this is not the whole picture.

TCPOptions

Option Default Notes
no_delay true Disables Nagle. Leave it on unless you are bulk-transferring
reuse_address true SO_REUSEADDR, so a restart can rebind a port in TIME_WAIT
send_buffer_size 0 Socket send buffer. Zero keeps the OS default
receive_buffer_size 0 Socket receive buffer. Zero keeps the OS default

ZDTOptions

Timing and retries

Option Default Notes
rto_min 100 ms Floor on the retransmit timeout, however low the measured RTT
rto_max 2000 ms Ceiling, including backoff
max_retries 10 Retransmits of one message before the connection is closed
keepalive_interval 1000 ms How often to ping an otherwise idle connection
idle_timeout 10 s Close a connection that has heard nothing this long

Lowering rto_min recovers from loss faster on a LAN. On the open internet it causes retransmits of packets that were merely late, which costs bandwidth and can push the congestion controller down.

Windows

Option Default Notes
max_datagrams_in_flight 512 Ceiling on the congestion window, in datagrams
cwnd 4096 Reliable messages allowed in flight. A memory bound, not congestion control

max_datagrams_in_flight is a bound, not the window. ZDT slow-starts from 10 datagrams and backs off on queueing delay rather than on loss; this caps how far it may grow. It counts datagrams, not bytes, so a half-full datagram costs as much as a full one. Bytes in flight are roughly this times the MTU per round trip, which is what governs throughput on a long link.

The two are separate because coalescing puts many messages in one datagram — holding cwnd near max_datagrams_in_flight would throttle small messages far below what the window actually allows.

Handshake and MTU

Option Default Notes
mtu_ladder 1492, 1200, 576 Candidates, probed largest first. Set with .Set({...}), max 4
handshake_retransmit 250 ms Wait for a reply before resending
handshake_retries_per_rung 4 Attempts at one MTU before stepping down

The settled MTU determines the largest message the connection can carry — see Choosing a Transport.

Limits and abuse protection

Option Default Notes
cookie_secret_rotation 120 s How often the server rotates its return-routability secret
max_half_open 1024 Concurrent half-open handshakes a server tracks
max_connections 4096 Established connections a server holds
per_source_handshake_rate 20/s Handshake messages accepted per source address
reassembly_timeout 5 s Discard a partial message after this
max_reassembly_bytes 16 MiB Ceiling on bytes held in partial reassemblies
max_inbox_datagrams 4096 Raw datagrams queued per connection before arrivals are dropped

Reaching max_reassembly_bytes refuses to start new messages rather than discarding data already accepted, so a peer stalls instead of losing anything.

ServerOptions

Listener scope: things that exist before any session does.

Option Default Notes
backlog 0 Pending-connection backlog. Zero uses SOMAXCONN. TCP only
max_connections 0 Cap on accepted connections. Zero means unlimited
reuse_address true SO_REUSEADDR on the listening socket

Note that ZDTOptions::max_connections and ServerOptions::max_connections are different settings: the ZDT one is enforced by the transport before a session exists, the listener one by the server.

Clone this wiki locally