zerodds-endpoint-go 1.0 — Spec Coverage
Source: docs/specs/zerodds-endpoint-go-1.0.md — the ZeroDDS Go endpoint
SDK spec. The marshalling comes from crates/lang-rules, column Language::Go; this document covers the transport.
Implementation:
endpoints/go/endpoint.go— XRCE framing (XrceWriteFrame/XrceReadFrame).endpoints/go/sync.go— syncClient.endpoints/go/async.go—Transportinterface, asyncAsyncReader/AsyncWriter.endpoints/go/reliable.go— reliable sender/receiver state machine + HEARTBEAT/ACKNACK wire codec +ReliableAsyncWriter.crates/endpoint-e2e/tests/go.rs— ping-pong E2E;crates/endpoint-e2e/tests/go_reliable.rs— reliable-stream E2E.
§1 XRCE framing
Spec: §1 — 8-byte XRCE header (session, stream, seq LE, submsg id 0x07
WRITE_DATA, flags, len LE) + body, byte-identical to crates/xrce +
endpoints/c.
Repo: endpoints/go/endpoint.go — XrceWriteFrame/XrceReadFrame,
constants XrceSessionNoKey (0x80) and XrceStreamBestEffort (0x01).
Tests: crates/endpoint-e2e/tests/go.rs::go_raw_udp (raw XCDR2 with no
XRCE frame — its own minimal harness); the framing itself is exercised live
via go_endpoint_sync and go_endpoint_async (§4).
Status: done.
§2 Sync Client
Spec: §2 — blocking Client: Write frames + delivers synchronously,
Poll is a single non-blocking receive, Receive blocks up to a timeout
(polling).
Repo: endpoints/go/async.go::Transport interface (Deliver/Receive,
the sole integration point); endpoints/go/sync.go::Client
(NewClient/Write/Poll/Receive, monotonic seq counter, default
session XrceSessionNoKey/XrceStreamBestEffort).
Tests: endpoints/go/sync_test.go::TestSyncLoopback; live E2E
go_endpoint_sync (§4).
Status: done.
§3 Async Reader/Writer
Spec: §3 — a goroutine polls the Transport and pushes unframed sample
bodies onto a channel (push); AsyncWriter is the send-side counterpart over
the same framing.
Repo: endpoints/go/async.go::AsyncReader (NewAsyncReader, Samples
channel, background loop, Close), AsyncWriter (NewAsyncWriter,
Write).
Tests: endpoints/go/async_test.go::TestAsyncLoopback +
TestAsyncUDP; live E2E go_endpoint_async (§4).
Status: done.
§4 Ping-pong E2E (live)
Spec: §5.1/§5.2 — a Go app exchanges a typed sample with the shared Rust XRCE peer over a real UDP socket: once as raw generated codec with no XRCE frame, once as the full stack (generated types + endpoint SDK) sync and async.
Repo: crates/endpoint-e2e/tests/go.rs — GO_RAW_MAIN (raw UDP, no XRCE
frame, uses only the generated MarshalXCDR/UnmarshalXCDRPong),
GO_ENDPOINT_MAIN (udpTransport implementing zerodds.Transport + the
zeroddsendpoint module, mode sync/async via CLI argument).
Tests: (Linux)
- go_raw_udp — generated Ping/Pong codec directly over a raw UDP
socket, no XRCE framing.
- go_endpoint_sync — full stack via zerodds.Client.
- go_endpoint_async — full stack via zerodds.AsyncReader/AsyncWriter.
3/3 passed (Linux).
Status: done.
§5 Reliable stream — state machine, wire, async writer
Spec: §4 (references reliable-endpoint v1.0 §3/§4) — XRCE reliable
stream (stream_id 0x80, §8.4.10/§8.4.11), mirroring the reference
crates/xrce/src/reliable.rs: ReliableSender.Submit/PendingHeartbeat/
RecvAcknack/GetInFlight; ReliableReceiver.RecvData/DrainInOrder/
PendingAcknack/Reset. Window 16, receiver buffer 64, heartbeat 500 ms,
payload ≤ 65535, RFC-1982 16-bit sequence numbers. Alongside it, the
async-decoupled ReliableAsyncWriter: the producer enqueues wait-free onto a
buffered channel, a dedicated drain goroutine holds the ReliableSender
state and does all the I/O (send, heartbeat, ACKNACK-driven retransmit) — the
producer never enters the kernel.
Repo: endpoints/go/reliable.go — ReliableWriteFrame/ReliableReadFrame,
HeartbeatFrame/ParseHeartbeat, AckNackFrame/ParseAckNack;
ReliableSender, ReliableReceiver; ReliableAsyncWriter (buffered channel
in, NewReliableAsyncWriter/Enqueue/Close/drain);
endpoints/go/example_reliable (runnable in-process demo, no socket);
endpoints/go/reliable_app (live UDP sender app for the E2E).
Tests: (Linux)
- go_reliable_unit_and_golden (crates/endpoint-e2e/tests/go_reliable.rs)
runs go test with -run against endpoints/go/reliable_test.go — 21 test
functions: monotonic seq (TestSubmitAssignsMonotonicSeqnrs),
payload-too-large (TestSubmitRejectsPayloadTooLarge), window-full
(TestSubmitRejectsWhenWindowFull), heartbeat first/silence/none
(TestPendingHeartbeatFiresFirstTime/...SilencedUntilPeriodElapsed/
...NoneWhenWindowEmpty), ACKNACK partial/full clear
(TestRecvAcknackClearsAckedSeqnrs/...FullClearWhenNoBitsSet), receiver
reorder/dedup/buffer-full (TestRecvDataBuffersInOrder/
...ReordersOutOfOrder/...DropsDuplicates/...RejectsWhenBufferFull),
pending-ACKNACK bitmap (TestPendingAcknackMarksMissingSlots), reset
(TestResetClearsStateCompletely), in-process end-to-end loss recovery
(TestEndToEndSenderReceiverWithLossRecovery), in-order delivery over the
reliable stream (TestConfigSubmessagesDeliveredInOrderViaReliableStream),
RFC-1982 wraparound (TestSeqLtGtRfc1982Wraparound), byte-golden
(TestByteGoldenHeartbeat/TestByteGoldenAckNack: HeartbeatFrame(1,3) ==
80 00 01 00 0B 01 05 00 01 00 03 00 80, AckNackFrame(1,0) ==
80 00 01 00 0A 01 05 00 01 00 00 00 80 — identical to the reference
goldens), frame round-trip parsing (TestFrameRoundTripParsing),
ReliableAsyncWriter loss recovery (TestReliableAsyncWriterLossRecovery).
- go_reliable_loss_recovery — peer drops every 3rd sample once; the app
(reliable_app) retransmits on ACKNACK; all 12 samples delivered gap-free
in order.
- go_reliable_no_loss — lossless baseline; 12/12.
- go_reliable_example — example_reliable runs and reports
sequence 0..11 verified in order + RELIABLE OK.
5/5 passed (Linux), 4 of which belong to this section (latency bench in §6).
Status: done.
§6 Latency — ring enqueue vs. inline sendto
Spec: §5.4 — the producer path of ReliableAsyncWriter (Enqueue →
channel push) must be measurably below the inline sendto syscall — the
evidence that async write removes syscall latency from the producer path,
not that it waits for ACKNACK.
Repo: endpoints/go/reliable_bench — 20000 iterations of inline
conn.Write (UDP sendto) vs. 20000 iterations of
ReliableAsyncWriter.Enqueue, no live peer needed (an arbitrary loopback
port, only local dispatch cost under measurement).
Tests: (Linux) go_reliable_latency_bench
(crates/endpoint-e2e/tests/go_reliable.rs) — ring enqueue 20–25 ns vs.
inline sendto 4360 ns (~175–220×).
Status: done.
Audit-Status
6 done / 0 partial / 0 open / 0 blocked / 0 n/a (informative).
Test run (Linux, verified): cargo test -p zerodds-endpoint-e2e --test go
3/3 (ping-pong: go_raw_udp/go_endpoint_sync/go_endpoint_async);
--test go_reliable 5/5 (go_reliable_unit_and_golden — 21 Go unit tests
incl. byte-golden, go_reliable_loss_recovery, go_reliable_no_loss,
go_reliable_example, go_reliable_latency_bench); latency bench ring
enqueue 20–25 ns / inline sendto 4360 ns (~175–220×).
Open items: none.
zerodds-endpoint-go 1.0 — Spec-Coverage
Quelle: docs/specs/zerodds-endpoint-go-1.0.md — ZeroDDS Go Endpoint-SDK-Spec.
Das Marshalling kommt aus crates/lang-rules, Spalte Language::Go; hier steht der Transport.
Implementation:
endpoints/go/endpoint.go— XRCE-Framing (XrceWriteFrame/XrceReadFrame).endpoints/go/sync.go— syncClient.endpoints/go/async.go—Transport-Interface, asyncAsyncReader/AsyncWriter.endpoints/go/reliable.go— reliable Sender/Receiver-State-Machine + HEARTBEAT/ACKNACK-Wire-Codec +ReliableAsyncWriter.crates/endpoint-e2e/tests/go.rs— Ping-Pong-E2E;crates/endpoint-e2e/tests/go_reliable.rs— reliable-Stream-E2E.
§1 XRCE-Framing
Spec: §1 — 8-Byte-XRCE-Header (session, stream, seq LE, submsg id 0x07
WRITE_DATA, flags, len LE) + Body, byte-identisch zu crates/xrce +
endpoints/c.
Repo: endpoints/go/endpoint.go — XrceWriteFrame/XrceReadFrame,
Konstanten XrceSessionNoKey (0x80) und XrceStreamBestEffort (0x01).
Tests: crates/endpoint-e2e/tests/go.rs::go_raw_udp (rohes XCDR2 ohne
XRCE-Frame — eigener Mini-Harness); Framing selbst wird über go_endpoint_sync
und go_endpoint_async (§4) live geübt.
Status: done.
§2 Sync Client
Spec: §2 — blockierender Client: Write framet + liefert synchron,
Poll ist ein nicht-blockierender Einzel-Receive, Receive blockiert bis zu
einem Timeout (pollend).
Repo: endpoints/go/async.go::Transport-Interface (Deliver/Receive,
der einzige Integrationspunkt); endpoints/go/sync.go::Client
(NewClient/Write/Poll/Receive, monotoner seq-Zähler, Default-Session
XrceSessionNoKey/XrceStreamBestEffort).
Tests: endpoints/go/sync_test.go::TestSyncLoopback; Live-E2E
go_endpoint_sync (§4).
Status: done.
§3 Async Reader/Writer
Spec: §3 — Goroutine pollt den Transport und schiebt entrahmte
Sample-Bodies auf einen Channel (push); AsyncWriter als Sendeseiten-Gegenstück
über dasselbe Framing.
Repo: endpoints/go/async.go::AsyncReader (NewAsyncReader, Samples-Channel,
Hintergrund-loop, Close), AsyncWriter (NewAsyncWriter, Write).
Tests: endpoints/go/async_test.go::TestAsyncLoopback +
TestAsyncUDP; Live-E2E go_endpoint_async (§4).
Status: done.
§4 Ping-Pong-E2E (live)
Spec: §5.1/§5.2 — eine Go-App tauscht mit dem geteilten Rust-XRCE-Peer über einen echten UDP-Socket ein typisiertes Sample aus: einmal roher generierter Codec ohne XRCE-Frame, einmal voller Stack (generierte Typen + Endpoint-SDK) sync und async.
Repo: crates/endpoint-e2e/tests/go.rs — GO_RAW_MAIN (rohes UDP, kein
XRCE-Frame, nutzt nur den generierten MarshalXCDR/UnmarshalXCDRPong),
GO_ENDPOINT_MAIN (udpTransport über zerodds.Transport +
zeroddsendpoint-Modul, Modus sync/async per CLI-Argument).
Tests: (Linux)
- go_raw_udp — generierter Ping/Pong-Codec direkt über einen rohen
UDP-Socket, ohne XRCE-Framing.
- go_endpoint_sync — voller Stack über zerodds.Client.
- go_endpoint_async — voller Stack über zerodds.AsyncReader/AsyncWriter.
3/3 grün (Linux).
Status: done.
§5 Reliable Stream — State-Machine, Wire, Async-Writer
Spec: §4 (verweist auf reliable-endpoint v1.0 §3/§4) — XRCE reliable
Stream (stream_id 0x80, §8.4.10/§8.4.11), spiegelt die Referenz
crates/xrce/src/reliable.rs: ReliableSender.Submit/PendingHeartbeat/
RecvAcknack/GetInFlight; ReliableReceiver.RecvData/DrainInOrder/
PendingAcknack/Reset. Window 16, Receiver-Buffer 64, Heartbeat 500 ms,
Payload ≤ 65535, RFC-1982 16-bit Sequenznummern. Dazu der async-entkoppelte
ReliableAsyncWriter: der Producer enqueued wait-free in einen gepufferten
Channel, eine dedizierte Drain-Goroutine hält den ReliableSender-State und
macht die gesamte I/O (senden, Heartbeat, ACKNACK-getriebenes Retransmit) —
der Producer geht nie in den Kernel.
Repo: endpoints/go/reliable.go — ReliableWriteFrame/ReliableReadFrame,
HeartbeatFrame/ParseHeartbeat, AckNackFrame/ParseAckNack;
ReliableSender, ReliableReceiver; ReliableAsyncWriter
(gepufferter Channel in, NewReliableAsyncWriter/Enqueue/Close/drain);
endpoints/go/example_reliable (lauffähige In-Process-Demo, kein Socket);
endpoints/go/reliable_app (live UDP-Sender-App für das E2E).
Tests: (Linux)
- go_reliable_unit_and_golden (crates/endpoint-e2e/tests/go_reliable.rs)
läuft go test mit -run auf endpoints/go/reliable_test.go — 21
Testfunktionen: monotone seq (TestSubmitAssignsMonotonicSeqnrs),
Payload-zu-groß (TestSubmitRejectsPayloadTooLarge), Window-full
(TestSubmitRejectsWhenWindowFull), Heartbeat first/silence/leer
(TestPendingHeartbeatFiresFirstTime/...SilencedUntilPeriodElapsed/
...NoneWhenWindowEmpty), ACKNACK Teil-/Voll-Clear
(TestRecvAcknackClearsAckedSeqnrs/...FullClearWhenNoBitsSet), Receiver
Reorder/Dedup/Buffer-full (TestRecvDataBuffersInOrder/
...ReordersOutOfOrder/...DropsDuplicates/...RejectsWhenBufferFull),
Pending-ACKNACK-Bitmap (TestPendingAcknackMarksMissingSlots), Reset
(TestResetClearsStateCompletely), In-Process-End-to-End-Loss-Recovery
(TestEndToEndSenderReceiverWithLossRecovery), In-Order-Delivery über den
reliable Stream (TestConfigSubmessagesDeliveredInOrderViaReliableStream),
RFC-1982-Wraparound (TestSeqLtGtRfc1982Wraparound), Byte-Golden
(TestByteGoldenHeartbeat/TestByteGoldenAckNack: HeartbeatFrame(1,3) ==
80 00 01 00 0B 01 05 00 01 00 03 00 80, AckNackFrame(1,0) ==
80 00 01 00 0A 01 05 00 01 00 00 00 80 — identisch zu den Referenz-Goldens),
Frame-Roundtrip-Parsing (TestFrameRoundTripParsing),
ReliableAsyncWriter-Loss-Recovery (TestReliableAsyncWriterLossRecovery).
- go_reliable_loss_recovery — Peer dropt jedes 3. Sample einmalig; die App
(reliable_app) retransmittet auf ACKNACK; alle 12 Samples lückenlos in
Reihenfolge geliefert.
- go_reliable_no_loss — lossless Baseline; 12/12.
- go_reliable_example — example_reliable läuft und meldet
sequence 0..11 verified in order + RELIABLE OK.
5/5 grün (Linux), davon 4 in diesem Abschnitt (Latenz-Bench in §6).
Status: done.
§6 Latenz — Ring-Enqueue vs. inline sendto
Spec: §5.4 — der Producer-Pfad des ReliableAsyncWriter
(Enqueue → Channel-Push) muss messbar unter dem inline sendto-Syscall
liegen — der Beleg, dass Async-Write die Syscall-Latenz aus dem Producer-Pfad
nimmt, nicht das Warten auf ACKNACK.
Repo: endpoints/go/reliable_bench — 20000 Iterationen inline conn.Write
(UDP-sendto) vs. 20000 Iterationen ReliableAsyncWriter.Enqueue, kein Live-
Peer nötig (beliebiger Loopback-Port, nur lokale Dispatch-Kosten unter
Messung).
Tests: (Linux) go_reliable_latency_bench
(crates/endpoint-e2e/tests/go_reliable.rs) — Ring-Enqueue 20–25 ns vs.
inline sendto 4360 ns (~175–220×).
Status: done.
Audit-Status
6 done / 0 partial / 0 open / 0 blocked / 0 n/a (informative).
Test-Lauf: Linux, verifiziert — cargo test -p zerodds-endpoint-e2e --test go
3/3 (Ping-Pong: go_raw_udp/go_endpoint_sync/go_endpoint_async);
--test go_reliable 5/5 (go_reliable_unit_and_golden — 21 Go-Unit-Tests inkl.
Byte-Golden, go_reliable_loss_recovery, go_reliable_no_loss,
go_reliable_example, go_reliable_latency_bench); Latenz-Bench Ring-Enqueue
20–25 ns / inline sendto 4360 ns (~175–220×).
Offene Punkte: keine.