Releases: SoundMatt/cpp-DDS
Release list
v0.25.1 — audit fix pass (spec version, IDL silent stubs, CLI capabilities, CI gates)
Fixes 8 of 9 findings from the 2026-07-30 x-Net audit pass, each independently re-verified before applying:
kRelaySpecVersion/kSpecVersion:1.11→2.0;dds::kSpecVersionis now a true alias ofrelay::kRelaySpecVersioninstead of an independently hardcoded literal that could drift.- IDL generator (
src/idl/gen.cpp) now hard-errors instead of silently emitting// TODO: encode/decodestub comments for nil sequence/array element types, unresolved struct references, and cyclic structs. - CLI
capabilitiesnow advertises"rtps"transport and"loaning"/"tsn"features (RELAY spec §12.2), reflecting shipped functionality that was previously under-reported. from_messageno longer silently discards a malformeddds.writer_guid; it clears the GUID and returnsErrSampleRejected.ROADMAP.md/CLAUDE.md: corrected stale spec-version claims, hardcoded per-developer paths, staleclose_with_drain()checkbox.- CI: removed
|| truemasking fromcpfusa initsteps; aligned pinned--project-versionwith the actual project version.
Two CI-gate sub-changes proposed in the same finding were evaluated and not applied because they would have broken CI on every run: raising --sec-tested from 96 to 100 (real coverage measured at 96.7%) and switching cpfusa cyber --write to a --check flag that does not exist on the pinned cpp-FuSa v0.17.1 CLI. See CHANGELOG.md for full detail.
Build verified clean; full suite passes (ctest 666/666).
See CHANGELOG.md for full detail.
v0.25.0
v0.24.0 — WAN bridge (dds::bridge::wan)
Added
dds::bridge::wan(include/dds/bridge/wan/wan.hpp,src/bridge/wan/wan.cpp) — a WAN bridge forwarding DDS samples between twodds::IParticipantdomains over a real TCP connection, the second item ofROADMAP.md's "Tier 4 — bridges" and a C++ port of go-DDS'sbridge/wanpackage. Landed as a second member ofcppdds_bridges.Bridge::serveaccepts TCP connections and publishes received samples to a local participant (a fresh per-connection publisher cache, matching go's per-callreceiveLoopexactly);Bridge::connectsynchronously subscribes toOptions::topicsbefore dialing (with cleanup-on-partial-failure) and streams each topic's samples to the server from an independent per-topic sender thread. Wire format is byte-exact with go'sencoding/json.Marshaloutput for the unexportedwireFramestruct (a 4-byte big-endian length prefix, capped at 16 MiB, followed by{"t":"<topic>","p":"<base64-payload>"}), verified against reference vectors captured from a real go-DDS process. Per this baseline's explicit scope (seewan.hpp's file-level scope note), the shared-token auth path is included alongside the framing it depends on (Options::token,write_auth/read_auth, constant-time server-side comparison, silent connection drop on mismatch); a real TLS/mTLS transport remains the explicitly-deferred stretch item. Also addsdds::mock::create'sisolated_brokerparameter (REQ-MOCK-006, additive, defaultfalse) — a C++ port of go-DDS'smock.IsolatedBroker(), needed to test two same-process participants standing in for two separate DDS domains without one echoing directly to the other.- Verified with 34 new tests (
tests/test_bridge_wan.cpp) plus 2 newdds::mocktests — 617/617 tests total.REQ-BRIDGE-WAN-001throughREQ-BRIDGE-WAN-007andREQ-MOCK-006added, traced and tested.ROADMAP.md'swanbullet checked off (restremains open).
Fixed
Bridge::close()'s socket force-close now callsshutdown()beforeclose()— required on Linux to reliably unblock a peer thread concurrently blocked inrecv()on the same fd (a real cross-platform correctness fix, not just a test artifact:close()alone doesn't reliably wake a blocked reader on another thread per POSIX, only observed to work that way on macOS/BSD).
v0.23.0 — gRPC protocol bridge (dds::bridge::grpc)
Added
dds::bridge::grpc(include/dds/bridge/grpc/{grpc.hpp,transport.hpp,config.hpp},src/bridge/grpc/{grpc.cpp,transport.cpp,config.cpp}) — a gRPC gateway bridging adds::IParticipantto RPC clients over JSON-encoded messages, the first item ofROADMAP.md's "Tier 4 — bridges" and a C++ port of go-DDS'sbridge/grpcpackage. Landed as the first member of a newcppdds_bridgesCMake target (CPPDDS_BUILD_BRIDGES, defaultON) — the first concrete piece of the previously-proposedddsbridgestarget group;cppdds_libitself is untouched.SubscribeRequest/PublishRequest/Sample/PublishAckand their JSON codec are byte-exact with go-DDS'sencoding/json.Marshaloutput, verified against reference vectors captured from a real go-DDS process.Bridgeimplements the three RPCs (subscribe/publish/stream_publish) as plain C++ methods againstSampleSender/PublishReceiverabstractions, independent of any networking, plus lazy subscriber/publisher caching,Options(auth_token/qos/filter/transform), andcheck_auth().transport.hpp'sServer/Clientspeak a real, working TCP wire protocol (a text header block plus real gRPC length-prefixed-message framing) rather than a full HTTP/2 gRPC transport — this repo has no HTTP/2 or protobuf dependency anywhere — documented in full ingrpc.hpp's file-level scope note.config.hpp/config.cpphand-roll a minimal YAML-subset parser for the bridge'slisten/auth_token/topicsschema.- Verified with 41 new tests (
tests/test_bridge_grpc.cpp) — 581/581 tests total.REQ-BRIDGE-GRPC-001throughREQ-BRIDGE-GRPC-011added, traced and tested.ROADMAP.md'sgrpcbullet checked off (wan/restremain open).
v0.22.0 — TSN (IEEE 802.1) QoS integration (dds::tsn)
Added
dds::tsn::Stream/StreamConfig(include/dds/tsn/tsn.hpp,src/tsn/tsn.cpp) — a C++ port of go-DDS'stsn/tsn.go, the fourth and last item ofROADMAP.md's "Tier 3 — xtypes, tsn, idl, cdr" (now fully complete).load_config()/parse_config()parse the identical JSONtsn_streamsshape via a small internal recursive-descent JSON reader scoped to exactly this config shape, matching this repo's established small-purpose-built-parser convention rather than a general-purpose dependency.include/dds/rtps/tsn.hppmirrors go-DDS'srtps/tsn.gosplit exactly:TSNParams/TSNStreamConfiglive insidedds::rtpsitself sodds::rtpsnever depends ondds::tsn.dds::tsn::StreamConfigAdapter/with_stream_config()is the adapter, assigned to a newParticipantOptions::tsn_configfield.include/dds/tsn/taprio.hpp+src/tsn/taprio.cpp—TAPRIOEntry/TAPRIOConfig(gate control list,cycle_duration()/validate()/tc_command()) plustaprio_from_streams(), all portable.src/tsn/taprio_linux.cpp(compiled only whenCMAKE_SYSTEM_NAMEis"Linux", mirroring Tier-1 phase 3'straffic_linux.cpp/traffic_other.cppsplit) programs and verifies the real Linuxtaprioqdisc via hand-builtRTM_NEWQDISC/RTM_GETQDISCnetlink messages overNETLINK_ROUTE— a byte-for-byte port of go-DDS'stsn/taprio_linux.goattribute layout, cross-checked field-by-field against a fresh go-DDS clone.src/tsn/taprio_other.cppreturns a documented "requires Linux" diagnostic everywhere else. Neitherapply()nor any TSN code is called automatically bydds::rtps::Participant, matching go-DDS's own participant.go.- Real
Participant/Writerwiring, not just types:ParticipantOptions::tsn_configset →new_publisherresolves each writer's topic against it (config match takes priority,QoS::transport_priority— a field that already existed — is the fallback PCP selector) and lazily creates/reuses one dedicatedUdpSocketper distinct PCP value, configured via the already-existing (Tier-1 phase 3)dds::rtps::traffic.hpphooks that had no caller anywhere in the codebase before this item.Writer::write()/send_heartbeat()route through that dedicated socket, computing aSO_TXTIMElaunch time for streams with a nonzerotx_offset. A TSN stream'smax_frag_payload()overridesfragment.hpp's default fragmentation threshold end-to-end. - 4 new cross-participant, real-loopback-UDP end-to-end tests plus 45 unit tests mirroring go-DDS's
tsn_test.go/taprio_test.gomatrices — 540/540 tests total.REQ-TSN-001throughREQ-TSN-007added, traced and tested.
Verified locally: Release C++17/C++20 builds clean, ctest 540/540, Debug ASan+UBSan pass on both macOS and a real Ubuntu-22.04/gcc-12 Docker container (exercising the actual Linux netlink code path). CI: all 13 checks green (Linux/macOS/Windows matrix, gcc-12 ASan+UBSan, cpp-FuSa full lifecycle).
Full changelog: https://github.com/SoundMatt/cpp-DDS/blob/main/CHANGELOG.md#0220--2026-07-28
v0.21.0 — OMG IDL parser + C++ code generator (dds::idl / ddstool)
Added
dds::idl(include/dds/idl/idl.hpp,src/idl/parser.cpp,src/idl/gen.cpp) — an OMG IDL lexer/parser plus a C++ code generator, a faithful C++ port of go-DDS'stools/idlpackage, the third item ofROADMAP.md's "Tier 3 — xtypes, tsn, idl, cdr". Parses module (nestable)/struct/enum/typedef declarations, basic types, bounded/unbounded sequences, bounded strings, fixed-size arrays, qualifiedModule::Namereferences, and the@keyannotation. Generates a self-contained C++ header: a struct/enum class/using-alias per declaration plus a<Name>Codecbuilt ondds::cdr::Encoder/Decoder(Tier 3,cdr, v0.20.0), with nested-struct inlining and a cycle guard. Two go-DDS quirks independently confirmed against a fresh go-DDS clone and faithfully preserved: the emitted namespace is alwaysidlgenunless the rootModule's name is overridden, and a parenthesized annotation argument (@id(5)) is a parse error.ddstool(ddstool/cli.hpp,ddstool/cli.cpp,ddstool/main.cpp) — a new standalone CLI executable exposingddstool idl [-out <file>] [-namespace <name>] <input.idl>, distinct from the existingcpp-ddsRELAY-conformance CLI. Logic lives in a smallddstool_clistatic library so it's testable in-process.- A checked-in round-trip fixture (
tests/idl_roundtrip/schema.idl+schema_gen.hpp, produced by actually running theddstoolbinary) mirroring go-DDS's owntools/idl/roundtrip/package field-for-field.Header/Telemetrymarshal()output verified byte-exact against reference vectors independently derived from a fresh go-DDS clone. - 101 new tests (
tests/test_idl.cpp,tests/test_ddstool_cli.cpp,tests/idl_roundtrip/test_idl_roundtrip.cpp) — 500/500 tests total. AddsREQ-IDL-001throughREQ-IDL-009, traced and tested.
Verified locally: Release C++17 build clean, new files additionally compiled warning-clean under a genuine -std=c++20 invocation, ctest 500/500, Debug ASan+UBSan pass. CI: all 13 checks green (Linux/macOS/Windows matrix, gcc-12 ASan+UBSan, cpp-FuSa full lifecycle).
Full changelog: https://github.com/SoundMatt/cpp-DDS/blob/main/CHANGELOG.md#0210--2026-07-27
v0.20.0 — general-purpose CDR/XCDR1 codec (dds::cdr)
Added
dds::cdr(include/dds/cdr/cdr.hpp,src/cdr/cdr.cpp) — general-purpose CDR/XCDR1 encode/decode per OMG DDS-XTypes 1.3, a faithful C++ port of go-DDS's top-leveltools/cdrpackage, the second item of ROADMAP.md's "Tier 3 — xtypes, tsn, idl, cdr".Encoder/Decoderhandle all CDR primitives with natural alignment, plus strings and byte sequences per the XCDR1 spec.Encoderprepends andDecoder::create()validates the 4-byte CDR_LE encapsulation header (accepting both CDR_LE and CDR_BE scheme values on decode, matching go-DDS's own quirk exactly).- Deliberately a SEPARATE library from Tier 1 phase 2's discovery-scoped
dds::rtps::PLCDREncoder/PLCDRDecoder— not reused, not extended; mirrors go-DDS's ownrtps/cdr.govs. top-leveltools/cdr/package split. - Every method verified byte-exact against reference vectors independently derived from a fresh go-DDS clone.
- 45 new tests (
tests/test_cdr.cpp) — 443/443 tests total. AddsREQ-CDR-001throughREQ-CDR-005, traced and tested.
Verified locally: Release C++17 build clean, the new files additionally compiled warning-clean under a genuine -std=c++20 invocation directly, ctest 443/443, Debug ASan+UBSan pass on macOS/AppleClang. CI: all 13 checks green (Linux/macOS/Windows matrix, gcc-12 ASan+UBSan, cpfusa full lifecycle).
Full changelog: https://github.com/SoundMatt/cpp-DDS/blob/main/CHANGELOG.md#0200--2026-07-27
v0.19.0 — dds::xtypes (DDS-XTypes Dynamic Data support)
dds::xtypes — DDS-XTypes Dynamic Data support
Implements the next Tier-3 roadmap item: a faithful C++ port of go-DDS's tools/xtypes/xtypes.go (Dynamic Data / runtime type system, loosely aligned with OMG DDS-XTypes 1.3), the first item of ROADMAP.md's "Tier 3 — xtypes, tsn, idl, cdr".
Added
dds::xtypes::TypeKind/FieldDescriptor/TypeDescriptor— the runtime schema modeldds::xtypes::identify()/TypeIdentifier— content-addressed type fingerprint (SHA-256 over a canonical JSON encoding, order-independent over field declaration)dds::xtypes::DynamicData— schema-validated property map withto_json()/from_json(), unknown fields silently skipped on read (forward compatibility)dds::xtypes::TypeRegistry— thread-safe, name-keyed store with structural-conflict detection (ErrTypeMismatch)dds::xtypes::check_compatibility()— forward/backward schema-evolution rules
TypeIdentifier's canonical-JSON hash is verified byte-for-byte against reference vectors independently derived from a fresh go-DDS clone, including Go's default HTML-safe JSON string-escaping rule, confirmed against real go-DDS output rather than assumed. No external crypto dependency is fetched for this project, so SHA-256 is implemented from scratch under src/xtypes/detail/ (independent of dds::security's own scratch SHA-256, which is explicitly scoped to security.cpp only) and verified against FIPS 180-4 known-answer vectors.
Scope: internal, additive — dds::xtypes is a standalone type system and dynamic-data package, not wired into RTPS discovery or dds::adapt(), matching dds::safety::E2EPublisher's and dds::security::Plugin's own precedent.
Adds REQ-XTYPE-001 through REQ-XTYPE-006 and REQ-TREG-001 through REQ-TREG-003, traced and tested. Checks off the xtypes item in ROADMAP.md.
36 new tests (417/417 total), verified with Release C++17/C++20 builds and a Debug ASan+UBSan pass; CI additionally exercises Linux/gcc-12 ASan+UBSan.
v0.18.0 — dds::security (HMAC, AES-256-GCM, topic ACL, anti-replay)
dds::security — HMAC-SHA-256, AES-256-GCM, topic ACL, anti-replay
Implements the next Tier-2 roadmap item: a C++ port of go-DDS's security package (security/security.go, access.go, replay.go), immediately following the already-completed ddssafety/E2E item (v0.17.0).
Added
dds::security::HMACPlugin— HMAC-SHA-256 message authentication (plaintext || HMAC[32])dds::security::AESGCMPlugin— AES-256-GCM authenticated encryption (nonce[12] || ciphertext || tag[16])dds::security::AccessPolicy/Permission/Rule— per-topic ACL, first-match-wins glob rules (byte-oriented port of Go'spath.Match)dds::security::ReplayGuard— sliding-window anti-replay sequence-number enforcement
HMACPlugin/AESGCMPlugin wire formats are byte-for-byte identical to go-DDS's, verified against reference vectors independently derived from a fresh go-DDS clone. No external crypto dependency is fetched for this project, so SHA-256/HMAC/AES-256/GCM are implemented from scratch under src/security/crypto/ (internal, non-public) and independently verified byte-exact against FIPS 180-4 / RFC 4231 / NIST SP 800-38A known-answer test vectors, the classic McGrew-Viega/NIST AES-256-GCM all-zero test vector, and Go's actual crypto/aes + crypto/cipher + crypto/hmac stdlib output.
Scope: internal, additive — dds::security::Plugin is a standalone seal/open library, not wired into dds::adapt(), dds::mock, or the RTPS transport, matching dds::safety::E2EPublisher's own precedent. go-DDS's security.cert/security.discovery are out of scope, matching the E2E item's precedent.
Adds REQ-SECURITY-001 through REQ-SECURITY-009, traced and tested. Checks off the security item in ROADMAP.md.
Verification
- Release C++17/C++20 builds clean across Linux/macOS/Windows, zero warnings
- 381/381 tests pass (44 new)
- Gcc-12 ASan+UBSan clean (reproduced locally in a matching Ubuntu-22.04 Docker container before pushing, after fixing a genuine UBSan finding — see
7a7cf27) relay conform/relay interop --protocol DDSpass unchangedcpfusa check/cyber/vuln/qualifyall green
Full Changelog: v0.17.0...v0.18.0
v0.17.0 — ddssafety E2E protection wire header (Tier 2)
[0.17.0] — 2026-07-27
Added
dds::safety::E2EPublisher/dds::safety::E2ESubscriber
(include/dds/safety/e2e.hpp,src/safety/e2e.cpp) — a byte-compatible
C++ port of go-DDS's end-to-end (E2E) data protection wire header
(safety/e2e.go), the first item ofROADMAP.md's "Tier 2 — safety and
security".E2EPublisherwraps adds::IPublisherand prepends an
18-byte little-endian protection header (DataID, SourceID,
SequenceCounter, Timestamp, CRC-16/CCITT-FALSE) to every payload before
writing, with a per-publisher sequence counter starting at 1.
E2ESubscriberwraps adds::ISubscriber, strips the header from every
received sample on a background pump thread, and validates CRC,
sequence-counter continuity, and sample freshness against
E2EConfig::max_age(zero disables freshness checking) — valid samples
are forwarded viachannel(); violations are reported viaerrors()
without suppressing delivery of sequence-gapped samples (matching
go-DDS's own behavior).- Byte-exact wire-format vectors (18-byte header layout and the
CRC-16/CCITT-FALSE algorithm) independently derived from a fresh go-DDS
clone and checked intests/test_safety_e2e.cpp, following the same
reference-vector derivation conventiontest_rtps_cdr.cppestablished
for RTPS. requirements/requirements.jsongainsREQ-E2E-001through
REQ-E2E-006, traced (fusa:req) and tested (fusa:test).
Internal/additive: E2EPublisher fully implements dds::IPublisher
(including the context-bounded write() overload, per REQ-SAFETY-003) —
a strict improvement over go-DDS's own E2EPublisher, which in practice
does not satisfy the full dds.Publisher interface (no WriteCtx).
E2ESubscriber is not forced into dds::ISubscriber for the same reason
go-DDS's own type isn't a full Subscriber either (no TryRead/
Unsubscribe); it exposes channel()/errors()/close() instead,
mirroring go-DDS's actual surface. go-DDS's safety.SafetyMetricsProvider/
SafetyEvent/monitor-integration layer (safety/metrics.go) is
Tier-5-adjacent observability and out of scope for this item.
Verified locally: Release C++17/C++20 clean, all tests passing, Debug
ASan+UBSan clean. ROADMAP.md checked off.