Skip to content

Configuration Reference

In quicX, configuration is split into two layers: the QUIC transport layer and the HTTP/3 application layer. This separation lets you tune network behaviour at a very fine granularity — whether your goal is to squeeze out maximum throughput or to minimise idle resource usage on long-lived connections.

This document lists every configuration option in both layers, their default values, and when to change them.


If you use the pure QUIC API you operate directly on the structs below. If you use the HTTP/3 API the same structs are nested inside Http3Config::quic_config_ and Http3Settings.

1.1 QuicConfig: Global Runtime and Security

Section titled “1.1 QuicConfig: Global Runtime and Security”

This struct controls “global” behaviour: event loop, crypto, logging.

Field / TypeDefaultMeaning and tuning notes
thread_mode_
ThreadMode
kMultiThreadCore: Engine threading model.
- kSingleThread: Lowest latency on a single core, no lock contention.
- kMultiThread: For high-concurrency servers on multi-core CPUs. Incoming UDP packets are hashed across worker threads.
worker_thread_num_
uint16_t
2Number of worker threads in kMultiThread mode. Recommended: CPU cores - 1, leaving one core for the OS to handle network interrupts.
log_level_
LogLevel
kNullLog level. Silenced by default for maximum performance. Set to kInfo or kDebug while debugging.
quic_version_
uint32_t
kQuicVersion2Preferred protocol version to negotiate. Defaults to QUIC v2 (RFC 9369). You can manually downgrade to v1.
enable_0rtt_
bool
falsePerformance: When enabled, a returning client that holds a session ticket can send its first HTTP request before the handshake completes, saving 1 RTT. Ideal for stateless APIs (e.g. REST).
keylog_file_
std::string
""Critical debugging knob: When set to a file path, quicX writes the per-connection TLS secrets to that file. Combined with Wireshark this lets you decrypt and inspect the wire traffic.

1.2 QlogConfig: Network Tracing and Diagnostics

Section titled “1.2 QlogConfig: Network Tracing and Diagnostics”

Inside QuicConfig, qlog_config_ controls the in-kernel diagnostic tracer. When enabled, every frame is emitted as a structured log following RFC 9254 (consumable by qvis and Wireshark).

Field / TypeDefaultMeaning and tuning notes
enabled_falseEnable qlog collection. Because tracing has a noticeable throughput cost, only turn it on when chasing packet loss or congestion-control bugs.
output_dir_"./qlogs"Root directory for log files.
format_kSequentialFile format. Defaults to kSequential (JSON-Lines) so logs can be streamed to disk without buffering everything in memory.
batch_write_trueAsynchronous batched disk writes. Keep this on under production load — synchronous I/O would block the event loop.
flush_interval_ms_100When batch_write_ is on, the buffered logs are flushed to disk every N milliseconds.
max_file_size_mb_100Per-file size cap. Once exceeded, the file is rotated (so a runaway trace cannot fill the disk).
max_file_count_10Maximum number of rolled files retained; older files are deleted.

If you instantiate a server (IQuicServer or quicx::IServer), QuicServerConfig lets you configure quicX’s defensive moat. Per RFC 9000, Retry packets exist to defend against UDP source-address spoofing and amplification attacks.

FieldDefaultMeaning and tuning notes
retry_policy_SELECTIVEDefence policy:
- NEVER: Never send Retry (fastest; only safe in fully trusted internal environments).
- SELECTIVE (recommended): Dynamically enables address validation when new-connection rate spikes or a single IP gets noisy.
- ALWAYS: Force every connecting client to do an extra round-trip address validation (most secure, costs 1 RTT).
retry_token_lifetime_60 (seconds)Validity of the Retry token issued to a client to prove “the source address really is yours”.
selective_retry_config_.rate_threshold_1000(Used only in SELECTIVE mode) Global new-connection rate threshold (conn/sec). Once exceeded, Retry is enabled globally to scrub spoofed traffic.
selective_retry_config_.ip_rate_threshold_100(Used only in SELECTIVE mode) Per-IP rate threshold (conn/min). IPs above this rate are flagged and forced through Retry validation individually.

1.4 QuicTransportParams: Negotiated Transport Parameters

Section titled “1.4 QuicTransportParams: Negotiated Transport Parameters”

These values are packed into the TLS extension during the handshake and sent to the peer. They primarily control flow-control sliding windows.

[!WARNING] Make sure you understand QUIC’s two-level flow control. If you do not raise these limits, even a 10 Gbps link will be capped at kilobyte-level throughput because the peer will keep telling you “the window is full”.

FieldDefaultDetailed semantics
max_idle_timeout_ms_120000 (2 min)If no traffic (application packets or PING) is exchanged for this long, the connection is torn down. Increase for IoT devices that only chat occasionally.
initial_max_data_64 MBConnection-level flow control. Maximum cumulative bytes that can be sent across all streams before the peer must issue a MAX_DATA window update. Bottleneck #1 for large transfers.
initial_max_stream_data_bidi_local_16 MBPer-stream limit for locally-initiated bidirectional streams. Maximum bytes you can send on one stream before needing a window update. Bottleneck #2 for large transfers.
initial_max_streams_bidi_200Maximum number of bidirectional streams the peer is allowed to open concurrently (in HTTP/3 this maps to concurrent requests). High-fan-in microservice gateways may need 1000+.
ack_delay_exponent_ms_3ACK-delay multiplier used in RTT calculations. Don’t change unless you’re doing protocol research.
max_ack_delay_ms_25Upper bound on how long a receiver may defer an ACK. Larger values save a few packets but may cause the sender to mistake the delay for loss and trigger PTO prematurely.

QUIC’s signature feature, used to achieve true “lossless mobile network handover”.

