TCP Transport
TCP-based transport for firewall-restricted environments, corporate networks, and cloud deployments without multicast support.
RTPS over TCP is not standardized and is HDDS-to-HDDS only. Each DDS vendor uses different framing. Use UDP for cross-vendor interop.
Overview
The TCP transport provides reliable, ordered delivery of RTPS messages over TCP connections. It is designed for environments where UDP is blocked, multicast is unavailable, or NAT traversal is required.
When to use TCP:
- Corporate firewalls with TCP-only policies
- Cloud/Kubernetes without multicast
- NAT traversal where UDP hole punching fails
- WAN connections with high packet loss
Configuration
TcpConfig
The main configuration struct controls all TCP transport behavior.
use hdds::transport::tcp::{TcpConfig, TcpRole};
// Basic: enable TCP with defaults
let config = TcpConfig::enabled();
// Custom configuration
let config = TcpConfig {
enabled: true,
listen_port: 7410,
role: TcpRole::Auto,
nodelay: true, // Disable Nagle (recommended for DDS)
max_message_size: 16 * 1024 * 1024, // 16 MB
..Default::default()
};
Configuration Options
| Option | Default | Description |
|---|---|---|
enabled | false | Enable TCP transport (opt-in) |
listen_port | 0 | TCP listen port (0 = ephemeral) |
listen_address | None | Bind address (None = all interfaces) |
role | Auto | Connection role (Auto, ServerOnly, ClientOnly) |
nodelay | true | Disable Nagle's algorithm |
max_message_size | 16 MB | Maximum RTPS message size (anti-OOM) |
connect_timeout | 5s | Outbound connection timeout |
reconnect_delay | 1s | Delay before reconnection attempt |
max_reconnect_attempts | 10 | Max reconnection attempts (0 = infinite) |
keepalive | true | Enable TCP keep-alive probes |
keepalive_interval | 30s | Keep-alive probe interval |
send_buffer_size | 256 KB | Application-level send buffer |
recv_buffer_size | 256 KB | Application-level receive buffer |
tls_enabled | false | Enable TLS encryption |
Builder Methods
use hdds::transport::tcp::{TcpConfig, TcpRole};
use std::time::Duration;
let config = TcpConfig::enabled()
.with_port(7410)
.with_role(TcpRole::Auto)
.with_nodelay(true)
.with_max_message_size(8 * 1024 * 1024) // 8 MB
.with_connect_timeout(Duration::from_secs(10))
.with_keepalive(true, Duration::from_secs(30));
TCP Roles
The TCP role controls connection behavior between participants.
| Role | Listen | Connect | Use Case |
|---|---|---|---|
Auto | Yes | Yes | Default. GUID tie-breaker ensures one connection per pair |
ServerOnly | Yes | No | Edge devices behind NAT, known server topology |
ClientOnly | No | Yes | Mobile/embedded clients, firewall blocks inbound |
use hdds::transport::tcp::{TcpConfig, TcpRole};
// Server: listen on port 7410, never initiate outbound connections
let server = TcpConfig::server_only(7410);
// Client: connect to known peers, never listen
let client = TcpConfig::client_only(vec![
"192.168.1.1:7410".parse().unwrap(),
"192.168.1.2:7410".parse().unwrap(),
]);
// TCP-only mode (no UDP discovery, requires initial_peers)
let tcp_only = TcpConfig::tcp_only(vec![
"192.168.1.1:7410".parse().unwrap(),
]);
In Auto mode, the participant with the "larger" GUID initiates the connection. This deterministic tie-breaking ensures exactly one TCP connection between any two participants, avoiding duplicate connections.
Transport Preferences
Control how TCP integrates with other transports.
| Preference | Discovery | Data | Description |
|---|---|---|---|
UdpOnly | UDP | UDP | Standard DDS (default) |
TcpOnly | TCP | TCP | No multicast, requires initial_peers |
UdpDiscoveryTcpData | UDP | TCP | Hybrid: multicast discovery, TCP data |
ShmPreferred | UDP | SHM/UDP | SHM local, UDP remote |
ShmLocalTcpRemote | UDP | SHM/TCP | SHM local, TCP remote |
use hdds::transport::tcp::TransportPreference;
// Hybrid mode: UDP multicast discovers peers, TCP for reliable data
let pref = TransportPreference::UdpDiscoveryTcpData;
// SHM for local processes, TCP for remote
let pref = TransportPreference::ShmLocalTcpRemote;
Initial Peers
For TCP-only mode or ClientOnly role, you must specify peers to bootstrap the mesh.
use hdds::transport::tcp::TcpConfig;
let config = TcpConfig::tcp_only(vec![
"10.0.0.1:7410".parse().unwrap(),
"10.0.0.2:7410".parse().unwrap(),
"10.0.0.3:7410".parse().unwrap(),
]);
TcpRole::ClientOnly requires at least one entry in initial_peers. The configuration will fail validation if initial_peers is empty.
TLS Encryption
TLS support requires the tcp-tls feature flag.
[dependencies]
hdds = { version = "0.1", features = ["tcp-tls"] }
Server-Side TLS
use hdds::transport::tcp::tls::TlsConfig;
let tls = TlsConfig::server()
.with_cert_file("server.crt")?
.with_key_file("server.key")?
.build()?;
Client-Side TLS
use hdds::transport::tcp::tls::TlsConfig;
// With system root certificates
let tls = TlsConfig::client()
.with_system_roots()
.build()?;
// With custom CA
let tls = TlsConfig::client()
.with_root_certs_file("ca.crt")?
.build()?;
Mutual TLS (mTLS)
use hdds::transport::tcp::tls::TlsConfig;
// Server requiring client certificates
let server_tls = TlsConfig::server()
.with_cert_file("server.crt")?
.with_key_file("server.key")?
.require_client_cert()
.build()?;
// Client with certificate for mTLS
let client_tls = TlsConfig::client()
.with_system_roots()
.with_cert_file("client.crt")?
.with_key_file("client.key")?
.build()?;
TLS Options
| Option | Default | Description |
|---|---|---|
verify_peer | true (client) / false (server) | Verify peer certificate |
require_client_cert | false | Require client certificate (mTLS) |
enable_session_resumption | true | TLS session ticket reuse |
min_protocol_version | TLS 1.2 | Minimum TLS version |
max_protocol_version | TLS 1.3 | Maximum TLS version |
alpn_protocols | ["dds"] | ALPN protocol negotiation |
dangerous_disable_verification() skips certificate verification entirely. Never use this in production -- it defeats the purpose of TLS.
TCP + TLS Configuration
use hdds::transport::tcp::TcpConfig;
let config = TcpConfig::enabled()
.with_port(7410)
.with_tls(true)
.with_tls_config(tls_config);
// Verify TLS is properly configured
assert!(config.is_tls_ready());
Wire Format
TCP is a stream protocol, so RTPS messages are length-prefixed:
+----------------+-------------------+
| Length (4B BE) | RTPS Message |
+----------------+-------------------+
Each frame starts with a 4-byte big-endian length field followed by the RTPS message payload. The maximum message size is controlled by max_message_size (default: 16 MB).
C API
The C FFI provides builder-style configuration for TCP transport.
#include <hdds.h>
// Create participant config
HddsParticipantConfig* cfg = hdds_config_create("my_app");
hdds_config_set_domain_id(cfg, 0);
// Enable TCP on port 7410 (sets hybrid mode by default)
hdds_config_enable_tcp(cfg, 7410);
// Set TCP role
hdds_config_set_tcp_role(cfg, HDDS_TCP_ROLE_AUTO);
// Add initial peers for TCP-only mode
hdds_config_add_tcp_peer(cfg, "192.168.1.1:7410");
hdds_config_add_tcp_peer(cfg, "192.168.1.2:7410");
// Disable Nagle's algorithm
hdds_config_set_tcp_nodelay(cfg, true);
// Enable TLS
hdds_config_enable_tls(cfg);
// Set transport preference
hdds_config_set_transport_preference(cfg, HDDS_TRANSPORT_PREF_TCP_ONLY);
// Build participant (consumes cfg)
HddsParticipant* p = hdds_config_build(cfg);
C Enums
// TCP roles
typedef enum {
HDDS_TCP_ROLE_AUTO = 0,
HDDS_TCP_ROLE_SERVER_ONLY = 1,
HDDS_TCP_ROLE_CLIENT_ONLY = 2,
} HddsTcpRole;
// Transport preferences
typedef enum {
HDDS_TRANSPORT_PREF_UDP_ONLY = 0,
HDDS_TRANSPORT_PREF_TCP_ONLY = 1,
HDDS_TRANSPORT_PREF_UDP_DISCOVERY_TCP_DATA = 2,
HDDS_TRANSPORT_PREF_SHM_PREFERRED = 3,
HDDS_TRANSPORT_PREF_SHM_LOCAL_TCP_REMOTE = 4,
} HddsTransportPreference;
Limitations
| Limitation | Description |
|---|---|
| HDDS-only | TCP framing is vendor-specific, not cross-vendor interoperable |
| No multicast | TCP cannot do multicast discovery; use UDP or initial_peers |
| Connection overhead | TCP requires per-peer connections (vs UDP broadcast) |
| Head-of-line blocking | Single TCP stream means one lost packet blocks all messages |
Next Steps
- Shared Memory Transport -- Zero-copy local IPC
- QUIC Transport -- Modern alternative to TCP
- Advanced Transport Features -- DSCP, filtering, TSN