Skip to main content

QUIC Transport

QUIC-based transport for modern, secure, NAT-friendly communication with built-in TLS 1.3 and connection migration.

Experimental

QUIC transport is experimental and requires the quic feature flag. The API may change in future releases. It is HDDS-to-HDDS only (not standardized for DDS interop).

Overview

QUIC provides a modern alternative to TCP for DDS communication. Built on UDP with mandatory TLS 1.3, it offers connection migration, multiplexed streams, and 0-RTT reconnection -- features particularly useful for mobile/IoT devices and cloud deployments.

When to use QUIC:

  • Mobile/roaming devices (IP changes frequently)
  • Cloud deployments behind NAT
  • IoT devices on cellular networks
  • Cross-datacenter communication
  • Firewall-restricted environments

When NOT to use QUIC:

  • Multicast discovery (use UDP)
  • Cross-vendor DDS interop (QUIC not standardized for DDS)
  • Ultra-low latency requirements (< 100 us)

Feature Flag

QUIC transport requires the quic feature:

[dependencies]
hdds = { version = "0.1", features = ["quic"] }

Without this feature, QUIC types are not available at compile time.

Configuration

QuicConfig

use hdds::transport::quic::QuicConfig;
use std::time::Duration;

let config = QuicConfig::builder()
.bind_addr("0.0.0.0:7400".parse().unwrap())
.server_name("my-dds-cluster.local")
.enable_0rtt(true)
.idle_timeout(Duration::from_secs(30))
.max_concurrent_streams(100)
.enable_migration(true)
.build();

Configuration Options

OptionDefaultDescription
bind_addr0.0.0.0:0Local bind address (0 = auto-assign port)
server_name"hdds.local"TLS SNI server name
enable_0rtttrueFast reconnection to known peers
keep_alive_interval15sNAT binding maintenance interval
idle_timeout30sConnection idle timeout
max_concurrent_streams100Streams per connection
max_recv_window1 MBMaximum receive window size
enable_migrationtrueAllow connection migration on IP change
dangerous_skip_verifyfalseSkip TLS certificate verification

Reconnection Settings

QUIC supports automatic reconnection with exponential backoff.

OptionDefaultDescription
reconnect_enabledtrueAuto-reconnect on connection drop
reconnect_max_attemptsNone (infinite)Max retry attempts
reconnect_base_delay1sInitial backoff delay
reconnect_max_delay60sMaximum backoff delay cap
use hdds::transport::quic::QuicConfig;
use std::time::Duration;

let config = QuicConfig::builder()
.reconnect_enabled(true)
.reconnect_max_attempts(Some(10))
.reconnect_base_delay(Duration::from_millis(500))
.reconnect_max_delay(Duration::from_secs(30))
.build();

TLS Certificates

By default, QUIC generates self-signed certificates automatically. For production deployments, provide custom certificates.

use hdds::transport::quic::QuicConfig;

let config = QuicConfig::builder()
.certificate(include_str!("cert.pem"))
.private_key(include_str!("key.pem"))
.build();
Testing Only

dangerous_skip_verify() disables all TLS certificate verification. Never use in production.

Connection Migration

QUIC automatically handles IP address changes without dropping the connection. This is transparent to the application.

Device moves from WiFi to cellular:
IP changes from 192.168.1.50 to 10.0.0.50
QUIC connection continues without interruption

Connection migration is enabled by default (enable_migration: true).

0-RTT Reconnection

When enable_0rtt is enabled, QUIC caches session tickets for known peers. Subsequent connections complete instantly (0-RTT) instead of requiring a full handshake.

0-RTT Security

0-RTT data can be replayed by attackers. HDDS only uses 0-RTT for idempotent discovery messages, not user data.

Wire Format

QUIC uses the same length-prefixed wire format as TCP:

+----------------+-------------------+
| Length (4B BE) | RTPS Message |
+----------------+-------------------+

Maximum message size: 16 MB (MAX_QUIC_MESSAGE_SIZE).

Connection States

QUIC connections go through the following states:

StateDescription
ConnectingTLS handshake in progress
ConnectedActive, sending/receiving data
DrainingGraceful shutdown in progress
ClosedConnection terminated

QUIC vs TCP vs UDP

FeatureUDPTCPQUIC
NAT traversalGoodPoorExcellent
Firewall friendlyVariesGoodGood (UDP 443)
Connection migrationNoNoYes
Built-in encryptionNoOptionalMandatory (TLS 1.3)
0-RTT reconnectionN/ANoYes
Head-of-line blockingNoYesNo
MulticastYesNoNo
Multiplexed streamsN/ANoYes

Hybrid Configuration

Combine UDP for multicast discovery with QUIC for data exchange:

use hdds::{Participant, TransportMode};
use hdds::transport::quic::QuicConfig;

let quic_config = QuicConfig::builder()
.bind_addr("0.0.0.0:7401".parse().unwrap())
.enable_0rtt(true)
.build();

let participant = Participant::builder("app")
.domain_id(0)
.with_transport(TransportMode::UdpMulticast) // Discovery
.with_quic_transport(quic_config) // User data
.build()?;

Known Limitations

LimitationDescription
ExperimentalAPI may change in future releases
Feature-gatedRequires quic feature flag at compile time
No multicastCannot do multicast discovery; combine with UDP
HDDS-onlyNot cross-vendor interoperable
No C FFIQUIC is not yet exposed in the C API
quinn dependencyAdds the quinn crate and its transitive dependencies

Next Steps