FieldDefaultMeaning
enable_active_migration_true(Client) Active migration. When the client detects a local NIC change, it actively probes the new path with the existing Connection ID.
enable_nat_rebinding_true(Server) Passive NAT rebinding. When a client’s NAT mapping ages out (e.g. on 4G/5G or behind public Wi-Fi), the server transparently refreshes the mapping as long as the packets validate, instead of dropping the connection.
path_validation_timeout_ms_6000 (6 s)If the new path’s PATH_CHALLENGE / PATH_RESPONSE handshake does not complete within this time after the old path breaks, the connection is closed.

HTTP/3 settings live in Http3Config, Http3ServerConfig, and Http3ClientConfig. Because HTTP/3 requests ride on QUIC streams, these knobs are mostly about preventing the server from being overwhelmed by abusive clients.

Field / TypeDefaultApplication-layer tuning notes
max_concurrent_streams_
uint64_t
200Very important. The number of in-flight requests a single client may have outstanding against an HTTP/3 server. Once exceeded, additional requests are blocked. For microservice gateways or internal high-fan-in aggregators, push this above 1000.
connection_timeout_ms_
uint32_t
0 (never)(Client only) When IClient::DoRequest is dialing or sending and gets no response within this many milliseconds, the call fails. Typical public-internet values are 3000–5000.
FieldDefaultMeaning
enable_push_falseWhether to enable HTTP/3 Server Push (RFC 9114). When on, the server can use Response::AppendPush to push static assets (e.g. style.css, large images) the client did not explicitly request. May cause head-of-line contention under heavy load — currently considered experimental.
qpack_max_table_capacity4096Lives inside Http3Settings. Size of the QPACK header-compression dynamic table (RFC 9204). 0 keeps QPACK in pure-static mode (no extra memory, best perf); the default 4096 is a conservative interop-friendly value — raise it when your traffic carries large per-request headers (Trace IDs, large cookies) and you want to trade memory for bandwidth.

The QUIC stack collects detailed counters (loss, retransmissions, buffer occupancy, …). You can expose them via a built-in HTTP/3 endpoint:

quicx::Http3ServerConfig server_config;
server_config.metrics_.enable_ = true; // global metrics collection (on by default)
server_config.metrics_.http_enable_ = true; // built-in HTTP/3 metrics endpoint (off by default)
server_config.metrics_.http_path_ = "/metrics"; // endpoint path (default /metrics)
server_config.metrics_.http_port_ = 8828; // dedicated metrics port (default 8828)

After this is configured, your monitoring system can scrape /metrics directly to observe quicX runtime health (metrics are exported in Prometheus format; you can also pull them via Metrics::ExportPrometheus()).


3. Compile-Time Static Configuration (config.h)

Section titled “3. Compile-Time Static Configuration (config.h)”

In addition to runtime-tunable settings, a small set of low-level limits are baked in as C++ constexpr constants for performance and memory-alignment reasons. They live in the source tree and require a recompile to change.

If you need to deploy quicX on resource-constrained embedded devices, or on a top-end multi-10 GbE server, you may want to edit them before building:

3.1 HTTP/3 Compile-Time Constants (src/http3/config.h)

Section titled “3.1 HTTP/3 Compile-Time Constants (src/http3/config.h)”
ConstantDefaultMeaning
kMaxDataFramePayload1350Maximum payload size of a single HTTP/3 DATA frame handed to the transport. 1350 is sized to fit a 1500-byte MTU after subtracting IP / UDP / QUIC / AEAD-tag / H3 framing overhead.
kServerPushWaitTimeMs10How long (ms) the client will wait for a pushed stream from the server.
kClientConnectionTimeoutMs60000Idle timeout for the client-side HTTP/3 session (60 s).

3.2 QUIC Compile-Time Constants (src/quic/config.h)

Section titled “3.2 QUIC Compile-Time Constants (src/quic/config.h)”

The protocol’s core control-plane limits.

ConstantDefaultMeaning and tuning notes
Sliding window / congestion replenishment
kDataBlockedThreshold16384 (16 KB)When the sender’s remaining global send-window drops below this, it sends a DATA_BLOCKED frame to the peer.
kDataIncreaseThreshold512 * 1024 (512 KB)When the receiver’s available window falls below this, it sends a MAX_DATA frame (“you can keep sending”). On 10 GbE links you should multiply this so the sender never stalls.
kDataIncreaseAmount2 * 1024 * 1024 (2 MB)How much window credit a MAX_DATA update grants. Bulk file-transfer servers can safely raise this above 10 MB.
kStreamWindowIncrement2 * 1024 * 1024Per-stream window credit granted on a MAX_STREAM_DATA update.
Memory pools and packet defaults
kMaxFramePayload1420Maximum payload of a single generic QUIC frame.
kPacketPoolSize256Number of pre-allocated packet buffers in the memory pool. Keep it a power of two. Gateway / load-balancer nodes benefit from raising it to 1024 / 2048 to remove allocation jitter.
kPacketBufferSize1500Packet buffer size; sized to a typical Ethernet MTU. Do not raise this — going above MTU will cause IP fragmentation and tank throughput.
Handshake and protocol
kHandshakeTimeoutMs30000 (30 s)Hard upper bound on TLS handshake duration; protects against slowloris-style attacks. Aligned with the 30 s client timeout: under heavy-loss networks the PTO backoff (0.75s/1.5s/3s/6s/12s…) needs far more than 5 seconds of retries to get through.
TLS peer verification (runtime)
QuicClientConfig::verify_peer_trueNote: certificate verification is controlled by runtime config, not a compile-time constant. The client verifies TLS peer certificates by default; set to false for local self-signed testing, or pair with ca_file_ to pin a CA.

After editing any of these constants you must rerun cmake --build to rebuild the library — the changes only take effect after a recompile.