ZeroDDS-TCP-Transport 1.0 — Spec Coverage
A ZeroDDS-vendor-specific TCP transport spec. Analogous to Cyclone’s
ddsi_tcp, FastDDS TCPv4 and RTI DDS TCP. Not OMG-normative.
Implementation:
crates/transport-tcp/· docs.rs — TCP transport (length-prefix framing + 16-byte handshake).
| Spec family | Status |
|---|---|
| OMG-normative | DDSI-RTPS 2.5 §9.4 (locator kind) + §9.5 (wire mapping) — fully covered; see ddsi-rtps-2.5.md section 9.4/9.5 |
| ZeroDDS-own spec | length-prefix framing + 16-byte handshake — zerodds-tcp-transport-1.0.md |
§1 Scope and spec status
§1.1 What OMG standardizes
For TCP, DDSI-RTPS 2.5 standardizes only:
- §9.4.5 LocatorKind:
LOCATOR_KIND_TCPv4 = 4,LOCATOR_KIND_TCPv6 = 8. - §9.5 wire mapping: the RTPS message format (RTPS header + submessages) is identical to the UDP PSM. TCP adds stream framing, which the spec does not further standardize.
ZeroDDS implementation:
crates/rtps/src/wire_types.rs· docs.rs — LocatorKind constants.crates/transport-tcp/src/framing.rs· docs.rs — RTPS-frame mapping onto the stream.
§1.2 What OMG does not standardize
- Handshake / BindConnection: there is no OMG standard for TCP
connection bring-up. Vendors have their own formats:
- Cyclone DDS: no handshake; raw RTPS frames with a length prefix.
- FastDDS: BindConnectionRequest/Response as RTPS submessages
0x71/0x72(vendor-specific). - RTI DDS: a TLS-oriented handshake (vendor-specific).
- Logical-port multiplexing: vendor-specific.
- Connection-pool reuse policies: not spec-relevant.
§1.3 ZeroDDS choice
The ZeroDDS TCP transport defines its own spec (this file) for the bring-up handshake. The spec is:
- OMG-conformant at the locator + wire-frame level (§9.4+§9.5).
- Vendor-specific at the handshake level (analogous to Cyclone/FastDDS/RTI).
- Cross-vendor-capable with Cyclone via a handshake-skip mode.
§2 Wire format
§2.1 Length-prefix frame (DDSI-RTPS §9.5-conformant)
Each RTPS datagram is framed over TCP as follows:
+---------+---------+---------+---------+
| length (u32, big-endian) | frame length in bytes (excl. the header itself)
+---------+---------+---------+---------+
| RTPS frame body (length bytes) | as in the UDP PSM
+---------+---------+---------+---------+
- length field: 4 bytes big-endian.
- RTPS frame body: a complete RTPS message (RTPS header + submessages), identical to the UDP PSM (DDSI-RTPS §9.5).
Repo anchors: crates/transport-tcp/src/framing.rs::encode_frame,
decode_frame. Tests: crates/transport-tcp/src/framing.rs::tests.
§2.2 Maximum frame size
Default: 64 MiB. The receiver MUST reject frames > limit (DoS protection).
Repo anchor: MAX_FRAME_SIZE in framing.rs.
§3 Handshake (ZeroDDS-specific)
§3.1 BindConnectionRequest (16 bytes, big-endian)
+---------+---------+---------+---------+
| 'Z' | 'D' | 'D' | 'S' | magic "ZDDS"
+---------+---------+---------+---------+
| v_major | v_minor | vendor_id (2 B) | protocol version + vendor id
+---------+---------+---------+---------+
| flags (u32) | reserved, = 0
+---------+---------+---------+---------+
| logical_port (u32) | DDS endpoint logical port
+---------+---------+---------+---------+
- Magic
"ZDDS"— does not collide with the RTPS magic"RTPS", the HTTP magic"HTTP", or a TLS ClientHello — an immediate discriminator. - Version: currently
(1,0). - VendorId: ZeroDDS =
[0x01, 0x0F]. - Flags: reserved, MUST be
0. - LogicalPort: u32;
0= “no claim”.
Repo anchors: handshake.rs::BindConnectionRequest,
encode_request, decode_request.
§3.2 BindConnectionResponse (16 bytes, big-endian)
+---------+---------+---------+---------+
| 'Z' | 'D' | 'A' | status | magic "ZDA" + accept/reject
+---------+---------+---------+---------+
| v_major | v_minor | vendor_id (2 B) | server version + vendor id
+---------+---------+---------+---------+
| flags (u32) | reserved, = 0
+---------+---------+---------+---------+
| reason_code (u32) | 0 on accept, otherwise per §3.3
+---------+---------+---------+---------+
- status byte:
0x2B('+') — accept0x2D('-') — reject
Repo anchors: handshake.rs::BindConnectionResponse,
encode_response, decode_response.
§3.3 Reject reason codes
| Code | Constant | Meaning |
|---|---|---|
| 0 | Unknown |
unclassified reject |
| 1 | VersionMismatch |
peer version outside the accepted window |
| 2 | ResourceLimit |
server has reached MAX_PEERS |
| 3 | LogicalPortConflict |
port already bound |
| 4 | VendorNotAccepted |
vendor policy rejects the vendor id |
Repo anchor: handshake.rs::RejectReason.
§3.4 Sequence
Client Server
| |
|-- BindConnectionRequest (16 B) --------->| §3.1
| | verifies version + magic
|<--- BindConnectionResponse (16 B) -------| §3.2
| |
|-- length-prefix frame [RTPS] ----------->| §2.1
|<-- length-prefix frame [RTPS] -----------|
| ... |
On reject both sides drop the connection. The client side should apply
backoff (see the connection pool in tcp_transport.rs).
§4 Cyclone ddsi_tcp compatibility
Cyclone DDS speaks raw RTPS frames over TCP without a handshake. ZeroDDS supports this mode via handshake skip:
- Client side:
TcpTransport::without_handshake()skips §3 and sends §2.1 length-prefix frames directly. - Server side: detects Cyclone mode when the first byte of the frame body is
not
'Z'(no ZeroDDS handshake magic) but'R'(the first byte of the RTPS magic), if the auto-detect feature is enabled.
Repo anchor: tcp_transport.rs::TcpTransport::without_handshake.
§5 Connection pool
Not spec-relevant; an implementation detail. The pool provides connection reuse, backoff and a MAX_PEERS cap.
Repo anchors: tcp_transport.rs::TcpTransport,
tcp_transport.rs::ConnectionPool.
§6 Cross-vendor extension points (optional)
Planned as optional feature flags for future releases, not an RC1 requirement (no normative spec):
feature = "fastdds-compat": BindConnectionRequest/Response as RTPS submessages0x71/0x72(FastDDS format).feature = "rti-compat": a TLS-oriented handshake (RTI format).
The extension would extend §3, not replace it — the ZeroDDS-own handshake stays the default.
§7 Test coverage
| Spec section | Tests |
|---|---|
| §2.1 length-prefix frame | framing.rs::tests (8 tests) |
| §2.2 max frame size | framing.rs::tests::frame_size_limit |
| §3.1 BindConnectionRequest | handshake.rs::tests::request_* |
| §3.2 BindConnectionResponse | handshake.rs::tests::response_* |
| §3.3 reject reasons | handshake.rs::tests::reject_reason_* |
| §3.4 handshake sequence | handshake.rs::tests::client_server_* |
| §4 Cyclone compat | tests/loopback.rs::cyclone_compat_* |
| §5 connection pool | tcp_transport.rs::tests::pool_* |
Total: 50 tests (lib) + 5 tests (integration). All green as of the audit date.
§8 Status
Fully covered. The ZeroDDS TCP transport is a complete, internally coherent spec; all § sections are implemented and tested. The cross-vendor extension points (§6) are marked optional.
ZeroDDS-TCP-Transport 1.0 — Spec-Coverage
ZeroDDS-vendor-spezifische TCP-Transport-Spec. Analog zu Cyclone’s
ddsi_tcp, FastDDS-TCPv4 und RTI-DDS-TCP. Nicht OMG-normativ.
Implementation:
crates/transport-tcp/· docs.rs — TCP-Transport (Length-Prefix-Framing + 16-Byte-Handshake).
| Spec-Family | Status |
|---|---|
| OMG-normativ | DDSI-RTPS 2.5 §9.4 (Locator-Kind) + §9.5 (Wire-Mapping) — voll abgedeckt; siehe ddsi-rtps-2.5.md Sektion 9.4/9.5 |
| ZeroDDS-eigene Spec | Length-Prefix-Framing + 16-Byte-Handshake — zerodds-tcp-transport-1.0.md |
§1 Scope und Spec-Status
§1.1 Was OMG normiert
DDSI-RTPS 2.5 normiert für TCP nur:
- §9.4.5 LocatorKind:
LOCATOR_KIND_TCPv4 = 4,LOCATOR_KIND_TCPv6 = 8. - §9.5 Wire-Mapping: RTPS-Message-Format (RTPS-Header + Submessages) ist identisch zum UDP-PSM. TCP fügt Stream-Framing hinzu, das die Spec nicht weiter normiert.
ZeroDDS-Implementation:
crates/rtps/src/wire_types.rs· docs.rs — LocatorKind-Konstanten.crates/transport-tcp/src/framing.rs· docs.rs — RTPS-Frame-Mapping auf Stream.
§1.2 Was OMG nicht normiert
- Handshake / BindConnection: Es existiert kein OMG-Standard für
TCP-Connection-Bring-up. Vendoren haben eigene Formate:
- Cyclone DDS: kein Handshake; raw RTPS-Frames mit Length-Prefix.
- FastDDS: BindConnectionRequest/Response als RTPS-Submessages
0x71/0x72(vendor-spezifisch). - RTI DDS: TLS-orientierter Handshake (vendor-spezifisch).
- Logical-Port-Multiplexing: vendor-spezifisch.
- Connection-Pool-Reuse-Policies: nicht spec-relevant.
§1.3 ZeroDDS-Wahl
ZeroDDS-TCP-Transport definiert eine eigene Spec (diese Datei) für den Bring-up-Handshake. Die Spec ist:
- OMG-konform auf Locator+Wire-Frame-Ebene (§9.4+§9.5).
- Vendor-spezifisch auf Handshake-Ebene (analog Cyclone/FastDDS/RTI).
- Cross-Vendor-fähig zu Cyclone via Handshake-Skip-Mode.
§2 Wire-Format
§2.1 Length-Prefix-Frame (DDSI-RTPS §9.5-konform)
Jedes RTPS-Datagramm wird über TCP wie folgt gerahmt:
+---------+---------+---------+---------+
| length (u32, big-endian) | Frame-Length in Bytes (excl. Header selbst)
+---------+---------+---------+---------+
| RTPS-Frame-Body (length Bytes) | wie bei UDP-PSM
+---------+---------+---------+---------+
- length-Field: 4 Byte big-endian.
- RTPS-Frame-Body: vollständiges RTPS-Message (RTPS-Header + Submessages), identisch zum UDP-PSM (DDSI-RTPS §9.5).
Repo-Anker: crates/transport-tcp/src/framing.rs::encode_frame,
decode_frame. Tests: crates/transport-tcp/src/framing.rs::tests.
§2.2 Maximum-Frame-Size
Default: 64 MiB. Empfänger MUSS Frames > Limit ablehnen (DoS-Schutz).
Repo-Anker: MAX_FRAME_SIZE in framing.rs.
§3 Handshake (ZeroDDS-spezifisch)
§3.1 BindConnectionRequest (16 Byte, big-endian)
+---------+---------+---------+---------+
| 'Z' | 'D' | 'D' | 'S' | magic "ZDDS"
+---------+---------+---------+---------+
| v_major | v_minor | vendor_id (2 B) | protocol-version + vendor-id
+---------+---------+---------+---------+
| flags (u32) | reserved, = 0
+---------+---------+---------+---------+
| logical_port (u32) | DDS-Endpoint-Logical-Port
+---------+---------+---------+---------+
- Magic
"ZDDS"— kollidiert nicht mit RTPS-Magic"RTPS", HTTP-Magic"HTTP", TLS-ClientHello — Sofort-Discriminator. - Version: aktuell
(1,0). - VendorId: ZeroDDS =
[0x01, 0x0F]. - Flags: reserviert, MUSS
0sein. - LogicalPort: u32;
0= “kein Claim”.
Repo-Anker: handshake.rs::BindConnectionRequest,
encode_request, decode_request.
§3.2 BindConnectionResponse (16 Byte, big-endian)
+---------+---------+---------+---------+
| 'Z' | 'D' | 'A' | status | magic "ZDA" + accept/reject
+---------+---------+---------+---------+
| v_major | v_minor | vendor_id (2 B) | server-version + vendor-id
+---------+---------+---------+---------+
| flags (u32) | reserved, = 0
+---------+---------+---------+---------+
| reason_code (u32) | 0 bei Accept, sonst per §3.3
+---------+---------+---------+---------+
- status-Byte:
0x2B('+') — Accept0x2D('-') — Reject
Repo-Anker: handshake.rs::BindConnectionResponse,
encode_response, decode_response.
§3.3 Reject-Reason-Codes
| Code | Konstante | Bedeutung |
|---|---|---|
| 0 | Unknown |
nicht klassifizierter Reject |
| 1 | VersionMismatch |
Peer-Version außerhalb des akzeptierten Fensters |
| 2 | ResourceLimit |
Server hat MAX_PEERS erreicht |
| 3 | LogicalPortConflict |
Port bereits gebunden |
| 4 | VendorNotAccepted |
Vendor-Policy lehnt Vendor-Id ab |
Repo-Anker: handshake.rs::RejectReason.
§3.4 Sequenz
Client Server
| |
|-- BindConnectionRequest (16 B) --------->| §3.1
| | verifies version + magic
|<--- BindConnectionResponse (16 B) -------| §3.2
| |
|-- Length-Prefix-Frame [RTPS] ----------->| §2.1
|<-- Length-Prefix-Frame [RTPS] -----------|
| ... |
Bei Reject droppen beide Seiten die Connection. Client-Side soll
Backoff anwenden (siehe tcp_transport.rs Connection-Pool).
§4 Cyclone-ddsi_tcp-Compatibility
Cyclone DDS spricht raw RTPS-Frames über TCP ohne Handshake. ZeroDDS unterstützt diesen Mode via Handshake-Skip:
- Client-Side:
TcpTransport::without_handshake()skippt §3 und sendet direkt §2.1 Length-Prefix-Frames. - Server-Side: detektiert Cyclone-Mode, wenn das erste Byte des
Frame-Bodys nicht
'Z'ist (kein ZeroDDS-Handshake-Magic), sondern'R'(RTPS-Magic-erstes-Byte). Falls Auto-Detect-Feature aktiviert.
Repo-Anker: tcp_transport.rs::TcpTransport::without_handshake.
§5 Connection-Pool
Nicht spec-relevant; Implementation-Detail. Der Pool bietet Connection-Reuse, Backoff und MAX_PEERS-Cap.
Repo-Anker: tcp_transport.rs::TcpTransport,
tcp_transport.rs::ConnectionPool.
§6 Cross-Vendor-Erweiterungspunkte (optional)
Für künftige Releases als optionale Feature-Flags vorgesehen, nicht RC1-Anforderung (kein normativer Spec):
feature = "fastdds-compat": BindConnectionRequest/Response als RTPS-Submessages0x71/0x72(FastDDS-Format).feature = "rti-compat": TLS-orientierter Handshake (RTI-Format).
Erweiterung würde §3 erweitern, nicht ersetzen — der ZeroDDS-eigene Handshake bleibt Default.
§7 Test-Coverage
| Spec-Sektion | Tests |
|---|---|
| §2.1 Length-Prefix-Frame | framing.rs::tests (8 Tests) |
| §2.2 Max-Frame-Size | framing.rs::tests::frame_size_limit |
| §3.1 BindConnectionRequest | handshake.rs::tests::request_* |
| §3.2 BindConnectionResponse | handshake.rs::tests::response_* |
| §3.3 Reject-Reasons | handshake.rs::tests::reject_reason_* |
| §3.4 Handshake-Sequenz | handshake.rs::tests::client_server_* |
| §4 Cyclone-Compat | tests/loopback.rs::cyclone_compat_* |
| §5 Connection-Pool | tcp_transport.rs::tests::pool_* |
Total: 50 Tests (lib) + 5 Tests (integration). Alle grün, Stand Audit-Datum.
§8 Status
Voll abgedeckt. ZeroDDS-TCP-Transport ist eine vollständige, in-sich-kohärente Spec; alle §-Sektionen sind implementiert und getestet. Cross-Vendor-Erweiterungspunkte (§6) sind als optional markiert.